diff --git a/.changeset/large-poems-deny.md b/.changeset/large-poems-deny.md
new file mode 100644
index 00000000..c11ae6b7
--- /dev/null
+++ b/.changeset/large-poems-deny.md
@@ -0,0 +1,6 @@
+---
+"@devup-ui/react": patch
+"@devup-ui/wasm": patch
+---
+
+Support nested selector
diff --git a/libs/extractor/src/lib.rs b/libs/extractor/src/lib.rs
index 9bd42945..f9aa7ad3 100644
--- a/libs/extractor/src/lib.rs
+++ b/libs/extractor/src/lib.rs
@@ -1353,6 +1353,170 @@ import clsx from 'clsx'
));
}
+ #[test]
+ #[serial]
+ fn extract_nested_selector() {
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.tsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+ }
+
#[test]
#[serial]
fn extract_conditional_selector() {
@@ -2802,6 +2966,37 @@ import {Button} from '@devup/ui'
));
}
+ #[test]
+ #[serial]
+ fn nested_theme_props() {
+ reset_class_map();
+ assert_debug_snapshot!(ToBTreeSet::from(
+ extract(
+ "test.jsx",
+ r#"import {Box} from '@devup-ui/core'
+
+ "#,
+ ExtractOption {
+ package: "@devup-ui/core".to_string(),
+ css_file: None
+ }
+ )
+ .unwrap()
+ ));
+ }
+
#[test]
#[serial]
fn template_literal_props() {
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-2.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-2.snap
new file mode 100644
index 00000000..32839d06
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-2.snap
@@ -0,0 +1,22 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "blue",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&:hover::placeholder, &:hover:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-3.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-3.snap
new file mode 100644
index 00000000..e592a8ae
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-3.snap
@@ -0,0 +1,35 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "blue",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&:hover::placeholder, &:hover:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&:hover::placeholder",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-4.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-4.snap
new file mode 100644
index 00000000..4aea7d29
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-4.snap
@@ -0,0 +1,22 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&:hover::placeholder:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-5.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-5.snap
new file mode 100644
index 00000000..85af7854
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-5.snap
@@ -0,0 +1,22 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&::placeholder:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-6.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-6.snap
new file mode 100644
index 00000000..7522cf8c
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-6.snap
@@ -0,0 +1,22 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&::placeholder:active:hover",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-7.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-7.snap
new file mode 100644
index 00000000..dbff2f26
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector-7.snap
@@ -0,0 +1,35 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "blue",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&::placeholder:active:hover",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&::placeholder:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector.snap b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector.snap
new file mode 100644
index 00000000..19ce0505
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__extract_nested_selector.snap
@@ -0,0 +1,22 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ "&:hover::placeholder",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ code: "import \"@devup-ui/core/devup-ui.css\";\n;\n",
+}
diff --git a/libs/extractor/src/snapshots/extractor__tests__nested_theme_props.snap b/libs/extractor/src/snapshots/extractor__tests__nested_theme_props.snap
new file mode 100644
index 00000000..186162f1
--- /dev/null
+++ b/libs/extractor/src/snapshots/extractor__tests__nested_theme_props.snap
@@ -0,0 +1,48 @@
+---
+source: libs/extractor/src/lib.rs
+expression: "ToBTreeSet::from(extract(\"test.jsx\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap())"
+---
+ToBTreeSet {
+ styles: {
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "blue",
+ level: 0,
+ selector: Some(
+ Selector(
+ ":root[data-theme=dark] &:active",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "green",
+ level: 0,
+ selector: Some(
+ Selector(
+ ":root[data-theme=dark] &:active::placeholder",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ Static(
+ ExtractStaticStyle {
+ property: "color",
+ value: "red",
+ level: 0,
+ selector: Some(
+ Selector(
+ ":root[data-theme=dark] &:hover",
+ ),
+ ),
+ style_order: None,
+ },
+ ),
+ },
+ 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 e3964609..82e3241c 100644
--- a/libs/extractor/src/style_extractor.rs
+++ b/libs/extractor/src/style_extractor.rs
@@ -273,11 +273,7 @@ pub fn extract_style_from_expression<'a>(
level,
Some(
&if let Some(selector) = selector {
- format!(
- "{}{}",
- selector.to_string().split("&").collect::>()[0],
- name
- )
+ name.replace("&", &selector.to_string())
} else {
name
}
diff --git a/packages/react/src/types/props/index.ts b/packages/react/src/types/props/index.ts
index d3b03cf6..760f2f82 100644
--- a/packages/react/src/types/props/index.ts
+++ b/packages/react/src/types/props/index.ts
@@ -62,12 +62,12 @@ export interface DevupCommonProps
DevupUiTransitionProps,
DevupUiUiProps,
DevupUiViewTransitionProps,
+ DevupSelectorProps,
+ DevupThemeSelectorProps,
DevupUiSvgProps {}
export interface DevupProps
- extends DevupCommonProps,
- DevupSelectorProps,
- DevupThemeSelectorProps {
+ extends DevupCommonProps {
as?: T
styleVars?: Record
}