Skip to content

Commit 0b99f3a

Browse files
committed
Implement Deep colors
1 parent cbfb780 commit 0b99f3a

File tree

10 files changed

+549
-308
lines changed

10 files changed

+549
-308
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"changes": { "bindings/devup-ui-wasm/package.json": "Patch" },
3+
"note": "Optimize theme interface support deep colors",
4+
"date": "2025-12-26T12:30:04.669317200Z"
5+
}

bindings/devup-ui-wasm/src/lib.rs

Lines changed: 25 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ mod tests {
341341
let mut color_theme = ColorTheme::default();
342342
color_theme.add_color("primary", "#000");
343343

344-
assert_eq!(color_theme.0.keys().count(), 1);
344+
assert_eq!(color_theme.css_keys().count(), 1);
345345

346346
theme.add_color_theme("default", color_theme);
347347
let mut color_theme = ColorTheme::default();
@@ -391,151 +391,44 @@ mod tests {
391391
);
392392
assert_eq!(theme.to_css(), "");
393393

394-
let mut theme = Theme::default();
395-
theme.add_color_theme(
396-
"default",
397-
ColorTheme({
398-
let mut map = HashMap::new();
399-
map.insert("primary".to_string(), "#000".to_string());
400-
map
401-
}),
402-
);
394+
// Helper to create a ColorTheme with a single color
395+
fn make_color_theme(name: &str, value: &str) -> ColorTheme {
396+
let mut ct = ColorTheme::default();
397+
ct.add_color(name, value);
398+
ct
399+
}
403400

404-
theme.add_color_theme(
405-
"dark",
406-
ColorTheme({
407-
let mut map = HashMap::new();
408-
map.insert("primary".to_string(), "#000".to_string());
409-
map
410-
}),
411-
);
401+
let mut theme = Theme::default();
402+
theme.add_color_theme("default", make_color_theme("primary", "#000"));
403+
theme.add_color_theme("dark", make_color_theme("primary", "#000"));
412404
assert_debug_snapshot!(theme.to_css());
413405

414406
let mut theme = Theme::default();
415-
theme.add_color_theme(
416-
"light",
417-
ColorTheme({
418-
let mut map = HashMap::new();
419-
map.insert("primary".to_string(), "#000".to_string());
420-
map
421-
}),
422-
);
423-
424-
theme.add_color_theme(
425-
"dark",
426-
ColorTheme({
427-
let mut map = HashMap::new();
428-
map.insert("primary".to_string(), "#000".to_string());
429-
map
430-
}),
431-
);
407+
theme.add_color_theme("light", make_color_theme("primary", "#000"));
408+
theme.add_color_theme("dark", make_color_theme("primary", "#000"));
432409
assert_debug_snapshot!(theme.to_css());
433410

434411
let mut theme = Theme::default();
435-
theme.add_color_theme(
436-
"a",
437-
ColorTheme({
438-
let mut map = HashMap::new();
439-
map.insert("primary".to_string(), "#000".to_string());
440-
map
441-
}),
442-
);
443-
444-
theme.add_color_theme(
445-
"b",
446-
ColorTheme({
447-
let mut map = HashMap::new();
448-
map.insert("primary".to_string(), "#000".to_string());
449-
map
450-
}),
451-
);
412+
theme.add_color_theme("a", make_color_theme("primary", "#000"));
413+
theme.add_color_theme("b", make_color_theme("primary", "#000"));
452414
assert_debug_snapshot!(theme.to_css());
453415

454416
let mut theme = Theme::default();
455-
theme.add_color_theme(
456-
"light",
457-
ColorTheme({
458-
let mut map = HashMap::new();
459-
map.insert("primary".to_string(), "#000".to_string());
460-
map
461-
}),
462-
);
463-
464-
theme.add_color_theme(
465-
"b",
466-
ColorTheme({
467-
let mut map = HashMap::new();
468-
map.insert("primary".to_string(), "#000".to_string());
469-
map
470-
}),
471-
);
472-
473-
theme.add_color_theme(
474-
"a",
475-
ColorTheme({
476-
let mut map = HashMap::new();
477-
map.insert("primary".to_string(), "#000".to_string());
478-
map
479-
}),
480-
);
481-
482-
theme.add_color_theme(
483-
"c",
484-
ColorTheme({
485-
let mut map = HashMap::new();
486-
map.insert("primary".to_string(), "#000".to_string());
487-
map
488-
}),
489-
);
417+
theme.add_color_theme("light", make_color_theme("primary", "#000"));
418+
theme.add_color_theme("b", make_color_theme("primary", "#000"));
419+
theme.add_color_theme("a", make_color_theme("primary", "#000"));
420+
theme.add_color_theme("c", make_color_theme("primary", "#000"));
490421
assert_debug_snapshot!(theme.to_css());
491422

492423
let mut theme = Theme::default();
493-
theme.add_color_theme(
494-
"light",
495-
ColorTheme({
496-
let mut map = HashMap::new();
497-
map.insert("primary".to_string(), "#000".to_string());
498-
map
499-
}),
500-
);
424+
theme.add_color_theme("light", make_color_theme("primary", "#000"));
501425
assert_debug_snapshot!(theme.to_css());
502426

503427
let mut theme = Theme::default();
504-
theme.add_color_theme(
505-
"light",
506-
ColorTheme({
507-
let mut map = HashMap::new();
508-
map.insert("primary".to_string(), "#000".to_string());
509-
map
510-
}),
511-
);
512-
513-
theme.add_color_theme(
514-
"b",
515-
ColorTheme({
516-
let mut map = HashMap::new();
517-
map.insert("primary".to_string(), "#001".to_string());
518-
map
519-
}),
520-
);
521-
522-
theme.add_color_theme(
523-
"a",
524-
ColorTheme({
525-
let mut map = HashMap::new();
526-
map.insert("primary".to_string(), "#002".to_string());
527-
map
528-
}),
529-
);
530-
531-
theme.add_color_theme(
532-
"c",
533-
ColorTheme({
534-
let mut map = HashMap::new();
535-
map.insert("primary".to_string(), "#000".to_string());
536-
map
537-
}),
538-
);
428+
theme.add_color_theme("light", make_color_theme("primary", "#000"));
429+
theme.add_color_theme("b", make_color_theme("primary", "#001"));
430+
theme.add_color_theme("a", make_color_theme("primary", "#002"));
431+
theme.add_color_theme("c", make_color_theme("primary", "#000"));
539432
assert_debug_snapshot!(theme.to_css());
540433
}
541434

