From bf2d907a1b293cd06081791570d290ae29644175 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Fri, 7 Feb 2025 18:18:09 +0900 Subject: [PATCH] Add snapshot tests for theme and print selectors --- .changeset/plenty-melons-look.md | 5 ++ libs/css/src/lib.rs | 79 ++++++++++++++----- libs/extractor/src/lib.rs | 29 +++++++ ...xtractor__tests__group_selector_props.snap | 5 +- .../extractor__tests__theme_selector-2.snap | 36 +++++++++ .../extractor__tests__theme_selector.snap | 23 ++++++ libs/extractor/src/style_extractor.rs | 15 +++- libs/sheet/src/lib.rs | 46 ++++++++--- .../snapshots/sheet__tests__create_css-8.snap | 5 ++ .../snapshots/sheet__tests__create_css-9.snap | 5 ++ .../sheet__tests__print_selector-2.snap | 5 ++ 11 files changed, 214 insertions(+), 39 deletions(-) create mode 100644 .changeset/plenty-melons-look.md create mode 100644 libs/extractor/src/snapshots/extractor__tests__theme_selector-2.snap create mode 100644 libs/extractor/src/snapshots/extractor__tests__theme_selector.snap create mode 100644 libs/sheet/src/snapshots/sheet__tests__create_css-8.snap create mode 100644 libs/sheet/src/snapshots/sheet__tests__create_css-9.snap create mode 100644 libs/sheet/src/snapshots/sheet__tests__print_selector-2.snap diff --git a/.changeset/plenty-melons-look.md b/.changeset/plenty-melons-look.md new file mode 100644 index 00000000..7f793862 --- /dev/null +++ b/.changeset/plenty-melons-look.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Fix compound selector issue diff --git a/libs/css/src/lib.rs b/libs/css/src/lib.rs index 272ce0d5..346fda1c 100644 --- a/libs/css/src/lib.rs +++ b/libs/css/src/lib.rs @@ -60,8 +60,21 @@ impl Ord for StyleSelector { impl From<&str> for StyleSelector { fn from(value: &str) -> Self { - if let Some(s) = value.strip_prefix("group") { - Dual("*[role=group]".to_string(), to_kebab_case(s)) + if value.contains(":") { + let t: Vec<_> = value.split(":").collect(); + if let Prefix(v) = t[0].into() { + Dual(v, t[1].to_string()) + } else { + Postfix(t[1].to_string()) + } + } else if let Some(s) = value.strip_prefix("group") { + let post = to_kebab_case(s); + Prefix(format!( + "{}{}{}", + "*[role=group]", + get_selector_separator(&post), + post + )) } else if let Some(s) = value.strip_prefix("theme") { // first character should lower case Prefix(format!( @@ -95,15 +108,20 @@ impl Display for StyleSelector { pub fn merge_selector(class_name: &str, selector: Option<&StyleSelector>) -> String { if let Some(selector) = selector { match selector { - Postfix(postfix) => match get_selector_separator(postfix) { - SelectorSeparator::Single => format!(".{}:{}", class_name, postfix), - SelectorSeparator::Double => format!(".{}::{}", class_name, postfix), - }, + Postfix(postfix) => format!( + ".{}{}{}", + class_name, + get_selector_separator(postfix), + postfix + ), Prefix(prefix) => format!("{} .{}", prefix, class_name), - Dual(prefix, postfix) => match get_selector_separator(postfix) { - SelectorSeparator::Single => format!("{}:{} .{}", prefix, postfix, class_name), - SelectorSeparator::Double => format!("{}::{} .{}", prefix, postfix, class_name), - }, + Dual(prefix, postfix) => format!( + "{} .{}{}{}", + prefix, + class_name, + get_selector_separator(postfix), + postfix + ), Media(_) => format!(".{}", class_name), } } else { @@ -115,6 +133,18 @@ pub enum SelectorSeparator { Single, Double, } +impl Display for SelectorSeparator { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!( + f, + "{}", + match self { + SelectorSeparator::Single => ":", + SelectorSeparator::Double => "::", + } + ) + } +} static DOUBLE_SEPARATOR: Lazy> = Lazy::new(|| { let mut set = HashSet::new(); @@ -627,15 +657,23 @@ mod tests { ); assert_eq!( StyleSelector::from("groupHover"), - Dual("*[role=group]".to_string(), "hover".to_string()) + Prefix("*[role=group]:hover".to_string()) ); assert_eq!( StyleSelector::from("groupFocusVisible"), - Dual("*[role=group]".to_string(), "focus-visible".to_string()) + Prefix("*[role=group]:focus-visible".to_string()) ); assert_eq!( StyleSelector::from("group1"), - Dual("*[role=group]".to_string(), "1".to_string()) + Prefix("*[role=group]:1".to_string()) + ); + + assert_eq!( + StyleSelector::from("themeDark:placeholder"), + Dual( + ":root[data-theme=dark]".to_string(), + "placeholder".to_string() + ) ); assert_eq!(Prefix(".cls".to_string()).to_string(), "-.cls-"); @@ -661,22 +699,21 @@ mod tests { assert_eq!( merge_selector( "cls", - Some(&Dual( - ":root[data-theme=dark]".to_string(), - "hover".to_string() - )), + Some(&Prefix(":root[data-theme=dark]:hover".to_string(),)), ), ":root[data-theme=dark]:hover .cls" ); assert_eq!( merge_selector( "cls", - Some(&Dual( - ":root[data-theme=dark]".to_string(), - "placeholder".to_string() - )), + Some(&Prefix(":root[data-theme=dark]::placeholder".to_string())), ), ":root[data-theme=dark]::placeholder .cls" ); + + assert_eq!( + merge_selector("cls", Some(&"themeDark:hover".into()),), + ":root[data-theme=dark] .cls:hover" + ); } } diff --git a/libs/extractor/src/lib.rs b/libs/extractor/src/lib.rs index 16e2b53e..48c874c4 100644 --- a/libs/extractor/src/lib.rs +++ b/libs/extractor/src/lib.rs @@ -2088,4 +2088,33 @@ import {Button} from '@devup/ui' ) .unwrap()); } + + #[test] + #[serial] + fn theme_selector() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } } diff --git a/libs/extractor/src/snapshots/extractor__tests__group_selector_props.snap b/libs/extractor/src/snapshots/extractor__tests__group_selector_props.snap index 7803f363..8d1b9a0b 100644 --- a/libs/extractor/src/snapshots/extractor__tests__group_selector_props.snap +++ b/libs/extractor/src/snapshots/extractor__tests__group_selector_props.snap @@ -10,9 +10,8 @@ ExtractOutput { value: "red", level: 0, selector: Some( - Dual( - "*[role=group]", - "hover", + Prefix( + "*[role=group]:hover", ), ), basic: false, diff --git a/libs/extractor/src/snapshots/extractor__tests__theme_selector-2.snap b/libs/extractor/src/snapshots/extractor__tests__theme_selector-2.snap new file mode 100644 index 00000000..f3f763fe --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__theme_selector-2.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "background", + value: "white", + level: 0, + selector: Some( + Postfix( + "hover", + ), + ), + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "background", + value: "black", + level: 0, + selector: Some( + Dual( + ":root[data-theme=dark]", + "hover", + ), + ), + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__theme_selector.snap b/libs/extractor/src/snapshots/extractor__tests__theme_selector.snap new file mode 100644 index 00000000..e8bcedcb --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__theme_selector.snap @@ -0,0 +1,23 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "background", + value: "black", + level: 0, + selector: Some( + Dual( + ":root[data-theme=dark]", + "hover", + ), + ), + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/style_extractor.rs b/libs/extractor/src/style_extractor.rs index 0ce986af..b6b0f9c9 100644 --- a/libs/extractor/src/style_extractor.rs +++ b/libs/extractor/src/style_extractor.rs @@ -74,6 +74,10 @@ pub fn extract_style_from_expression<'a>( level: u8, selector: Option<&str>, ) -> ExtractResult<'a> { + println!( + "extract_style_from_expression: {:?} {:?} {:?}", + selector, name, expression + ); let mut typo = false; if name.is_none() && selector.is_none() { @@ -240,13 +244,20 @@ pub fn extract_style_from_expression<'a>( // }; } - if let Some(selector) = name.strip_prefix("_") { + if let Some(new_selector) = name.strip_prefix("_") { return extract_style_from_expression( ast_builder, None, expression, level, - Some(selector), + Some( + if let Some(selector) = selector { + format!("{}:{}", selector, new_selector) + } else { + new_selector.to_string() + } + .as_str(), + ), ); } typo = name == "typography"; diff --git a/libs/sheet/src/lib.rs b/libs/sheet/src/lib.rs index 8f401c76..6e88e912 100644 --- a/libs/sheet/src/lib.rs +++ b/libs/sheet/src/lib.rs @@ -188,36 +188,35 @@ impl StyleSheet { .unwrap_or_else(|| self.theme.break_points.last().cloned().unwrap_or(0)), ) }; - for (media, props) in medias { - let inner_css = props + if !sorted_props.is_empty() { + let inner_css = sorted_props .into_iter() .map(ExtractStyle::extract) .collect::>() .join(""); css.push_str( if let Some(break_point) = break_point { - format!( - "\n@media (min-width:{}px) and {}{{{}}}", - break_point, media, inner_css - ) + format!("\n@media (min-width:{}px){{{}}}", break_point, inner_css) } else { - format!("\n@media {}{{{}}}", media, inner_css.as_str()) + inner_css } .as_str(), ); } - - if !sorted_props.is_empty() { - let inner_css = sorted_props + for (media, props) in medias { + let inner_css = props .into_iter() .map(ExtractStyle::extract) .collect::>() .join(""); css.push_str( if let Some(break_point) = break_point { - format!("\n@media (min-width:{}px){{{}}}", break_point, inner_css) + format!( + "\n@media (min-width:{}px) and {}{{{}}}", + break_point, media, inner_css + ) } else { - inner_css + format!("\n@media {}{{{}}}", media, inner_css.as_str()) } .as_str(), ); @@ -400,7 +399,7 @@ mod tests { "bg", 0, "red", - Some(&StyleSelector::Dual("*".to_string(), "hover".to_string())), + Some(&StyleSelector::Prefix("*:hover".to_string())), false, ); sheet.add_property( @@ -412,6 +411,21 @@ mod tests { false, ); assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property( + "test", + "bg", + 0, + "red", + Some(&"themeDark:hover".into()), + false, + ); + assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property("test", "bg", 0, "red", Some(&"wrong:hover".into()), false); + assert_debug_snapshot!(sheet.create_css()); } #[test] @@ -454,6 +468,12 @@ mod tests { sheet.add_property("test", "mx", 1, "40px", Some(&"print".into()), false); sheet.add_property("test", "my", 1, "40px", Some(&"print".into()), false); assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property("test", "mx", 0, "40px", Some(&"print".into()), false); + sheet.add_property("test", "my", 0, "40px", None, false); + + assert_debug_snapshot!(sheet.create_css()); } #[test] diff --git a/libs/sheet/src/snapshots/sheet__tests__create_css-8.snap b/libs/sheet/src/snapshots/sheet__tests__create_css-8.snap new file mode 100644 index 00000000..b00c455a --- /dev/null +++ b/libs/sheet/src/snapshots/sheet__tests__create_css-8.snap @@ -0,0 +1,5 @@ +--- +source: libs/sheet/src/lib.rs +expression: sheet.create_css() +--- +":root[data-theme=dark] .test:hover{background:red}" diff --git a/libs/sheet/src/snapshots/sheet__tests__create_css-9.snap b/libs/sheet/src/snapshots/sheet__tests__create_css-9.snap new file mode 100644 index 00000000..42aebfe1 --- /dev/null +++ b/libs/sheet/src/snapshots/sheet__tests__create_css-9.snap @@ -0,0 +1,5 @@ +--- +source: libs/sheet/src/lib.rs +expression: sheet.create_css() +--- +".test:hover{background:red}" diff --git a/libs/sheet/src/snapshots/sheet__tests__print_selector-2.snap b/libs/sheet/src/snapshots/sheet__tests__print_selector-2.snap new file mode 100644 index 00000000..070dfa9d --- /dev/null +++ b/libs/sheet/src/snapshots/sheet__tests__print_selector-2.snap @@ -0,0 +1,5 @@ +--- +source: libs/sheet/src/lib.rs +expression: sheet.create_css() +--- +".test{margin-top:40px;margin-bottom:40px;}\n@media print{.test{margin-left:40px;margin-right:40px;}}"