Skip to content

Commit

Permalink
Handle DomProps with both jsx and html attribute name (#171)
Browse files Browse the repository at this point in the history
* feat: handle DomProps with both jsx and html attribute name

* feat: use tuple on name and jsxName for DomProps

---------

Co-authored-by: David Sancho <[email protected]>
  • Loading branch information
pedrobslisboa and davesnx authored Oct 30, 2024
1 parent ffa038c commit 904d2ca
Show file tree
Hide file tree
Showing 11 changed files with 588 additions and 516 deletions.
2 changes: 1 addition & 1 deletion packages/react/src/DomProps.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1659,7 +1659,7 @@ let camelcaseToKebabcase str =
in
str |> chars_of_string |> loop [] |> List.rev |> string_of_chars

let findByName tag jsxName =
let findByJsxName ~tag jsxName =
let byName p = getJSXName p = jsxName in
if isDataAttribute jsxName then
let name = camelcaseToKebabcase jsxName in
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/DomProps.mli
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ type errors = [ `ElementNotFound | `AttributeNotFound ]

val getJSXName : prop -> string
val getName : prop -> string
val findByName : string -> string -> (prop, errors) result
val findByJsxName : tag:string -> string -> (prop, errors) result
val isReactValidProp : string -> bool
val find_closest_name : string -> string option
28 changes: 13 additions & 15 deletions packages/react/src/React.ml
Original file line number Diff line number Diff line change
Expand Up @@ -339,18 +339,18 @@ module JSX = struct
| Inline of string

type prop =
| Bool of (string * bool)
| String of (string * string)
| Bool of (string * string * bool)
| String of (string * string * string)
| Style of string
| DangerouslyInnerHtml of string
| Ref of Ref.t
| Event of string * event

let bool key value = Bool (key, value)
let string key value = String (key, value)
let bool name jsxName value = Bool (name, jsxName, value)
let string name jsxName value = String (name, jsxName, value)
let style value = Style value
let int key value = String (key, string_of_int value)
let float key value = String (key, string_of_float value)
let int name jsxName value = String (name, jsxName, string_of_int value)
let float name jsxName value = String (name, jsxName, string_of_float value)
let dangerouslyInnerHtml value = DangerouslyInnerHtml value#__html
let ref value = Ref value
let event key value = Event (key, value)
Expand Down Expand Up @@ -397,9 +397,8 @@ exception Invalid_children of string

let compare_attribute left right =
match (left, right) with
| JSX.Bool (left_key, _), JSX.Bool (right_key, _) ->
String.compare left_key right_key
| String (left_key, _), String (right_key, _) ->
| JSX.Bool (left_key, _, _), JSX.Bool (right_key, _, _)
| String (left_key, _, _), String (right_key, _, _) ->
String.compare left_key right_key
| Style left_styles, Style right_styles ->
String.compare left_styles right_styles
Expand All @@ -408,10 +407,9 @@ let compare_attribute left right =
let clone_attribute acc attr new_attr =
let open JSX in
match (attr, new_attr) with
| Bool (left, _), Bool (right, value) when left == right ->
Bool (left, value) :: acc
| String (left, _), String (right, value) when left == right ->
String (left, value) :: acc
| Bool (left, _, _), Bool (right, _, _) when left == right -> new_attr :: acc
| String (left, _, _), String (right, _, _) when left == right ->
new_attr :: acc
| _ -> new_attr :: acc

module StringMap = Map.Make (String)
Expand All @@ -421,8 +419,8 @@ let attributes_to_map attributes =
List.fold_left
(fun acc attr ->
match attr with
| Bool (key, value) -> acc |> StringMap.add key (Bool (key, value))
| String (key, value) -> acc |> StringMap.add key (String (key, value))
| (Bool (key, _, _) | String (key, _, _)) as prop ->
acc |> StringMap.add key prop
(* The following constructors shoudn't be part of the StringMap *)
| DangerouslyInnerHtml _ -> acc
| Ref _ -> acc
Expand Down
12 changes: 6 additions & 6 deletions packages/react/src/React.mli
Original file line number Diff line number Diff line change
Expand Up @@ -515,21 +515,21 @@ module JSX : sig

(** JSX.prop is the representation of HTML/SVG attributes and DOM events *)
type prop =
| Bool of (string * bool)
| String of (string * string)
| Bool of (string * string * bool)
| String of (string * string * string)
| Style of string
| DangerouslyInnerHtml of string
| Ref of domRef
| Event of string * event

(** Helpers to create JSX.prop without variants, helpful for function application *)

val bool : string -> bool -> prop
val string : string -> string -> prop
val bool : string -> string -> bool -> prop
val string : string -> string -> string -> prop
val style : string -> prop
val dangerouslyInnerHtml : < __html : string ; .. > -> prop
val int : string -> int -> prop
val float : string -> float -> prop
val int : string -> string -> int -> prop
val float : string -> string -> float -> prop
val ref : domRef -> prop
val event : string -> event -> prop

Expand Down
28 changes: 20 additions & 8 deletions packages/react/test/test_cloneElement.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
let equal_attrs (a1 : React.JSX.prop) (a2 : React.JSX.prop) =
match (a1, a2) with
| Bool (k1, v1), Bool (k2, v2) -> k1 == k2 && v1 = v2
| String (k1, v1), String (k2, v2) -> k1 == k2 && v1 == v2
| Bool (k1, x1, v1), Bool (k2, x2, v2) -> k1 == k2 && x1 == x2 && v1 = v2
| String (k1, x1, v1), String (k2, x2, v2) -> k1 == k2 && x1 == x2 && v1 == v2
| Style s1, Style s2 -> s1 == s2
| DangerouslyInnerHtml s1, DangerouslyInnerHtml s2 -> s1 == s2
(* Can't compare functions ^^ *)
Expand Down Expand Up @@ -36,35 +36,47 @@ let assert_component left right =

let clone_empty () =
let component =
React.createElement "div" [ React.JSX.Bool ("hidden", true) ] []
React.createElement "div" [ React.JSX.Bool ("hidden", "hidden", true) ] []
in
assert_component component (React.cloneElement component [])

let clone_attributes () =
let component =
React.createElement "div" [ React.JSX.String ("val", "33") ] []
React.createElement "div" [ React.JSX.String ("val", "val", "33") ] []
in
let expected =
React.createElement "div"
[ React.JSX.String ("val", "31"); React.JSX.Bool ("lola", true) ]
[
React.JSX.String ("val", "val", "31");
React.JSX.Bool ("lola", "lola", true);
]
[]
in
let cloned =
React.cloneElement component
[ React.JSX.Bool ("lola", true); React.JSX.String ("val", "31") ]
[
React.JSX.Bool ("lola", "lola", true);
React.JSX.String ("val", "val", "31");
]
in
assert_component cloned expected

let clone_order_attributes () =
let component = React.createElement "div" [] [] in
let expected =
React.createElement "div"
[ React.JSX.String ("val", "31"); React.JSX.Bool ("lola", true) ]
[
React.JSX.String ("val", "val", "31");
React.JSX.Bool ("lola", "lola", true);
]
[]
in
let cloned =
React.cloneElement component
[ React.JSX.Bool ("lola", true); React.JSX.String ("val", "31") ]
[
React.JSX.Bool ("lola", "lola", true);
React.JSX.String ("val", "val", "31");
]
in
assert_component cloned expected

Expand Down
2 changes: 1 addition & 1 deletion packages/react/test/test_react.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ module Gap = struct
if element = React.null then React.null
else
React.createElement "div"
[ React.JSX.String ("class", "divider") ]
[ React.JSX.String ("class", "className", "divider") ]
[ element ])
end

Expand Down
Loading

0 comments on commit 904d2ca

Please sign in to comment.