Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions packages/parser/lib/Parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,14 @@ keyframe_style_rule:
(* TODO: Handle separated_list(COMMA, percentage) *)
}

combined_selector:
| x = selector { x }
| x = relative_selector { x }

combined_selector_list:
| selector = loc(combined_selector) WS? { [selector] }
| selector = loc(combined_selector) WS? COMMA WS? seq = combined_selector_list WS? { selector :: seq }

selector_list:
| selector = loc(selector) WS? { [selector] }
| selector = loc(selector) WS? COMMA WS? seq = selector_list WS? { selector :: seq }
Expand All @@ -190,14 +198,14 @@ relative_selector_list:

/* .class {} */
style_rule:
| prelude = loc(selector_list) WS?
| prelude = loc(combined_selector_list) WS?
block = loc(empty_brace_block) {
{ prelude;
block;
loc = make_loc $startpos $endpos;
}
}
| prelude = loc(selector_list) WS?
| prelude = loc(combined_selector_list) WS?
declarations = brace_block(loc(declarations)) {
{ prelude;
block = declarations;
Expand Down
11 changes: 9 additions & 2 deletions packages/runtime/melange/Emotion_bindings.ml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,19 @@ external makeAnimation : Js.Json.t Js.Dict.t -> string = "keyframes"
let makeKeyframes frames = makeAnimation frames
let insertRule css = injectRaw css
let renderRule renderer css = renderRaw renderer css
let global rules = injectRules (Rule.toJson rules)

let global rules =
rules
|> Emotion_bindings_helper.replaceSelectorGlobal
|> Rule.toJson
|> injectRules

let renderGlobal renderer selector rules =
renderRules renderer selector (Rule.toJson rules)

let style rules = make (Rule.toJson rules)
let style rules =
rules |> Emotion_bindings_helper.replaceSelector |> Rule.toJson |> make

let merge styles = mergeStyles styles
let merge2 s s2 = merge [| s; s2 |]
let merge3 s s2 s3 = merge [| s; s2; s3 |]
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime/melange/Kloth.ml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ module String = struct
[@@mel.send]

external trim : string -> string = "trim" [@@mel.send]

let contains = Stdlib.String.contains
end

module Int = struct
Expand Down
8 changes: 0 additions & 8 deletions packages/runtime/native/CSS.ml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ let contains_ampersand selector = String.contains selector '&'
let contains_a_coma selector = String.contains selector ','
let starts_with_at selector = String.starts_with ~prefix:"@" selector
let starts_with_dot selector = String.starts_with ~prefix:"." selector
let starts_with_double_dot selector = String.starts_with ~prefix:":" selector
let starts_with_ampersand selector = String.starts_with ~prefix:"&" selector

let prefix ~pre s =
Expand Down Expand Up @@ -136,16 +135,11 @@ let resolve_ampersand hash selector =
let resolved_selector = replace_ampersand ~by:classname selector in
if contains_ampersand selector then resolved_selector
else if starts_with_at selector then resolved_selector
(* This is the differente between SASS and Emotion. Emotion doesn't add a space on pseuo-selectors, while SASS does *)
else if starts_with_double_dot selector then
Printf.sprintf ".%s%s" hash resolved_selector
else Printf.sprintf ".%s %s" hash resolved_selector

let add_ampersand selector =
if contains_ampersand selector then selector
else if starts_with_at selector then selector
(* This is the differente between SASS and Emotion. Emotion doesn't add a space on pseuo-selectors, while SASS does *)
else if starts_with_double_dot selector then Printf.sprintf "&%s" selector
else Printf.sprintf "& %s" selector

let remove_media_from_selector selector =
Expand Down Expand Up @@ -295,8 +289,6 @@ let resolve_selectors ?(prefix_with_ampersand = true) rules =
if contains_ampersand current_selector.(0) then
(* reemplazar el ampersand del current_selector, con el padre *)
replace_ampersand ~by:prefix current_selector.(0)
else if starts_with_double_dot current_selector.(0) then
prefix ^ current_selector.(0)
(* This case is the same as the "else", but I keep it for reference *)
else if starts_with_dot current_selector.(0) then
prefix ^ " " ^ current_selector.(0)
Expand Down
2 changes: 2 additions & 0 deletions packages/runtime/native/Kloth.ml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ module String = struct
|| (i < len_str && prefix.[i] = str.[i] && compare_prefix (i + 1))
in
compare_prefix 0

let contains = Stdlib.String.contains
end

module Int = struct
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/native/Kloth.mli
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module String : sig
val length : string -> int
val trim : string -> string
val starts_with : prefix:string -> string -> bool
val contains: string -> char -> bool
end

module Int : sig
Expand Down
21 changes: 21 additions & 0 deletions packages/runtime/native/shared/Emotion_bindings_helper.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
let addAmpersand selector =
if Kloth.String.contains selector '&' then selector
else if Kloth.String.starts_with ~prefix:"@" selector then selector
else "& " ^ selector

let rec replaceSelector rules =
Kloth.Array.map
~f:(function
| Rule.Selector (selector, rules) ->
Rule.Selector
(Kloth.Array.map ~f:addAmpersand selector, replaceSelector rules)
| Declaration (_, _) as x -> x)
rules

let replaceSelectorGlobal rules =
Kloth.Array.map
~f:(function
| Rule.Selector (selector, rules) ->
Rule.Selector (selector, replaceSelector rules)
| Declaration (_, _) as x -> x)
rules
13 changes: 10 additions & 3 deletions packages/runtime/rescript/Emotion_bindings.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,19 @@ external makeAnimation : Js.Json.t Js.Dict.t -> string = "keyframes"
let makeKeyframes frames = makeAnimation frames
let insertRule css = injectRaw css
let renderRule renderer css = renderRaw renderer css
let global rules = injectRules (Rule.toJson rules)

let global rules =
rules
|> Emotion_bindings_helper.replaceSelectorGlobal
|> Rule.toJson
|> injectRules

let renderGlobal renderer selector rules =
renderRules renderer selector (Rule.toJson rules)

let style rules = make (Rule.toJson rules)
let style rules =
rules |> Emotion_bindings_helper.replaceSelector |> Rule.toJson |> make

let merge styles = mergeStyles styles
let merge2 s s2 = merge [| s; s2 |]
let merge3 s s2 s3 = merge [| s; s2; s3 |]
Expand Down Expand Up @@ -68,5 +75,5 @@ let fontFace ~fontFamily ~src ?fontStyle ?fontWeight ?fontDisplay ?sizeAdjust
|]
|> Kloth.Array.filter_map ~f:(fun i -> i)
in
global [| Rule.Selector ([|"@font-face"|], fontFace) |];
global [| Rule.Selector ([| "@font-face" |], fontFace) |];
fontFamily
7 changes: 6 additions & 1 deletion packages/runtime/rescript/Kloth.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,18 @@ end
module String = struct
external get : string -> int -> char = "%string_safe_get"
external length : string -> int = "length" [@@bs.get]
external jsContains : string -> string -> bool = "includes" [@@bs.send]

(* Public API *)

external starts_with : prefix:string -> string -> bool = "startsWith"
[@@bs.send]

external trim : string -> string = "trim" [@@bs.send]

let contains s c =
let needle = String.make 1 c in
jsContains s needle
end

module Int = struct
Expand Down Expand Up @@ -87,4 +92,4 @@ end

module Fun = struct
external id : 'a -> 'a = "%identity"
end
end
1 change: 1 addition & 0 deletions packages/runtime/test/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
(flags
(:standard -open Alcotest_extra))
(libraries
str
alcotest
fmt
server-reason-react.js
Expand Down
7 changes: 6 additions & 1 deletion packages/runtime/test/test.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
let () =
Alcotest.run ~show_errors:true ~compact:true ~tail_errors:`Unlimited
"styled-ppx.native"
[ Test_styles.tests; Test_autoprefixer.tests; Test_hash.tests ]
[
Test_styles.tests;
Test_autoprefixer.tests;
Test_hash.tests;
Test_emotion_bindings_helper.tests;
]
3 changes: 1 addition & 2 deletions packages/runtime/test/test_autoprefixer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ let text_decoration =
(CSS.textDecorations
~line:(CSS.Types.TextDecorationLine.Value.make ~lineThrough:true ())
())
"-webkit-text-decoration: line-through auto solid currentColor; \
text-decoration: line-through auto solid currentColor;")
"-webkit-text-decoration: line-through ; text-decoration: line-through ;")

let display_grid =
test "display_grid" (fun () ->
Expand Down
41 changes: 41 additions & 0 deletions packages/runtime/test/test_emotion_bindings_helper.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
let pp_selectors =
Format.(
pp_print_array ~pp_sep:(fun out () -> fprintf out ",") pp_print_string)

let pp_declaration ppf (property, value) =
Format.fprintf ppf "%s:%s;" property value

let rec pp_rule ppf = function
| Rule.Selector (selectors, rules) ->
Format.(
fprintf ppf "%a{%a}" pp_selectors selectors (pp_print_array pp_rule) rules)
| Rule.Declaration (property, value) ->
Format.fprintf ppf "%a" pp_declaration (property, value)

let pp_rules = Format.(pp_print_array ~pp_sep:pp_print_nothing pp_rule)

let print_rules rules =
let out = Format.asprintf "%a" pp_rules rules in
Str.global_replace (Str.regexp "\n") "" out

let nested_selector =
test "nested_selector" @@ fun () ->
let rules =
[|
CSS.selectorMany [| "div"; ":hover" |]
[|
CSS.color CSS.black;
CSS.selector "main" [||];
CSS.selector ":hover" [||];
CSS.selector "&:hover" [||];
CSS.selector "&.foo" [||];
CSS.selector "@media (min-width: 30em)" [||];
|];
|]
|> Emotion_bindings_helper.replaceSelector
in
assert_string (print_rules rules)
"& div,& :hover{color:#000000;& main{}& :hover{}&:hover{}&.foo{}@media \
(min-width: 30em){}}"

let tests = "Emotion Bindings Helper", [ nested_selector ]
1 change: 1 addition & 0 deletions packages/runtime/test/test_emotion_bindings_helper.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
val tests : string * unit Alcotest.test_case list
Loading
Loading