@@ -11416,6 +11416,227 @@ export const e = spin.toString()",
1141611416 assert!(extract("a.css.ts", code, option(false)).is_ok());
1141711417 }
1141811418
11419+ #[rstest]
11420+ #[case::user_example(
11421+ "{ color: 'hotpink' }",
11422+ "'&:hover,&:focus': hotpink",
11423+ "'&:hover': { ...hotpinkRules }, '&:focus': { ...hotpinkRules }"
11424+ )]
11425+ #[case::inner_comma(
11426+ "{ color: 'hotpink' }",
11427+ "'&:is(a,b), &:not(.x,.y)': hotpink",
11428+ "'&:is(a,b)': { ...hotpinkRules }, '&:not(.x,.y)': { ...hotpinkRules }"
11429+ )]
11430+ #[case::three_selectors(
11431+ "{ color: 'hotpink' }",
11432+ "' &:hover, &:focus, &:active ': hotpink",
11433+ "'&:hover': { ...hotpinkRules }, '&:focus': { ...hotpinkRules }, '&:active': { ...hotpinkRules }"
11434+ )]
11435+ #[case::responsive(
11436+ "{ color: ['hotpink', null, 'blue'], p: [1, 2] }",
11437+ "'&:hover,&:focus': hotpink",
11438+ "'&:hover': { ...hotpinkRules }, '&:focus': { ...hotpinkRules }"
11439+ )]
11440+ #[case::nested_layer_order(
11441+ "{ '@layer': { base: { color: 'hotpink', _active: { color: ['red', 'blue'] } } } }",
11442+ "styleOrder: 3, '&:hover,&:focus': hotpink, '&:hover': { color: 'green' }",
11443+ "styleOrder: 3, '&:hover': { ...hotpinkRules }, '&:focus': { ...hotpinkRules }, '&:hover': { color: 'green' }"
11444+ )]
11445+ #[case::quoted_commas(
11446+ "{ color: 'hotpink' }",
11447+ r#"'&[data-x=a,b], &[title="a,]b"]': hotpink"#,
11448+ r#"'&[data-x=a,b]': { ...hotpinkRules }, '&[title="a,]b"]': { ...hotpinkRules }"#
11449+ )]
11450+ #[serial]
11451+ fn test_css_nested_static_result(
11452+ #[case] rules: &str,
11453+ #[case] nested: &str,
11454+ #[case] expanded: &str,
11455+ #[values("css(hotpinkRules)", "css({}, hotpinkRules)")] source: &str,
11456+ ) {
11457+ let compile = |body| {
11458+ reset_class_map();
11459+ reset_file_map();
11460+ extract(
11461+ "test.tsx",
11462+ &format!("import {{ css }} from '@devup-ui/react'; const hotpinkRules = {rules}; const hotpink = {source}; export const hover = css({{ {body} }});"),
11463+ ExtractOption::default(),
11464+ )
11465+ .unwrap()
11466+ };
11467+ let expected = compile(expanded);
11468+ let actual = compile(nested);
11469+ assert_eq!(actual.styles, expected.styles);
11470+ assert_eq!(actual.code, expected.code);
11471+ }
11472+
11473+ #[rstest]
11474+ #[case::unknown("")]
11475+ #[case::external_class("const hotpink = css('external', { color: 'red' });")]
11476+ #[serial]
11477+ fn test_css_nested_static_result_unknown_error(#[case] binding: &str) {
11478+ reset_class_map();
11479+ reset_file_map();
11480+ let error = extract(
11481+ "test.tsx",
11482+ &format!("import {{ css }} from '@devup-ui/react'\n{binding}\nexport const hover = css({{ '&:hover,&:focus': hotpink }})"),
11483+ ExtractOption {
11484+ package: "@devup-ui/react".to_string(),
11485+ css_dir: "@devup-ui/react".to_string(),
11486+ single_css: true,
11487+ import_main_css: false,
11488+ import_aliases: HashMap::new(),
11489+ },
11490+ )
11491+ .unwrap_err()
11492+ .to_string();
11493+ assert!(
11494+ error.starts_with("test.tsx:3:47: `css()` cannot use `hotpink` at build time:")
11495+ && error.contains("its values must be literals, theme tokens or constants"),
11496+ "{error}"
11497+ );
11498+ }
11499+
11500+ #[rstest]
11501+ #[case::composed(
11502+ "const hotpink = css(base, { p: 2 });",
11503+ "hotpink",
11504+ "{ color: 'hotpink', p: 2 }"
11505+ )]
11506+ #[case::chained(
11507+ "const hotpink = css({ _active: base });",
11508+ "hotpink",
11509+ "{ _active: { color: 'hotpink' } }"
11510+ )]
11511+ #[case::keyframes(
11512+ "const hotpink = css({ animationName: spin });",
11513+ "hotpink",
11514+ "{ animationName: spin }"
11515+ )]
11516+ #[case::alias("const hotpink = base;", "hotpink", "{ color: 'hotpink' }")]
11517+ #[case::inline("", "css({ color: 'hotpink' })", "{ color: 'hotpink' }")]
11518+ #[case::inline_known_composition(
11519+ "const hotpink = css(base, { color: 'blue', _active: base });",
11520+ "css(base, { color: 'blue', _active: base })",
11521+ "{ color: 'blue', _active: { color: 'hotpink' } }"
11522+ )]
11523+ #[case::composed_later_wins(
11524+ "const hotpink = css(base, { color: 'blue', p: 2 });",
11525+ "hotpink",
11526+ "{ color: 'blue', p: 2 }"
11527+ )]
11528+ #[case::alias_chain(
11529+ "const warm = base; const hotpink = warm;",
11530+ "hotpink",
11531+ "{ color: 'hotpink' }"
11532+ )]
11533+ #[case::selector_record(
11534+ "const hotpink = css({ selectors: { '&:active': base } });",
11535+ "hotpink",
11536+ "{ selectors: { '&:active': { color: 'hotpink' } } }"
11537+ )]
11538+ #[case::declaration_string(
11539+ "const hotpink = css({ content: base });",
11540+ "hotpink",
11541+ "{ content: `${base}` }"
11542+ )]
11543+ #[case::spread_composed(
11544+ "const hotpink = css(...[base, { p: 2 }]);",
11545+ "hotpink",
11546+ "{ color: 'hotpink', p: 2 }"
11547+ )]
11548+ #[case::adjacent_spreads(
11549+ "const hotpink = css(...[base], ...[{ color: 'blue', p: 2 }]);",
11550+ "hotpink",
11551+ "{ color: 'blue', p: 2 }"
11552+ )]
11553+ #[case::nested_array_spread(
11554+ "const hotpink = css(...[...[base], { p: 2 }]);",
11555+ "hotpink",
11556+ "{ color: 'hotpink', p: 2 }"
11557+ )]
11558+ #[case::direct_spread_source(
11559+ "const hotpink = css(...{ _active: base });",
11560+ "hotpink",
11561+ "{ _active: { color: 'hotpink' } }"
11562+ )]
11563+ #[case::spread_declaration_string(
11564+ "const hotpink = css(...[{ content: base }, { p: 2 }]);",
11565+ "hotpink",
11566+ "{ content: `${base}`, p: 2 }"
11567+ )]
11568+ #[case::layer_record(
11569+ "",
11570+ "{ '@layer': { colors: base } }",
11571+ "{ '@layer': { colors: { color: 'hotpink' } } }"
11572+ )]
11573+ #[case::media_record(
11574+ "",
11575+ "{ '@media': { print: base } }",
11576+ "{ '@media': { print: { color: 'hotpink' } } }"
11577+ )]
11578+ #[case::supports_record(
11579+ "",
11580+ "{ '@supports': { '(display: grid)': base } }",
11581+ "{ '@supports': { '(display: grid)': { color: 'hotpink' } } }"
11582+ )]
11583+ #[case::container_record(
11584+ "",
11585+ "{ '@container': { '(min-width: 10px)': base } }",
11586+ "{ '@container': { '(min-width: 10px)': { color: 'hotpink' } } }"
11587+ )]
11588+ #[case::underscore_media_record(
11589+ "",
11590+ "{ _media: { print: base } }",
11591+ "{ _media: { print: { color: 'hotpink' } } }"
11592+ )]
11593+ #[case::record_declaration_string(
11594+ "",
11595+ "{ '@layer': { colors: { content: base } } }",
11596+ "{ '@layer': { colors: { content: `${base}` } } }"
11597+ )]
11598+ #[serial]
11599+ fn test_css_nested_static_source_references(
11600+ #[case] binding: &str,
11601+ #[case] value: &str,
11602+ #[case] expanded: &str,
11603+ ) {
11604+ let compile = |nested: &str| {
11605+ reset_class_map();
11606+ reset_file_map();
11607+ extract(
11608+ "test.tsx",
11609+ &format!("import {{ css, keyframes }} from '@devup-ui/react'; const spin = keyframes({{ from: {{ opacity: 0 }}, to: {{ opacity: 1 }} }}); const base = css({{ color: 'hotpink' }}); {binding} export const hover = css({{ styleOrder: 3, '@layer': {{ base: {{ '&:hover,&:focus': {nested} }} }} }});"),
11610+ ExtractOption::default(),
11611+ ).unwrap()
11612+ };
11613+ let expected = compile(expanded);
11614+ let actual = compile(value);
11615+ assert_eq!(actual.styles, expected.styles);
11616+ assert_eq!(actual.code, expected.code);
11617+ }
11618+
11619+ #[test]
11620+ #[serial]
11621+ fn test_css_nested_inline_without_binding() {
11622+ let compile = |source| {
11623+ reset_class_map();
11624+ reset_file_map();
11625+ extract("test.tsx", source, ExtractOption::default()).unwrap()
11626+ };
11627+ let expected = compile(
11628+ "import { css } from '@devup-ui/react'; css({ color: 'hotpink' }); export const hover = css({ '&:hover': { color: 'hotpink' }, '&:focus': { color: 'hotpink' } });",
11629+ );
11630+ let actual = compile(
11631+ "import { css } from '@devup-ui/react'; export const hover = css({ '&:hover,&:focus': css({ color: 'hotpink' }) });",
11632+ );
11633+ assert_eq!(actual.styles, expected.styles);
11634+ assert_eq!(
11635+ actual.code.split("export const").last(),
11636+ expected.code.split("export const").last()
11637+ );
11638+ }
11639+
1141911640 #[test]
1142011641 #[serial]
1142111642 fn test_keyframes_no_args() {
0 commit comments