Skip to content

Commit c9593ce

Browse files
committed
Support media query to css
1 parent 3c24bb2 commit c9593ce

File tree

53 files changed

+974
-180
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+974
-180
lines changed

.changeset/puny-jeans-mix.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@devup-ui/wasm": patch
3+
---
4+
5+
css util support media query

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

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -231,50 +231,12 @@ pub fn get_theme_interface(
231231
theme_interface_name: &str,
232232
) -> String {
233233
let sheet = GLOBAL_STYLE_SHEET.lock().unwrap();
234-
let mut color_keys = HashSet::new();
235-
let mut typography_keys = HashSet::new();
236-
let mut theme_keys = HashSet::new();
237-
for color_theme in sheet.theme.colors.values() {
238-
color_theme.0.keys().for_each(|key| {
239-
color_keys.insert(key.clone());
240-
});
241-
}
242-
sheet.theme.typography.keys().for_each(|key| {
243-
typography_keys.insert(key.clone());
244-
});
245-
246-
sheet.theme.colors.keys().for_each(|key| {
247-
theme_keys.insert(key.clone());
248-
});
249-
250-
if color_keys.is_empty() && typography_keys.is_empty() {
251-
String::new()
252-
} else {
253-
format!(
254-
"import \"{}\";declare module \"{}\"{{interface {}{{{}}}interface {}{{{}}}interface {}{{{}}}}}",
255-
package_name,
256-
package_name,
257-
color_interface_name,
258-
color_keys
259-
.into_iter()
260-
.map(|key| format!("${key}:null;"))
261-
.collect::<Vec<String>>()
262-
.join(""),
263-
typography_interface_name,
264-
typography_keys
265-
.into_iter()
266-
.map(|key| format!("{key}:null;"))
267-
.collect::<Vec<String>>()
268-
.join(""),
269-
theme_interface_name,
270-
theme_keys
271-
.into_iter()
272-
// key to pascal
273-
.map(|key| format!("{key}:null;"))
274-
.collect::<Vec<String>>()
275-
.join("")
276-
)
277-
}
234+
sheet.create_interface(
235+
package_name,
236+
color_interface_name,
237+
typography_interface_name,
238+
theme_interface_name,
239+
)
278240
}
279241
#[cfg(test)]
280242
mod tests {
@@ -311,42 +273,6 @@ mod tests {
311273
);
312274
}
313275

314-
#[test]
315-
#[serial]
316-
fn test_get_theme_interface() {
317-
{
318-
let mut sheet = GLOBAL_STYLE_SHEET.lock().unwrap();
319-
*sheet = StyleSheet::default();
320-
}
321-
assert_eq!(
322-
get_theme_interface(
323-
"package",
324-
"ColorInterface",
325-
"TypographyInterface",
326-
"ThemeInterface"
327-
),
328-
""
329-
);
330-
331-
{
332-
let mut sheet = GLOBAL_STYLE_SHEET.lock().unwrap();
333-
let mut theme = Theme::default();
334-
let mut color_theme = ColorTheme::default();
335-
color_theme.add_color("primary", "#000");
336-
theme.add_color_theme("dark", color_theme);
337-
sheet.set_theme(theme);
338-
}
339-
assert_eq!(
340-
get_theme_interface(
341-
"package",
342-
"ColorInterface",
343-
"TypographyInterface",
344-
"ThemeInterface"
345-
),
346-
"import \"package\";declare module \"package\"{interface ColorInterface{$primary:null;}interface TypographyInterface{}interface ThemeInterface{dark:null;}}"
347-
);
348-
}
349-
350276
#[test]
351277
fn deserialize_theme() {
352278
{

libs/css/src/constant.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ pub(super) static DOUBLE_SEPARATOR: phf::Set<&str> = phf_set! {
7777
};
7878

7979
pub(super) static F_SPACE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"\s*,\s*").unwrap());
80+
pub(super) static F_DOT_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\b|,)0\.(\d+)").unwrap());
81+
pub(super) static DOT_ZERO_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\b|,)-?0\.0+").unwrap());
82+
8083
pub(super) static COLOR_HASH: Lazy<Regex> = Lazy::new(|| Regex::new(r"#([0-9a-zA-Z]+)").unwrap());
8184
pub(super) static ZERO_RE: Lazy<Regex> =
8285
Lazy::new(|| Regex::new(r"(^|\s|\(|,)-?0(px|em|rem|vh|vw|%|dvh|dvw)").unwrap());