@@ -584,7 +477,7 @@ mod tests {
584477
"TypographyInterface",
585478
"ThemeInterface"
586479
),
587-
"import \"package\";declare module \"package\"{interface ColorInterface{$primary:null;}interface TypographyInterface{}interface ThemeInterface{dark:null;}}"
480+
"import \"package\";declare module \"package\"{interface ColorInterface{$primary:null}interface TypographyInterface{}interface ThemeInterface{dark:null}}"
588481
);
589482

590483
// test wrong case
@@ -612,7 +505,7 @@ mod tests {
612505
"TypographyInterface",
613506
"ThemeInterface"
614507
),
615-
"import \"package\";declare module \"package\"{interface ColorInterface{[`$(primary)`]:null;}interface TypographyInterface{[`prim\\`\\`ary`]:null;}interface ThemeInterface{dark:null;}}"
508+
"import \"package\";declare module \"package\"{interface ColorInterface{[`$(primary)`]:null}interface TypographyInterface{[`prim\\`\\`ary`]:null}interface ThemeInterface{dark:null}}"
616509
);
617510
}
618511

bindings/devup-ui-wasm/src/snapshots/devup_ui_wasm__tests__deserialize_theme-2.snap

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,24 @@ expression: theme
44
---
55
Theme {
66
colors: {
7-
"dark": ColorTheme(
8-
{
9-
"primary": "#fff",
7+
"dark": ColorTheme {
8+
entries: {
9+
"primary": ColorEntry {
10+
interface_key: "primary",
11+
css_key: "primary",
12+
value: "#fff",
13+
},
1014
},
11-
),
12-
"default": ColorTheme(
13-
{
14-
"primary": "#000",
15+
},
16+
"default": ColorTheme {
17+
entries: {
18+
"primary": ColorEntry {
19+
interface_key: "primary",
20+
css_key: "primary",
21+
value: "#000",
22+
},
1523
},
16-
),
24+
},
1725
},
1826
breakpoints: [
1927
0,

libs/sheet/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ edition = "2024"
66
[dependencies]
77
css = { path = "../css" }
88
serde = { version = "1.0.228", features = ["derive"] }
9+
serde_json = "1.0.146"
910
regex = "1.12.2"
1011
once_cell = "1.21.3"
1112
extractor = { path = "../extractor" }
1213

1314
[dev-dependencies]
1415
insta = "1.45.0"
15-
serde_json = "1.0.146"
1616
criterion = { version = "0.8", features = ["html_reports"] }
1717
rstest = "0.26.1"
1818

libs/sheet/src/lib.rs

Lines changed: 77 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,11 @@ impl StyleSheet {
383383
typography_interface_name: &str,
384384
theme_interface_name: &str,
385385
) -> String {
386-
let mut color_keys = HashSet::new();
387-
let mut typography_keys = HashSet::new();
388-
let mut theme_keys = HashSet::new();
386+
let mut color_keys = BTreeSet::new();
387+
let mut typography_keys = BTreeSet::new();
388+
let mut theme_keys = BTreeSet::new();
389389
for color_theme in self.theme.colors.values() {
390-
color_theme.0.keys().for_each(|key| {
390+
color_theme.interface_keys().for_each(|key| {
391391
color_keys.insert(key.clone());
392392
});
393393
}
@@ -409,19 +409,21 @@ impl StyleSheet {
409409
color_interface_name,
410410
color_keys
411411
.into_iter()
412-
.map(|key| format!("{}:null;", convert_interface_key(&format!("${key}"))))
413-
.collect::<String>(),
412+
.map(|key| format!("{}:null", convert_interface_key(&format!("${key}"))))
413+
.collect::<Vec<_>>()
414+
.join(";"),
414415
typography_interface_name,
415416
typography_keys
416417
.into_iter()
417-
.map(|key| format!("{}:null;", convert_interface_key(&key)))
418-
.collect::<String>(),
418+
.map(|key| format!("{}:null", convert_interface_key(&key)))
419+
.collect::<Vec<_>>()
420+
.join(";"),
419421
theme_interface_name,
420422
theme_keys
421423
.into_iter()
422-
// key to pascal
423-
.map(|key| format!("{}:null;", convert_interface_key(&key)))
424-
.collect::<String>()
424+
.map(|key| format!("{}:null", convert_interface_key(&key)))
425+
.collect::<Vec<_>>()
426+
.join(";")
425427
)
426428
}
427429
}
@@ -1628,17 +1630,14 @@ mod tests {
16281630
color_theme.add_color("primary", "#000");
16291631
theme.add_color_theme("dark", color_theme);
16301632
sheet.set_theme(theme);
1631-
assert_eq!(
1632-
sheet.create_interface(
1633-
"package",
1634-
"ColorInterface",
1635-
"TypographyInterface",
1636-
"ThemeInterface"
1637-
),
1638-
"import \"package\";declare module \"package\"{interface ColorInterface{$primary:null;}interface TypographyInterface{}interface ThemeInterface{dark:null;}}"
1639-
);
1640-
1641-
// test wrong case
1633+
assert_debug_snapshot!(sheet.create_interface(
1634+
"package",
1635+
"ColorInterface",
1636+
"TypographyInterface",
1637+
"ThemeInterface"
1638+
));
1639+
1640+
// test wrong case (backticks and special characters)
16421641
let mut sheet = StyleSheet::default();
16431642
let mut theme = Theme::default();
16441643
let mut color_theme = ColorTheme::default();
@@ -1655,15 +1654,62 @@ mod tests {
16551654
))],
16561655
);
16571656
sheet.set_theme(theme);
1658-
assert_eq!(
1659-
sheet.create_interface(
1660-
"package",
1661-
"ColorInterface",
1662-
"TypographyInterface",
1663-
"ThemeInterface"
1664-
),
1665-
"import \"package\";declare module \"package\"{interface ColorInterface{[`$(primary)`]:null;}interface TypographyInterface{[`prim\\`\\`ary`]:null;}interface ThemeInterface{dark:null;}}"
1666-
);
1657+
assert_debug_snapshot!(sheet.create_interface(
1658+
"package",
1659+
"ColorInterface",
1660+
"TypographyInterface",
1661+
"ThemeInterface"
1662+
));
1663+
1664+
// test nested colors - interface keys should use dots for TypeScript
1665+
let mut sheet = StyleSheet::default();
1666+
let theme: Theme = serde_json::from_str(
1667+
r##"{
1668+
"colors": {
1669+
"light": {
1670+
"gray": {
1671+
"100": "#f5f5f5",
1672+
"200": "#eee"
1673+
},
1674+
"primary": "#000",
1675+
"secondary.light": "#ccc"
1676+
}
1677+
}
1678+
}"##,
1679+
)
1680+
.unwrap();
1681+
sheet.set_theme(theme);
1682+
assert_debug_snapshot!(sheet.create_interface(
1683+
"package",
1684+
"ColorInterface",
1685+
"TypographyInterface",
1686+
"ThemeInterface"
1687+
));
1688+
1689+
// test deep nested colors
1690+
let mut sheet = StyleSheet::default();
1691+
let theme: Theme = serde_json::from_str(
1692+
r##"{
1693+
"colors": {
1694+
"dark": {
1695+
"brand": {
1696+
"primary": {
1697+
"light": "#f0f",
1698+
"dark": "#0f0"
1699+
}
1700+
}
1701+
}
1702+
}
1703+
}"##,
1704+
)
1705+
.unwrap();
1706+
sheet.set_theme(theme);
1707+
assert_debug_snapshot!(sheet.create_interface(
1708+
"package",
1709+
"ColorInterface",
1710+
"TypographyInterface",
1711+
"ThemeInterface"
1712+
));
16671713
}
16681714

16691715
#[test]

0 commit comments

Comments
 (0)