From 1722428909ba380fec114be1e2a75f0d2462a645 Mon Sep 17 00:00:00 2001 From: Alexander Akait <4567934+alexander-akait@users.noreply.github.com> Date: Tue, 27 Dec 2022 15:55:46 +0300 Subject: [PATCH] feat(css/prefixer): Support `clamp` (#6695) --- .../data/prefixes_and_browsers.json | 10 +++ crates/swc_css_prefixer/src/prefixer.rs | 86 ++++++++++++++++--- .../tests/fixture/clamp/input.css | 44 ++++++++++ .../tests/fixture/clamp/output.css | 51 +++++++++++ .../clamp/output.defaults-not-ie-11.css | 34 ++++++++ 5 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 crates/swc_css_prefixer/tests/fixture/clamp/input.css create mode 100644 crates/swc_css_prefixer/tests/fixture/clamp/output.css create mode 100644 crates/swc_css_prefixer/tests/fixture/clamp/output.defaults-not-ie-11.css diff --git a/crates/swc_css_prefixer/data/prefixes_and_browsers.json b/crates/swc_css_prefixer/data/prefixes_and_browsers.json index 697041032cea..07ffeb535527 100644 --- a/crates/swc_css_prefixer/data/prefixes_and_browsers.json +++ b/crates/swc_css_prefixer/data/prefixes_and_browsers.json @@ -3294,6 +3294,16 @@ "samsung": "4" } ], + "clamp()": [ + { + "safari": "11.1", + "ios": "11.3" + }, + { + "safari": "13", + "ios": "13.3" + } + ], "-webkit-image-set()": [ { diff --git a/crates/swc_css_prefixer/src/prefixer.rs b/crates/swc_css_prefixer/src/prefixer.rs index da1c2a0ac236..d92c45ff4914 100644 --- a/crates/swc_css_prefixer/src/prefixer.rs +++ b/crates/swc_css_prefixer/src/prefixer.rs @@ -115,7 +115,7 @@ pub fn prefixer(options: Options) -> impl VisitMut { } } -pub struct CrossFadeFunctionReplacerOnLegacyVariant<'a> { +struct CrossFadeFunctionReplacerOnLegacyVariant<'a> { from: &'a str, to: &'a str, } @@ -228,14 +228,14 @@ impl VisitMut for CrossFadeFunctionReplacerOnLegacyVariant<'_> { } } -pub fn replace_cross_fade_function_on_legacy_variant(node: &mut N, from: &str, to: &str) +fn replace_cross_fade_function_on_legacy_variant(node: &mut N, from: &str, to: &str) where N: for<'aa> VisitMutWith>, { node.visit_mut_with(&mut CrossFadeFunctionReplacerOnLegacyVariant { from, to }); } -pub struct ImageSetFunctionReplacerOnLegacyVariant<'a> { +struct ImageSetFunctionReplacerOnLegacyVariant<'a> { from: &'a str, to: &'a str, in_function: bool, @@ -291,7 +291,7 @@ impl VisitMut for ImageSetFunctionReplacerOnLegacyVariant<'_> { } } -pub fn replace_image_set_function_on_legacy_variant(node: &mut N, from: &str, to: &str) +fn replace_image_set_function_on_legacy_variant(node: &mut N, from: &str, to: &str) where N: for<'aa> VisitMutWith>, { @@ -302,7 +302,7 @@ where }); } -pub struct LinearGradientFunctionReplacerOnLegacyVariant<'a> { +struct LinearGradientFunctionReplacerOnLegacyVariant<'a> { from: &'a str, to: &'a str, } @@ -478,14 +478,14 @@ impl VisitMut for LinearGradientFunctionReplacerOnLegacyVariant<'_> { } } -pub fn replace_gradient_function_on_legacy_variant(node: &mut N, from: &str, to: &str) +fn replace_gradient_function_on_legacy_variant(node: &mut N, from: &str, to: &str) where N: for<'aa> VisitMutWith>, { node.visit_mut_with(&mut LinearGradientFunctionReplacerOnLegacyVariant { from, to }); } -pub struct MediaFeatureResolutionReplacerOnLegacyVariant<'a> { +struct MediaFeatureResolutionReplacerOnLegacyVariant<'a> { from: &'a str, to: &'a str, } @@ -531,7 +531,7 @@ impl VisitMut for MediaFeatureResolutionReplacerOnLegacyVariant<'_> { } } -pub fn replace_media_feature_resolution_on_legacy_variant(node: &mut N, from: &str, to: &str) +fn replace_media_feature_resolution_on_legacy_variant(node: &mut N, from: &str, to: &str) where N: for<'aa> VisitMutWith>, { @@ -622,7 +622,7 @@ where }); } -pub struct FontFaceFormatOldSyntax {} +struct FontFaceFormatOldSyntax {} impl VisitMut for FontFaceFormatOldSyntax { fn visit_mut_function(&mut self, n: &mut Function) { @@ -662,13 +662,75 @@ impl VisitMut for FontFaceFormatOldSyntax { } } -pub fn font_face_format_old_syntax(node: &mut N) +fn font_face_format_old_syntax(node: &mut N) where N: VisitMutWith, { node.visit_mut_with(&mut FontFaceFormatOldSyntax {}); } +struct ClampReplacer {} + +impl VisitMut for ClampReplacer { + fn visit_mut_function(&mut self, n: &mut Function) { + n.visit_mut_children_with(self); + + if n.name != js_word!("clamp") { + return; + } + + let min_function = if let ( + Some(middle @ ComponentValue::CalcSum(_)), + Some(comma), + Some(right @ ComponentValue::CalcSum(_)), + ) = (n.value.get(2), n.value.get(3), n.value.get(4)) + { + Function { + span: n.span, + name: FunctionName::Ident(Ident { + span: n.span, + value: js_word!("min"), + raw: None, + }), + value: vec![middle.clone(), comma.clone(), right.clone()], + } + } else { + return; + }; + + if let (Some(left), Some(comma)) = (n.value.get(0), n.value.get(1)) { + *n = Function { + span: n.span, + name: FunctionName::Ident(Ident { + span: n.span, + value: js_word!("max"), + raw: None, + }), + value: vec![ + left.clone(), + comma.clone(), + ComponentValue::CalcSum(Box::new(CalcSum { + span: DUMMY_SP, + expressions: vec![CalcProductOrOperator::Product(CalcProduct { + span: DUMMY_SP, + expressions: vec![CalcValueOrOperator::Value(CalcValue::Function( + min_function, + ))], + })], + })), + ], + }; + } + } +} + +fn replace_clamp(node: &mut N) +where + N: VisitMutWith, +{ + node.visit_mut_with(&mut ClampReplacer {}); +} + macro_rules! to_ident { ($val:expr) => {{ ComponentValue::Ident(Box::new(Ident { @@ -1449,6 +1511,10 @@ impl VisitMut for Prefixer { "-webkit-repeating-radial-gradient", ); } + + if should_prefix("clamp()", self.env, true) { + replace_clamp(&mut webkit_value); + } } let mut moz_value = n.value.clone(); diff --git a/crates/swc_css_prefixer/tests/fixture/clamp/input.css b/crates/swc_css_prefixer/tests/fixture/clamp/input.css new file mode 100644 index 000000000000..d88990744076 --- /dev/null +++ b/crates/swc_css_prefixer/tests/fixture/clamp/input.css @@ -0,0 +1,44 @@ +a { + width: clamp(10px, 64px, 80px); +} + +a { + width: clamp(calc(100% - 10px), min(10px, 100%), max(40px, 4em)); +} + +a { + width: clamp(10%, 2px, 4rem); +} + +a { + width: clamp(10%, 2px, 4rem); + height: calc(10px + 100%); +} + +a { + width: clamp(10%, 2.5px, 5.1px); +} + +a { + width: clamp(10%, 2.5px, 5px); +} + +a { + width: clamp(calc(10px + 100%), calc(10rem + 200%), 10px); +} + +a { + width: clamp(var(--foo-a), var(--foo-b), var(--foo-c)); +} + +a { + margin: 0 40px 0 calc(-1 * clamp(32px, 16vw, 64px)); +} + +a { + font-size: clamp(clamp(1rem, 2vw, 3rem), 4vw, 5rem); +} + +a { + width: calc(10px + clamp(2px, 4px, 6px)); +} diff --git a/crates/swc_css_prefixer/tests/fixture/clamp/output.css b/crates/swc_css_prefixer/tests/fixture/clamp/output.css new file mode 100644 index 000000000000..cae5c874de0c --- /dev/null +++ b/crates/swc_css_prefixer/tests/fixture/clamp/output.css @@ -0,0 +1,51 @@ +a { + width: max(10px, min(64px, 80px)); + width: clamp(10px, 64px, 80px); +} +a { + width: max(-webkit-calc(100% - 10px), min(min(10px, 100%), max(40px, 4em))); + width: clamp(-moz-calc(100% - 10px), min(10px, 100%), max(40px, 4em)); + width: clamp(calc(100% - 10px), min(10px, 100%), max(40px, 4em)); +} +a { + width: max(10%, min(2px, 4rem)); + width: clamp(10%, 2px, 4rem); +} +a { + width: max(10%, min(2px, 4rem)); + width: clamp(10%, 2px, 4rem); + height: -webkit-calc(10px + 100%); + height: -moz-calc(10px + 100%); + height: calc(10px + 100%); +} +a { + width: max(10%, min(2.5px, 5.1px)); + width: clamp(10%, 2.5px, 5.1px); +} +a { + width: max(10%, min(2.5px, 5px)); + width: clamp(10%, 2.5px, 5px); +} +a { + width: max(-webkit-calc(10px + 100%), min(-webkit-calc(10rem + 200%), 10px)); + width: clamp(-moz-calc(10px + 100%), -moz-calc(10rem + 200%), 10px); + width: clamp(calc(10px + 100%), calc(10rem + 200%), 10px); +} +a { + width: max(var(--foo-a), min(var(--foo-b), var(--foo-c))); + width: clamp(var(--foo-a), var(--foo-b), var(--foo-c)); +} +a { + margin: 0 40px 0 -webkit-calc(-1 * max(32px, min(16vw, 64px))); + margin: 0 40px 0 -moz-calc(-1 * clamp(32px, 16vw, 64px)); + margin: 0 40px 0 calc(-1 * clamp(32px, 16vw, 64px)); +} +a { + font-size: max(max(1rem, min(2vw, 3rem)), min(4vw, 5rem)); + font-size: clamp(clamp(1rem, 2vw, 3rem), 4vw, 5rem); +} +a { + width: -webkit-calc(10px + max(2px, min(4px, 6px))); + width: -moz-calc(10px + clamp(2px, 4px, 6px)); + width: calc(10px + clamp(2px, 4px, 6px)); +} diff --git a/crates/swc_css_prefixer/tests/fixture/clamp/output.defaults-not-ie-11.css b/crates/swc_css_prefixer/tests/fixture/clamp/output.defaults-not-ie-11.css new file mode 100644 index 000000000000..3cbf86f0de74 --- /dev/null +++ b/crates/swc_css_prefixer/tests/fixture/clamp/output.defaults-not-ie-11.css @@ -0,0 +1,34 @@ +a { + width: clamp(10px, 64px, 80px); +} +a { + width: clamp(calc(100% - 10px), min(10px, 100%), max(40px, 4em)); +} +a { + width: clamp(10%, 2px, 4rem); +} +a { + width: clamp(10%, 2px, 4rem); + height: calc(10px + 100%); +} +a { + width: clamp(10%, 2.5px, 5.1px); +} +a { + width: clamp(10%, 2.5px, 5px); +} +a { + width: clamp(calc(10px + 100%), calc(10rem + 200%), 10px); +} +a { + width: clamp(var(--foo-a), var(--foo-b), var(--foo-c)); +} +a { + margin: 0 40px 0 calc(-1 * clamp(32px, 16vw, 64px)); +} +a { + font-size: clamp(clamp(1rem, 2vw, 3rem), 4vw, 5rem); +} +a { + width: calc(10px + clamp(2px, 4px, 6px)); +}