libs/css/src/lib.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,16 @@ pub fn merge_selector(class_name: &str, selector: Option<&StyleSelector>) -> Str
2020
if let Some(selector) = selector {
2121
match selector {
2222
StyleSelector::Selector(value) => value.replace("&", &format!(".{class_name}")),
23-
StyleSelector::Media(_) => format!(".{class_name}"),
23+
StyleSelector::Media {
24+
selector: s,
25+
query: _,
26+
} => {
27+
if let Some(s) = s {
28+
s.replace("&", &format!(".{class_name}"))
29+
} else {
30+
format!(".{class_name}")
31+
}
32+
}
2433
StyleSelector::Global(v, _) => v.to_string(),
2534
}
2635
} else {
@@ -211,9 +220,14 @@ mod tests {
211220
sheet_to_classname("background", 0, Some("rgba(255,0,0,0.5)"), None, None),
212221
);
213222

223+
assert_eq!(
224+
sheet_to_classname("background", 0, Some("rgba(255, 0, 0, 0.5)"), None, None),
225+
sheet_to_classname("background", 0, Some("rgba(255,0,0,.5)"), None, None),
226+
);
227+
214228
{
215229
let map = GLOBAL_CLASS_MAP.lock().unwrap();
216-
assert_eq!(map.get("background-0-rgba(255,0,0,0.5)--255"), Some(&2));
230+
assert_eq!(map.get("background-0-rgba(255,0,0,.5)--255"), Some(&2));
217231
}
218232
assert_eq!(
219233
sheet_to_classname("background", 0, Some("#fff"), None, None),
@@ -365,6 +379,16 @@ mod tests {
365379
sheet_to_classname("test", 0, Some("0 0vw"), None, None),
366380
"d2"
367381
);
382+
383+
reset_class_map();
384+
assert_eq!(
385+
sheet_to_classname("transition", 0, Some("all 0.3s ease-in-out"), None, None),
386+
"d0"
387+
);
388+
assert_eq!(
389+
sheet_to_classname("transition", 0, Some("all .3s ease-in-out"), None, None),
390+
"d0"
391+
);
368392
}
369393

370394
#[test]

libs/css/src/optimize_value.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::{COLOR_HASH, F_SPACE_RE, ZERO_RE};
1+
use crate::{
2+
COLOR_HASH, F_SPACE_RE, ZERO_RE,
3+
constant::{DOT_ZERO_RE, F_DOT_RE},
4+
};
25

36
pub fn optimize_value(value: &str) -> String {
47
let mut ret = value.trim().to_string();
@@ -11,6 +14,8 @@ pub fn optimize_value(value: &str) -> String {
1114
.to_string();
1215
}
1316
if ret.contains("0") {
17+
ret = DOT_ZERO_RE.replace_all(&ret, "0").to_string();
18+
ret = F_DOT_RE.replace_all(&ret, "${1}.${2}").to_string();
1419
ret = ZERO_RE.replace_all(&ret, "${1}0").to_string();
1520
}
1621
// remove ; from dynamic value
@@ -57,6 +62,17 @@ mod tests {
5762

5863
#[rstest]
5964
#[case("0px", "0")]
65+
#[case("0.0px", "0")]
66+
#[case("0.0em", "0")]
67+
#[case("0.0rem", "0")]
68+
#[case("0.0vh", "0")]
69+
#[case("0.0vw", "0")]
70+
#[case("0.0%", "0")]
71+
#[case("0.0dvh", "0")]
72+
#[case("0.0dvw", "0")]
73+
#[case("1.3s", "1.3s")]
74+
#[case("0.3s", ".3s")]
75+
#[case("0.3s ease-in-out", ".3s ease-in-out")]
6076
#[case("0em", "0")]
6177
#[case("0rem", "0")]
6278
#[case("0vh", "0")]
@@ -73,6 +89,7 @@ mod tests {
7389
#[case("scale(0px)", "scale(0)")]
7490
#[case("scale(-0px)", "scale(0)")]
7591
#[case("scale(-0px);", "scale(0)")]
92+
#[case("rgba(255, 0, 0, 0.5)", "rgba(255,0,0,.5)")]
7693
#[case("red;", "red")]
7794
#[case("translate(0px)", "translate(0)")]
7895
#[case("translate(-0px,0px)", "translate(0,0)")]

libs/css/src/style_selector.rs

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use crate::{constant::SELECTOR_ORDER_MAP, selector_separator::SelectorSeparator,
99

1010
#[derive(Debug, PartialEq, Clone, Hash, Eq, Serialize, Deserialize)]
1111
pub enum StyleSelector {
12-
Media(String),
12+
Media {
13+
query: String,
14+
selector: Option<String>,
15+
},
1316
Selector(String),
1417
// selector, file
1518
Global(String, String),
@@ -23,12 +26,36 @@ impl PartialOrd for StyleSelector {
2326
impl Ord for StyleSelector {
2427
fn cmp(&self, other: &Self) -> Ordering {
2528
match (self, other) {
26-
(StyleSelector::Media(a), StyleSelector::Media(b)) => a.cmp(b),
29+
(
30+
StyleSelector::Media {
31+
query: a,
32+
selector: aa,
33+
},
34+
StyleSelector::Media {
35+
query: b,
36+
selector: bb,
37+
},
38+
) => {
39+
let c = a.cmp(b);
40+
if c == Ordering::Equal { aa.cmp(bb) } else { c }
41+
}
2742
(StyleSelector::Selector(a), StyleSelector::Selector(b)) => {
2843
get_selector_order(a).cmp(&get_selector_order(b))
2944
}
30-
(StyleSelector::Media(_), StyleSelector::Selector(_)) => Ordering::Greater,
31-
(StyleSelector::Selector(_), StyleSelector::Media(_)) => Ordering::Less,
45+
(
46+
StyleSelector::Media {
47+
selector: _,
48+
query: _,
49+
},
50+
StyleSelector::Selector(_),
51+
) => Ordering::Greater,
52+
(
53+
StyleSelector::Selector(_),
54+
StyleSelector::Media {
55+
selector: _,
56+
query: _,
57+
},
58+
) => Ordering::Less,
3259
(StyleSelector::Global(a, _), StyleSelector::Global(b, _)) => {
3360
if a == b {
3461
return Ordering::Equal;
@@ -84,7 +111,10 @@ impl From<&str> for StyleSelector {
84111
&s[1..]
85112
))
86113
} else if value == "print" {
87-
StyleSelector::Media("print".to_string())
114+
StyleSelector::Media {
115+
query: "print".to_string(),
116+
selector: None,
117+
}
88118
} else {
89119
let post = to_kebab_case(value);
90120

@@ -134,7 +164,13 @@ impl Display for StyleSelector {
134164
"{}",
135165
match self {
136166
StyleSelector::Selector(value) => value.to_string(),
137-
StyleSelector::Media(value) => format!("@{value}"),
167+
StyleSelector::Media { query, selector } => {
168+
if let Some(selector) = selector {
169+
format!("@{query} {selector}")
170+
} else {
171+
format!("@{query}")
172+
}
173+
}
138174
StyleSelector::Global(value, _) => format!("{value}"),
139175
}
140176
)
@@ -182,7 +218,12 @@ mod tests {
182218

183219
#[rstest]
184220
#[case(StyleSelector::Selector("&:hover".to_string()), "&:hover")]
185-
#[case(StyleSelector::Media("screen and (max-width: 600px)".to_string()), "@screen and (max-width: 600px)")]
221+
#[case(StyleSelector::Media {
222+
query: "screen and (max-width: 600px)".to_string(),
223+
selector: None,
224+
},
225+
"@screen and (max-width: 600px)"
226+
)]
186227
#[case(StyleSelector::Global(":root[data-theme=dark]".to_string(), "file.rs".to_string()), ":root[data-theme=dark]")]
187228
fn test_style_selector_display(#[case] selector: StyleSelector, #[case] expected: &str) {
188229
let output = format!("{selector}");
@@ -191,7 +232,10 @@ mod tests {
191232

192233
#[rstest]
193234
#[case(
194-
StyleSelector::Media("screen".to_string()),
235+
StyleSelector::Media {
236+
query: "screen".to_string(),
237+
selector: None,
238+
},
195239
StyleSelector::Selector("&:hover".to_string()),
196240
std::cmp::Ordering::Greater
197241
)]
@@ -201,8 +245,14 @@ mod tests {
201245
std::cmp::Ordering::Less
202246
)]
203247
#[case(
204-
StyleSelector::Media("a".to_string()),
205-
StyleSelector::Media("b".to_string()),
248+
StyleSelector::Media {
249+
query: "a".to_string(),
250+
selector: None,
251+
},
252+
StyleSelector::Media {
253+
query: "b".to_string(),
254+
selector: None,
255+
},
206256
std::cmp::Ordering::Less
207257
)]
208258
#[case(
@@ -217,7 +267,10 @@ mod tests {
217267
)]
218268
#[case(
219269
StyleSelector::Selector("&:hover".to_string()),
220-
StyleSelector::Media("screen".to_string()),
270+
StyleSelector::Media {
271+
query: "screen".to_string(),
272+
selector: None,
273+
},
221274
std::cmp::Ordering::Less
222275
)]
223276
#[case(

0 commit comments

Comments
 (0)