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}"