diff --git a/CHANGES.md b/CHANGES.md index 066396df1..1b13221f0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,7 @@ ## 0.62.0 +- [FIX] Accept `clamp()` as a value for length properties (`width`, `height`, `padding`, `margin`, `font-size`, `gap`, `inset`, ...). It was registered as a function but never listed in the `extended-length` value rule, so `width: clamp(1rem, 2vw, 3rem)` failed to validate (@Atlas07) - [FEATURE] Add `--env development|production` to the PPX as a preset over the individual flags: `development` = `--dev` (marker classes + readable label suffixes), `production` = `--minify` (no labels, minified CSS) (@davesnx) - [BREAKING] [FEATURE] `styled-ppx.generate` no longer takes a mode flag (`--minify` removed): the PPX embeds `[@@@css.config [("env", "production")]]` in production builds and the aggregator minifies its output automatically when every input file declares it, warning on mixed dev/production inputs. The environment is declared once, on the `(pps styled-ppx ...)` stanza (@davesnx) - [BREAKING] [FEATURE] CSS static extraction and atomization: all extensions (`[%css]`, `[%styled.]`, `[%styled.global]`, `[%keyframe]`) are now statically extracted at compile time. The PPX emits `[@@@css ...]` attributes that the `styled-ppx.generate` aggregator collects into CSS assets, with declarations atomized into content-addressed classes for zero runtime overhead (#573) (@davesnx) diff --git a/packages/css-grammar/lib/Shared.ml b/packages/css-grammar/lib/Shared.ml index a0178816a..db4f820e5 100644 --- a/packages/css-grammar/lib/Shared.ml +++ b/packages/css-grammar/lib/Shared.ml @@ -1795,7 +1795,7 @@ let url : url Rule.rule = Url.rule (* https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/length-percentage#use_in_calc *) module Extended_length = [%spec_module - " | | | | ", + " | | | | | ", (module Css_types.Length)] let extended_length : extended_length Rule.rule = Extended_length.rule diff --git a/packages/css-grammar/lib/Types.ml b/packages/css-grammar/lib/Types.ml index 46689cf45..162a268a2 100644 --- a/packages/css-grammar/lib/Types.ml +++ b/packages/css-grammar/lib/Types.ml @@ -120,6 +120,7 @@ and extended_length = | `Interpolation of string list | `Function_min of calc_sum list | `Function_max of calc_sum list + | `Function_clamp of calc_sum list ] and calc_sum = diff --git a/packages/css-grammar/test/Parser_test.re b/packages/css-grammar/test/Parser_test.re index 4b147d9b9..b4be23edf 100644 --- a/packages/css-grammar/test/Parser_test.re +++ b/packages/css-grammar/test/Parser_test.re @@ -199,6 +199,12 @@ let test_width_with_component_values = () => | Ok () => () }; +let test_width_with_clamp = () => + switch (validate_property("width", "clamp(1rem, 2vw, 3rem)")) { + | Error(msg) => Alcotest.fail("clamp should validate: " ++ msg) + | Ok () => () + }; + let test_media_query_prelude_with_component_values = () => switch ( Parser.type_check( @@ -279,6 +285,7 @@ let tests = [ `Quick, test_width_with_component_values, ), + Alcotest.test_case("width with clamp", `Quick, test_width_with_clamp), Alcotest.test_case( "media query prelude with component_value_list", `Quick, diff --git a/packages/ppx/src/Property_to_runtime.re b/packages/ppx/src/Property_to_runtime.re index adb5f5df4..358f4908d 100644 --- a/packages/ppx/src/Property_to_runtime.re +++ b/packages/ppx/src/Property_to_runtime.re @@ -394,6 +394,9 @@ and render_function_min = (~loc, calc_sums) => { and render_function_max = (~loc, calc_sums) => { [%expr `max([%e render_function_min_or_max(~loc, calc_sums)])]; } +and render_function_clamp = (~loc, calc_sums) => { + [%expr `clamp([%e render_function_min_or_max(~loc, calc_sums)])]; +} and render_calc_product = (~loc, (value, products): Types.calc_product) => { let rec go = (left, rest) => { switch (rest) { @@ -473,6 +476,7 @@ and render_extended_length = (~loc) => | `Function_calc(fc) => render_function_calc(~loc, fc) | `Function_min(values) => render_function_min(~loc, values) | `Function_max(values) => render_function_max(~loc, values) + | `Function_clamp(values) => render_function_clamp(~loc, values) | `Interpolation(i) => render_variable(~loc, String.concat(".", i)) and render_extended_percentage = (~loc) => fun diff --git a/packages/ppx/src/Property_to_string.re b/packages/ppx/src/Property_to_string.re index a77c073f1..406737610 100644 --- a/packages/ppx/src/Property_to_string.re +++ b/packages/ppx/src/Property_to_string.re @@ -208,6 +208,9 @@ and render_function_min = calc_sums => { and render_function_max = calc_sums => { render_function_min_or_max(calc_sums); } +and render_function_clamp = calc_sums => { + render_function_min_or_max(calc_sums); +} and render_product = ((value, products)) => { let rec go = (left, rest) => { switch (rest) { @@ -276,6 +279,7 @@ and render_extended_length = | `Function_calc(fc) => render_function_calc(fc) | `Function_min(values) => render_function_min(values) | `Function_max(values) => render_function_max(values) + | `Function_clamp(values) => render_function_clamp(values) | `Interpolation(i) => render_variable(String.concat(".", i)) and render_extended_percentage = diff --git a/packages/ppx/test/css-support/calc.t/input.re b/packages/ppx/test/css-support/calc.t/input.re index a2500544c..911d12638 100644 --- a/packages/ppx/test/css-support/calc.t/input.re +++ b/packages/ppx/test/css-support/calc.t/input.re @@ -3,6 +3,7 @@ [%css {|width: calc(100vh - calc(2rem + 120px))|}]; [%css {|width: calc(100vh * 2)|}]; [%css {|width: calc(2 * 120px)|}]; +[%css {|width: clamp(1rem, 2vw, 3rem)|}]; /* Test froze a bit with this expression */ /* [%css {|width: calc(100vh - calc(2rem + calc(2rem + calc(2rem + calc(2rem + 120px)))))|} diff --git a/packages/ppx/test/css-support/calc.t/run.t b/packages/ppx/test/css-support/calc.t/run.t index db56da879..0c3c8ab6e 100644 --- a/packages/ppx/test/css-support/calc.t/run.t +++ b/packages/ppx/test/css-support/calc.t/run.t @@ -18,10 +18,12 @@ If this test fail means that the module is not in sync with the ppx [@css ".css-12qo4ty{width:calc(100vh - calc(2rem + 120px));}"]; [@css ".css-1g5uhfp{width:calc(100vh * 2);}"]; [@css ".css-6t8hw4{width:calc(2 * 120px);}"]; + [@css ".css-5ikc61{width:clamp(1rem, 2vw, 3rem);}"]; CSS.make("css-hxo6vg", []); CSS.make("css-1bjj19s", []); CSS.make("css-12qo4ty", []); CSS.make("css-1g5uhfp", []); CSS.make("css-6t8hw4", []); + CSS.make("css-5ikc61", []); $ dune build diff --git a/packages/runtime/native/shared/Css_types.ml b/packages/runtime/native/shared/Css_types.ml index df8a04024..1b079db49 100644 --- a/packages/runtime/native/shared/Css_types.ml +++ b/packages/runtime/native/shared/Css_types.ml @@ -188,6 +188,7 @@ module Length = struct [ length | `min of t array | `max of t array + | `clamp of t array | `add of calc_value * calc_value | `sub of calc_value * calc_value | `mult of calc_value * calc_value @@ -204,6 +205,7 @@ module Length = struct | `calc of calc_value | `min of t array | `max of t array + | `clamp of t array ] let ch (x : float) = `ch x @@ -257,6 +259,8 @@ module Length = struct | #Percentage.t as p -> Percentage.toString p | `calc calc -> calc_value_to_string calc | (`min _ | `max _) as x -> minmax_to_string x + | `clamp xs -> + {js|clamp(|js} ^ Calc.max_or_min_values toString xs ^ {js|)|js} | #Var.t as x -> Var.toString x and calc_value_to_string x = @@ -265,12 +269,16 @@ module Length = struct | `num x -> Kloth.Float.to_string x | `calc calc -> calc_value_to_string calc | (`min _ | `max _) as x -> minmax_to_string x + | `clamp xs -> + {js|clamp(|js} ^ Calc.max_or_min_values toString xs ^ {js|)|js} | (`add _ | `sub _ | `mult _ | `div _) as x -> Calc.min_max_to_string calc_value_to_string minmax_to_string x and minmax_to_string = function | (`calc _ | `min _ | `max _ | `num _) as x -> Calc.min_max_num_to_string toString x + | `clamp xs -> + {js|clamp(|js} ^ Calc.max_or_min_values toString xs ^ {js|)|js} | #length as l -> toString l end