diff --git a/packages/parser/css_parser.mly b/packages/parser/css_parser.mly index d10e882ab..2fd95f3ff 100644 --- a/packages/parser/css_parser.mly +++ b/packages/parser/css_parser.mly @@ -226,9 +226,9 @@ style_rule: } ; -prelude: xs = nonempty_list(loc(component_value_in_prelude)) { xs }; +prelude: xs = loption(nonempty_list(loc(component_value_in_prelude))) { xs }; -component_values: xs = nonempty_list(loc(component_value)) { xs }; +component_values: xs = loption(nonempty_list(loc(component_value))) { xs }; declarations: | xs = nonempty_list(declaration_or_at_rule); SEMI_COLON?; { xs } diff --git a/packages/ppx/src/declarations_to_string.re b/packages/ppx/src/declarations_to_string.re index 77052784c..da44b2377 100644 --- a/packages/ppx/src/declarations_to_string.re +++ b/packages/ppx/src/declarations_to_string.re @@ -262,23 +262,29 @@ let max_width = let height = apply(Parser.property_height, [%expr "height"], render_size); let min_height = apply(Parser.property_height, [%expr "min-height"], render_size); let max_height = apply(Parser.property_height, [%expr "max-height"], render_size); + +let render_ratio = fun + | `Static((a, (), b)) => + [%expr [%e string_of_int(a) |> render_string] ++ "/" ++ [%e string_of_int(b) |> render_string]] + | `Integer(i) => [%expr [%e render_integer(i)]]; + let aspect_ratio = apply( Parser.property_media_max_aspect_ratio, [%expr "aspect-ratio"], - ((a, (), b)) => [%expr [%e string_of_int(a) |> render_string] ++ "/" ++ [%e string_of_int(b) |> render_string]] + render_ratio ); let min_aspect_ratio = apply( Parser.property_media_max_aspect_ratio, [%expr "min-aspect-ratio"], - ((a, (), b)) => [%expr [%e string_of_int(a) |> render_string] ++ "/" ++ [%e string_of_int(b) |> render_string]] + render_ratio ); let max_aspect_ratio = apply( Parser.property_media_max_aspect_ratio, [%expr "max-aspect-ratio"], - ((a, (), b)) => [%expr [%e string_of_int(a) |> render_string] ++ "/" ++ [%e string_of_int(b) |> render_string]] + render_ratio ); let orientation = apply( diff --git a/packages/ppx/test/css-support/test.expected.re b/packages/ppx/test/css-support/test.expected.re index 1f47bd7b5..d75e3c550 100644 --- a/packages/ppx/test/css-support/test.expected.re +++ b/packages/ppx/test/css-support/test.expected.re @@ -1171,6 +1171,10 @@ CssJs.unsafe({js|background-image|js}, "unset"); CssJs.unsafe({js|width|js}, "unset"); CssJs.unsafe({js|clipPath|js}, {js| url('#clip')|js}); CssJs.unsafe({js|clipPath|js}, {js| inset(50%)|js}); +CssJs.unsafe({js|clipPath|js}, {js| circle()|js}); +CssJs.unsafe({js|clipPath|js}, {js| ellipse()|js}); +CssJs.unsafe({js|clipPath|js}, {js| path('M 20 20 H 80 V 30')|js}); +CssJs.unsafe({js|clipPath|js}, {js| circle() border-box|js}); CssJs.unsafe({js|clipPath|js}, {js| border-box|js}); CssJs.unsafe({js|clipPath|js}, {js| padding-box|js}); CssJs.unsafe({js|clipPath|js}, {js| content-box|js}); @@ -1211,6 +1215,7 @@ CssJs.unsafe({js|maskRepeat|js}, {js| no-repeat no-repeat|js}); CssJs.unsafe({js|maskPosition|js}, {js| center|js}); CssJs.unsafe({js|maskPosition|js}, {js| center center|js}); CssJs.unsafe({js|maskPosition|js}, {js| left 50%|js}); +CssJs.unsafe({js|maskPosition|js}, {js| bottom 10px right 20px|js}); CssJs.unsafe({js|maskClip|js}, {js| border-box|js}); CssJs.unsafe({js|maskClip|js}, {js| padding-box|js}); CssJs.unsafe({js|maskClip|js}, {js| content-box|js}); @@ -1245,6 +1250,7 @@ CssJs.unsafe({js|mask|js}, {js| url(image.png)|js}); CssJs.unsafe({js|mask|js}, {js| url(image.png) luminance|js}); CssJs.unsafe({js|mask|js}, {js| url(image.png) luminance top space|js}); CssJs.unsafe({js|maskBorderSource|js}, {js| none|js}); +CssJs.unsafe({js|maskBorderSource|js}, {js| url(image.png)|js}); CssJs.unsafe({js|maskBorderSlice|js}, {js| 0 fill|js}); CssJs.unsafe({js|maskBorderSlice|js}, {js| 50% fill|js}); CssJs.unsafe({js|maskBorderSlice|js}, {js| 1.1 fill|js}); @@ -1284,6 +1290,7 @@ CssJs.unsafe({js|maskBorderRepeat|js}, {js| stretch space|js}); CssJs.unsafe({js|maskBorderRepeat|js}, {js| repeat space|js}); CssJs.unsafe({js|maskBorderRepeat|js}, {js| round space|js}); CssJs.unsafe({js|maskBorderRepeat|js}, {js| space space|js}); +CssJs.unsafe({js|maskBorder|js}, {js| url(image.png)|js}); CssJs.unsafe({js|maskType|js}, {js| luminance|js}); CssJs.unsafe({js|maskType|js}, {js| alpha|js}); CssJs.unsafe({js|mixBlendMode|js}, {js| normal|js}); @@ -1326,6 +1333,7 @@ CssJs.unsafe({js|display|js}, {js| flow|js}); CssJs.unsafe({js|display|js}, {js| flow-root|js}); CssJs.unsafe({js|filter|js}, {js| none|js}); CssJs.unsafe({js|filter|js}, {js| url(#id)|js}); +CssJs.unsafe({js|filter|js}, {js| url(image.svg#id)|js}); CssJs.unsafe({js|filter|js}, {js| blur(5px)|js}); CssJs.unsafe({js|filter|js}, {js| brightness(0.5)|js}); CssJs.unsafe({js|filter|js}, {js| contrast(150%)|js}); @@ -1339,6 +1347,7 @@ CssJs.unsafe({js|filter|js}, {js| saturate(150%)|js}); CssJs.unsafe({js|filter|js}, {js| grayscale(100%) sepia(100%)|js}); CssJs.unsafe({js|backdropFilter|js}, {js| none|js}); CssJs.unsafe({js|backdropFilter|js}, {js| url(#id)|js}); +CssJs.unsafe({js|backdropFilter|js}, {js| url(image.svg#id)|js}); CssJs.unsafe({js|backdropFilter|js}, {js| blur(5px)|js}); CssJs.unsafe({js|backdropFilter|js}, {js| brightness(0.5)|js}); CssJs.unsafe({js|backdropFilter|js}, {js| contrast(150%)|js}); @@ -1415,6 +1424,12 @@ CssJs.unsafe({js|scrollMargin|js}, {js| 6px 5px|js}); CssJs.unsafe({js|scrollMargin|js}, {js| 10px 20px 30px|js}); CssJs.unsafe({js|scrollMargin|js}, {js| 10px 20px 30px 40px|js}); CssJs.unsafe({js|scrollMargin|js}, {js| 20px 3em 1in 5rem|js}); +CssJs.unsafe({js|scrollMargin|js}, {js| calc(2px)|js}); +CssJs.unsafe({js|scrollMargin|js}, {js| calc(3 * 25px)|js}); +CssJs.unsafe( + {js|scrollMargin|js}, + {js| calc(3 * 25px) 5px 10em calc(1vw - 5px)|js}, +); CssJs.unsafe({js|scrollMarginBlock|js}, {js| 10px|js}); CssJs.unsafe({js|scrollMarginBlock|js}, {js| 10px 10px|js}); CssJs.unsafe({js|scrollMarginBlockEnd|js}, {js| 10px|js}); @@ -1435,6 +1450,13 @@ CssJs.unsafe({js|scrollPadding|js}, {js| 10px 20px 30px 40px|js}); CssJs.unsafe({js|scrollPadding|js}, {js| 10px auto 30px auto|js}); CssJs.unsafe({js|scrollPadding|js}, {js| 10%|js}); CssJs.unsafe({js|scrollPadding|js}, {js| 20% 3em 1in 5rem|js}); +CssJs.unsafe({js|scrollPadding|js}, {js| calc(2px)|js}); +CssJs.unsafe({js|scrollPadding|js}, {js| calc(50%)|js}); +CssJs.unsafe({js|scrollPadding|js}, {js| calc(3 * 25px)|js}); +CssJs.unsafe( + {js|scrollPadding|js}, + {js| calc(3 * 25px) 5px 10% calc(10% - 5px)|js}, +); CssJs.unsafe({js|scrollPaddingBlock|js}, {js| 10px|js}); CssJs.unsafe({js|scrollPaddingBlock|js}, {js| 50%|js}); CssJs.unsafe({js|scrollPaddingBlock|js}, {js| 10px 50%|js}); @@ -1692,6 +1714,8 @@ CssJs.maxHeight(`maxContent); CssJs.maxHeight(`minContent); CssJs.unsafe({js|maxHeight|js}, {js| fit-content(10%)|js}); CssJs.unsafe({js|aspectRatio|js}, {js| auto|js}); +CssJs.unsafe({js|aspectRatio|js}, {js| 2|js}); +CssJs.unsafe({js|aspectRatio|js}, {js| 16 / 9|js}); CssJs.width(`fitContent); CssJs.minWidth(`fitContent); CssJs.maxWidth(`fitContent); diff --git a/packages/ppx/test/css-support/test.re b/packages/ppx/test/css-support/test.re index 248497c72..97ff1be89 100644 --- a/packages/ppx/test/css-support/test.re +++ b/packages/ppx/test/css-support/test.re @@ -1892,11 +1892,11 @@ /* CSS Masking Module Level 1 */ [%css {|clip-path: url('#clip')|}]; [%css {|clip-path: inset(50%)|}]; -/* [%css {|clip-path: circle()|}]; */ -/* [%css {|clip-path: ellipse()|}]; */ +[%css {|clip-path: circle()|}]; +[%css {|clip-path: ellipse()|}]; /* [%css {|clip-path: polygon(0 10px, 30px 0)|}]; */ -/* [%css {|clip-path: path('M 20 20 H 80 V 30')|}]; */ -/* [%css {|clip-path: circle() border-box|}]; */ +[%css {|clip-path: path('M 20 20 H 80 V 30')|}]; +[%css {|clip-path: circle() border-box|}]; [%css {|clip-path: border-box|}]; [%css {|clip-path: padding-box|}]; [%css {|clip-path: content-box|}]; @@ -1908,6 +1908,7 @@ [%css {|clip-rule: nonzero|}]; [%css {|clip-rule: evenodd|}]; [%css {|mask-image: none|}]; +/* TODO: Parser.re don't contain linear-gradient as valid mask-image */ /* [%css {|mask-image: linear-gradient(black 0%, transparent 100%)|}]; */ [%css {|mask-image: url(image.png)|}]; [%css {|mask-mode: alpha|}]; @@ -1938,7 +1939,8 @@ [%css {|mask-position: center|}]; [%css {|mask-position: center center|}]; [%css {|mask-position: left 50%|}]; -/* [%css {|mask-position: bottom 10px right 20px|}]; */ +[%css {|mask-position: bottom 10px right 20px|}]; +/* TODO: mask-position is incomplete in Parser.re */ /* [%css {|mask-position: bottom 10px right|}]; */ /* [%css {|mask-position: top right 10px|}]; */ [%css {|mask-clip: border-box|}]; @@ -1975,7 +1977,7 @@ [%css {|mask: url(image.png) luminance|}]; [%css {|mask: url(image.png) luminance top space|}]; [%css {|mask-border-source: none|}]; -/* [%css {|mask-border-source: url(image.png)|}]; */ +[%css {|mask-border-source: url(image.png)|}]; [%css {|mask-border-slice: 0 fill|}]; [%css {|mask-border-slice: 50% fill|}]; [%css {|mask-border-slice: 1.1 fill|}]; @@ -2015,7 +2017,8 @@ [%css {|mask-border-repeat: repeat space|}]; [%css {|mask-border-repeat: round space|}]; [%css {|mask-border-repeat: space space|}]; -/* [%css {|mask-border: url(image.png)|}]; */ +[%css {|mask-border: url(image.png)|}]; +/* TODO: Parser.re is incomplete */ /* [%css {|mask-border: url(image.png) 10px|}]; */ /* [%css {|mask-border: url(image.png) space|}]; */ /* [%css {|mask-border: url(image.png) 1 fill|}]; */ @@ -2143,7 +2146,7 @@ /* Filter Effects Module Level 1 */ [%css {|filter: none|}]; [%css {|filter: url(#id)|}]; -/* [%css {|filter: url(image.svg#id)|}]; */ +[%css {|filter: url(image.svg#id)|}]; [%css {|filter: blur(5px)|}]; [%css {|filter: brightness(0.5)|}]; [%css {|filter: contrast(150%)|}]; @@ -2170,7 +2173,7 @@ /* Filter Effects Module Level 2 */ [%css {|backdrop-filter: none|}]; [%css {|backdrop-filter: url(#id)|}]; -/* [%css {|backdrop-filter: url(image.svg#id)|}]; */ +[%css {|backdrop-filter: url(image.svg#id)|}]; [%css {|backdrop-filter: blur(5px)|}]; [%css {|backdrop-filter: brightness(0.5)|}]; [%css {|backdrop-filter: contrast(150%)|}]; @@ -2292,9 +2295,9 @@ [%css {|scroll-margin: 10px 20px 30px|}]; [%css {|scroll-margin: 10px 20px 30px 40px|}]; [%css {|scroll-margin: 20px 3em 1in 5rem|}]; -/* [%css {|scroll-margin: calc(2px)|}]; */ -/* [%css {|scroll-margin: calc(3 * 25px)|}]; */ -/* [%css {|scroll-margin: calc(3 * 25px) 5px 10em calc(1vw - 5px)|}]; */ +[%css {|scroll-margin: calc(2px)|}]; +[%css {|scroll-margin: calc(3 * 25px)|}]; +[%css {|scroll-margin: calc(3 * 25px) 5px 10em calc(1vw - 5px)|}]; [%css {|scroll-margin-block: 10px|}]; [%css {|scroll-margin-block: 10px 10px|}]; [%css {|scroll-margin-block-end: 10px|}]; @@ -2315,10 +2318,10 @@ [%css {|scroll-padding: 10px auto 30px auto|}]; [%css {|scroll-padding: 10%|}]; [%css {|scroll-padding: 20% 3em 1in 5rem|}]; -/* [%css {|scroll-padding: calc(2px)|}]; */ -/* [%css {|scroll-padding: calc(50%)|}]; */ -/* [%css {|scroll-padding: calc(3 * 25px)|}]; */ -/* [%css {|scroll-padding: calc(3 * 25px) 5px 10% calc(10% - 5px)|}]; */ +[%css {|scroll-padding: calc(2px)|}]; +[%css {|scroll-padding: calc(50%)|}]; +[%css {|scroll-padding: calc(3 * 25px)|}]; +[%css {|scroll-padding: calc(3 * 25px) 5px 10% calc(10% - 5px)|}]; [%css {|scroll-padding-block: 10px|}]; [%css {|scroll-padding-block: 50%|}]; [%css {|scroll-padding-block: 10px 50%|}]; @@ -2522,6 +2525,7 @@ [%css {|list-style-type: other-style|}]; [%css {|list-style-type: inside|}]; [%css {|list-style-type: outside|}]; +/* TODO: escape chars lexing is half broken */ /* [%css {|list-style-type: \32 style|}]; */ [%css {|list-style-type: "-"|}]; [%css {|list-style-type: '-'|}]; @@ -2631,8 +2635,8 @@ /* CSS Box Sizing Module Level 4 */ [%css {|aspect-ratio: auto|}]; -/* [%css {|aspect-ratio: 2|}]; */ -/* [%css {|aspect-ratio: 16 / 9|}]; */ +[%css {|aspect-ratio: 2|}]; +[%css {|aspect-ratio: 16 / 9|}]; /* [%css {|aspect-ratio: auto 16 / 9|}]; */ /* [%css {|contain-intrinsic-size: none|}]; */ /* [%css {|contain-intrinsic-size: 10px|}]; */ diff --git a/packages/reason-css-parser/lib/Parser.re b/packages/reason-css-parser/lib/Parser.re index eaac04e91..546542d8e 100644 --- a/packages/reason-css-parser/lib/Parser.re +++ b/packages/reason-css-parser/lib/Parser.re @@ -877,7 +877,7 @@ and pseudo_class_selector = [%value.rec "':' | ':' "] and pseudo_page = [%value.rec "':' [ 'left' | 'right' | 'first' | 'blank' ]"] and quote = [%value.rec "'open-quote' | 'close-quote' | 'no-open-quote' | 'no-close-quote'"] -and ratio = [%value.rec " '/' "] +and ratio = [%value.rec " '/' | "] and relative_selector = [%value.rec "[ ]? "] and relative_selector_list = [%value.rec "[ ]#"] and relative_size = [%value.rec "'larger' | 'smaller'"] diff --git a/packages/renderer/ast_renderer.re b/packages/renderer/ast_renderer.re index d97ea649f..da5cd6cfd 100644 --- a/packages/renderer/ast_renderer.re +++ b/packages/renderer/ast_renderer.re @@ -186,7 +186,7 @@ and render_component_value = (ast: with_loc(Component_value.t)) => { | Function(name, body) => let body = body |> fst |> List.map(render_component_value) |> String.concat(", "); - "Function(" ++ fst(name) ++ ", " ++ body ++ ")"; + "Function(" ++ fst(name) ++ ", [" ++ body ++ "])"; | Hash(string) => "Hash(" ++ string ++ ")" | Number(string) => "Number(" ++ string ++ ")" | Unicode_range(string) => "Unicode_range(" ++ string ++ ")"