diff --git a/.changeset/bright-carrots-float.md b/.changeset/bright-carrots-float.md new file mode 100644 index 00000000..59288ea1 --- /dev/null +++ b/.changeset/bright-carrots-float.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Optimize to convert theme var diff --git a/Cargo.lock b/Cargo.lock index afed87fc..f821df69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,18 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + [[package]] name = "assert-unchecked" version = "0.1.2" @@ -54,6 +66,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + [[package]] name = "castaway" version = "0.2.3" @@ -78,6 +96,58 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "compact_str" version = "0.8.1" @@ -120,6 +190,73 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79" +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + [[package]] name = "css" version = "0.1.0" @@ -265,6 +402,16 @@ dependencies = [ "slab", ] +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -274,6 +421,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "indexmap" version = "2.7.0" @@ -297,6 +450,26 @@ dependencies = [ "similar", ] +[[package]] +name = "is-terminal" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.14.0" @@ -406,6 +579,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + [[package]] name = "outref" version = "0.5.1" @@ -492,7 +671,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20347f1cff149f8d7354b0a16877714f4e3f7d6eb4f5cd659c3de1d5d283e846" dependencies = [ "bitflags", - "itertools", + "itertools 0.14.0", "nonmax", "oxc_index", "oxc_syntax", @@ -613,7 +792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceb1f387b1ded0c84bdbc1f14eb087204cb9cd9ca4b4ff867be8d1575c7b20a" dependencies = [ "assert-unchecked", - "itertools", + "itertools 0.14.0", "oxc_allocator", "oxc_ast", "oxc_cfg", @@ -783,6 +962,34 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -816,6 +1023,26 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.8" @@ -1002,6 +1229,7 @@ dependencies = [ name = "sheet" version = "0.1.0" dependencies = [ + "criterion", "css", "insta", "once_cell", @@ -1109,6 +1337,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "unicode-id-start" version = "1.3.1" diff --git a/apps/landing/src/components/Header/ThemeSwitch.tsx b/apps/landing/src/components/Header/ThemeSwitch.tsx index 941b23e3..15b29dc5 100644 --- a/apps/landing/src/components/Header/ThemeSwitch.tsx +++ b/apps/landing/src/components/Header/ThemeSwitch.tsx @@ -1,6 +1,6 @@ 'use client' -import { Box, getTheme, setTheme } from '@devup-ui/react' +import { Box, css, getTheme, setTheme } from '@devup-ui/react' export function ThemeSwitch() { return ( @@ -13,6 +13,11 @@ export function ThemeSwitch() { }} > + + + ) } diff --git a/libs/css/src/lib.rs b/libs/css/src/lib.rs index a69eabe3..6d5f1029 100644 --- a/libs/css/src/lib.rs +++ b/libs/css/src/lib.rs @@ -2,6 +2,7 @@ use crate::StyleSelector::{Dual, Postfix, Prefix}; use once_cell::sync::Lazy; use regex::Regex; use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; use std::collections::{HashMap, HashSet}; use std::fmt; use std::fmt::{Display, Formatter}; @@ -25,34 +26,30 @@ pub enum StyleSelector { } impl PartialOrd for StyleSelector { - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for StyleSelector { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { + fn cmp(&self, other: &Self) -> Ordering { match (self, other) { (Postfix(a), Postfix(b)) => SELECTOR_ORDER_MAP .get(a) .unwrap_or(&0) .cmp(SELECTOR_ORDER_MAP.get(b).unwrap_or(&0)), (Prefix(a), Prefix(b)) => a.cmp(b), - (Dual(p1, a), Dual(p2, b)) => { - if p1 == p2 { - SELECTOR_ORDER_MAP - .get(a) - .unwrap_or(&0) - .cmp(SELECTOR_ORDER_MAP.get(b).unwrap_or(&0)) - } else { - p1.cmp(p2) - } - } - (Postfix(_), _) => std::cmp::Ordering::Less, - (Prefix(_), Postfix(_)) => std::cmp::Ordering::Greater, - (Prefix(_), _) => std::cmp::Ordering::Less, - (Dual(_, _), Postfix(_)) => std::cmp::Ordering::Greater, - (Dual(_, _), Prefix(_)) => std::cmp::Ordering::Greater, + (Dual(p1, a), Dual(p2, b)) => match p1.cmp(p2) { + Ordering::Equal => SELECTOR_ORDER_MAP + .get(a) + .unwrap_or(&0) + .cmp(SELECTOR_ORDER_MAP.get(b).unwrap_or(&0)), + x => x, + }, + (Postfix(_), _) => Ordering::Less, + (Prefix(_), Postfix(_)) => Ordering::Greater, + (Prefix(_), Dual(_, _)) => Ordering::Less, + (Dual(_, _), _) => Ordering::Greater, } } } diff --git a/libs/sheet/Cargo.toml b/libs/sheet/Cargo.toml index c1f9a6f0..724cfa0d 100644 --- a/libs/sheet/Cargo.toml +++ b/libs/sheet/Cargo.toml @@ -12,3 +12,8 @@ once_cell = "1.20.2" [dev-dependencies] insta = "1.42.1" serde_json = "1.0.138" +criterion = { version = "0.5", features = ["html_reports"] } + +[[bench]] +name = "my_benchmark" +harness = false diff --git a/libs/sheet/benches/my_benchmark.rs b/libs/sheet/benches/my_benchmark.rs new file mode 100644 index 00000000..c0dce865 --- /dev/null +++ b/libs/sheet/benches/my_benchmark.rs @@ -0,0 +1,49 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use once_cell::sync::Lazy; +use regex::Regex; +use std::hint::black_box; + +static VAR_RE: Lazy = Lazy::new(|| Regex::new(r"\$\w+").unwrap()); + +fn convert_theme_variable_value_a(value: &str) -> String { + if value.contains("$") { + VAR_RE + .replace_all(value, |caps: ®ex::Captures| { + format!("var(--{})", &caps[0][1..]) + }) + .to_string() + } else { + value.to_string() + } +} + +fn convert_theme_variable_value_b(value: &str) -> String { + VAR_RE + .replace_all(value, |caps: ®ex::Captures| { + format!("var(--{})", &caps[0][1..]) + }) + .to_string() +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("convert_theme_variable_value_a", |b| { + b.iter(|| { + convert_theme_variable_value_a(black_box("$primary")); + convert_theme_variable_value_a(black_box("red")); + convert_theme_variable_value_a(black_box("solid 2px red")); + convert_theme_variable_value_a(black_box("solid 2px $primary")); + }) + }); + + c.bench_function("convert_theme_variable_value_b", |b| { + b.iter(|| { + convert_theme_variable_value_b(black_box("$primary")); + convert_theme_variable_value_b(black_box("red")); + convert_theme_variable_value_b(black_box("solid 2px red")); + convert_theme_variable_value_b(black_box("solid 2px $primary")); + }) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/libs/sheet/src/lib.rs b/libs/sheet/src/lib.rs index 1bc1df35..ce3d1355 100644 --- a/libs/sheet/src/lib.rs +++ b/libs/sheet/src/lib.rs @@ -50,11 +50,15 @@ impl ExtractStyle for StyleSheetProperty { static VAR_RE: Lazy = Lazy::new(|| Regex::new(r"\$\w+").unwrap()); fn convert_theme_variable_value(value: &str) -> String { - VAR_RE - .replace_all(value, |caps: ®ex::Captures| { - format!("var(--{})", &caps[0][1..]) - }) - .to_string() + if value.contains("$") { + VAR_RE + .replace_all(value, |caps: ®ex::Captures| { + format!("var(--{})", &caps[0][1..]) + }) + .to_string() + } else { + value.to_string() + } } #[derive(Debug, Hash, Eq, PartialEq, Deserialize, Serialize)] @@ -75,13 +79,10 @@ fn deserialize_btree_map_u8<'de, D>( where D: Deserializer<'de>, { - let map: BTreeMap> = - Deserialize::deserialize(deserializer)?; let mut result = BTreeMap::new(); - - for (key, value) in map { - let key: u8 = key.parse().map_err(Error::custom)?; - result.insert(key, value); + for (key, value) in BTreeMap::>::deserialize(deserializer)? + { + result.insert(key.parse().map_err(Error::custom)?, value); } Ok(result) @@ -315,6 +316,63 @@ mod tests { sheet.add_property("test", "bg", 0, "red", Some(&"hover".into()), false); sheet.add_property("test", "bg", 0, "blue", Some(&"active".into()), false); assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property( + "test", + "bg", + 0, + "red", + Some(&StyleSelector::from("groupFocusVisible")), + false, + ); + sheet.add_property( + "test", + "bg", + 0, + "blue", + Some(&StyleSelector::from("groupFocusVisible")), + false, + ); + assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property( + "test", + "bg", + 0, + "red", + Some(&StyleSelector::from("groupFocusVisible")), + false, + ); + sheet.add_property( + "test", + "bg", + 0, + "blue", + Some(&StyleSelector::from("hover")), + false, + ); + assert_debug_snapshot!(sheet.create_css()); + + let mut sheet = StyleSheet::default(); + sheet.add_property( + "test", + "bg", + 0, + "red", + Some(&StyleSelector::Dual("*".to_string(), "hover".to_string())), + false, + ); + sheet.add_property( + "test", + "bg", + 0, + "blue", + Some(&StyleSelector::from("groupFocusVisible")), + false, + ); + assert_debug_snapshot!(sheet.create_css()); } #[test] diff --git a/libs/sheet/src/snapshots/sheet__tests__create_css-5.snap b/libs/sheet/src/snapshots/sheet__tests__create_css-5.snap index eb43fc3c..e2a05023 100644 --- a/libs/sheet/src/snapshots/sheet__tests__create_css-5.snap +++ b/libs/sheet/src/snapshots/sheet__tests__create_css-5.snap @@ -2,4 +2,4 @@ source: libs/sheet/src/lib.rs expression: sheet.create_css() --- -".test::placeholder{background:red}.test:hover{background:red}.test:active{background:blue}" +"*[role=group]:focus-visible .test{background:blue}*[role=group]:focus-visible .test{background:red}" diff --git a/libs/sheet/src/snapshots/sheet__tests__create_css-6.snap b/libs/sheet/src/snapshots/sheet__tests__create_css-6.snap new file mode 100644 index 00000000..58329cdb --- /dev/null +++ b/libs/sheet/src/snapshots/sheet__tests__create_css-6.snap @@ -0,0 +1,5 @@ +--- +source: libs/sheet/src/lib.rs +expression: sheet.create_css() +--- +".test:hover{background:blue}*[role=group]:focus-visible .test{background:red}" diff --git a/libs/sheet/src/snapshots/sheet__tests__create_css-7.snap b/libs/sheet/src/snapshots/sheet__tests__create_css-7.snap new file mode 100644 index 00000000..ea306b67 --- /dev/null +++ b/libs/sheet/src/snapshots/sheet__tests__create_css-7.snap @@ -0,0 +1,5 @@ +--- +source: libs/sheet/src/lib.rs +expression: sheet.create_css() +--- +"*:hover .test{background:red}*[role=group]:focus-visible .test{background:blue}"