Skip to content

Commit be90632

Browse files
authored
Merge pull request #549 from dev-five-git/support-supoorts-rule
Support supports rule
2 parents 78a4662 + 0377f63 commit be90632

File tree

379 files changed

+1860
-482
lines changed

Some content is hidden

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

379 files changed

+1860
-482
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"bindings/devup-ui-wasm/package.json":"Patch","packages/react/package.json":"Patch"},"note":"Support @media, @support","date":"2026-01-12T14:31:53.767704300Z"}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
22
source: bindings/devup-ui-wasm/src/lib.rs
3-
expression: get_css(None).unwrap()
3+
expression: "get_css(None, false).unwrap().split(\"*/\").nth(1).unwrap()"
44
---
55
"@layer t;@layer t{:root{color-scheme:light;--primary:light-dark(#FFF,#000)}:root[data-theme=dark]{color-scheme:dark}}"

libs/css/src/lib.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub fn merge_selector(class_name: &str, selector: Option<&StyleSelector>) -> Str
4040
if let Some(selector) = selector {
4141
match selector {
4242
StyleSelector::Selector(value) => value.replace("&", &format!(".{class_name}")),
43-
StyleSelector::Media { selector: s, .. } => {
43+
StyleSelector::At { selector: s, .. } => {
4444
if let Some(s) = s {
4545
s.replace("&", &format!(".{class_name}"))
4646
} else {
@@ -85,7 +85,12 @@ pub fn add_selector_params(selector: StyleSelector, params: &str) -> StyleSelect
8585
StyleSelector::Global(value, file) => {
8686
StyleSelector::Global(format!("{}({})", value, params), file)
8787
}
88-
StyleSelector::Media { query, selector } => StyleSelector::Media {
88+
StyleSelector::At {
89+
kind,
90+
query,
91+
selector,
92+
} => StyleSelector::At {
93+
kind,
8994
query: query.to_string(),
9095
selector: selector.map(|s| format!("{}({})", s, params)),
9196
},
@@ -317,6 +322,7 @@ mod tests {
317322
use crate::{
318323
class_map::{get_class_map, reset_class_map, set_class_map},
319324
debug::set_debug,
325+
style_selector::AtRuleKind,
320326
};
321327

322328
use super::*;
@@ -721,7 +727,8 @@ mod tests {
721727
assert_eq!(
722728
merge_selector(
723729
"cls",
724-
Some(&StyleSelector::Media {
730+
Some(&StyleSelector::At {
731+
kind: AtRuleKind::Media,
725732
query: "print".to_string(),
726733
selector: None
727734
})
@@ -732,7 +739,8 @@ mod tests {
732739
assert_eq!(
733740
merge_selector(
734741
"cls",
735-
Some(&StyleSelector::Media {
742+
Some(&StyleSelector::At {
743+
kind: AtRuleKind::Media,
736744
query: "print".to_string(),
737745
selector: Some("&:hover".to_string())
738746
})
@@ -796,13 +804,15 @@ mod tests {
796804
);
797805
assert_eq!(
798806
add_selector_params(
799-
StyleSelector::Media {
807+
StyleSelector::At {
808+
kind: AtRuleKind::Media,
800809
query: "print".to_string(),
801810
selector: Some("&:is".to_string())
802811
},
803812
"test"
804813
),
805-
StyleSelector::Media {
814+
StyleSelector::At {
815+
kind: AtRuleKind::Media,
806816
query: "print".to_string(),
807817
selector: Some("&:is(test)".to_string())
808818
}

libs/css/src/style_selector.rs

Lines changed: 95 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,30 @@ use crate::{
1010
utils::to_camel_case,
1111
};
1212

13+
#[derive(
14+
Debug, PartialEq, PartialOrd, Ord, Clone, Copy, Hash, Eq, Serialize, Deserialize, Default,
15+
)]
16+
pub enum AtRuleKind {
17+
#[default]
18+
Media,
19+
Supports,
20+
Container,
21+
}
22+
23+
impl Display for AtRuleKind {
24+
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
25+
match self {
26+
AtRuleKind::Media => write!(f, "media"),
27+
AtRuleKind::Supports => write!(f, "supports"),
28+
AtRuleKind::Container => write!(f, "container"),
29+
}
30+
}
31+
}
32+
1333
#[derive(Debug, PartialEq, Clone, Hash, Eq, Serialize, Deserialize)]
1434
pub enum StyleSelector {
15-
Media {
35+
At {
36+
kind: AtRuleKind,
1637
query: String,
1738
selector: Option<String>,
1839
},
@@ -30,7 +51,12 @@ fn optimize_selector_string(selector: &str) -> String {
3051
}
3152
pub fn optimize_selector(selector: StyleSelector) -> StyleSelector {
3253
match selector {
33-
StyleSelector::Media { query, selector } => StyleSelector::Media {
54+
StyleSelector::At {
55+
kind,
56+
query,
57+
selector,
58+
} => StyleSelector::At {
59+
kind,
3460
query: query.to_string(),
3561
selector: selector
3662
.as_ref()
@@ -54,15 +80,21 @@ impl Ord for StyleSelector {
5480
fn cmp(&self, other: &Self) -> Ordering {
5581
match (self, other) {
5682
(
57-
StyleSelector::Media {
83+
StyleSelector::At {
84+
kind: ka,
5885
query: a,
5986
selector: aa,
6087
},
61-
StyleSelector::Media {
88+
StyleSelector::At {
89+
kind: kb,
6290
query: b,
6391
selector: bb,
6492
},
6593
) => {
94+
let k = (*ka as u8).cmp(&(*kb as u8));
95+
if k != Ordering::Equal {
96+
return k;
97+
}
6698
let c = a.cmp(b);
6799
if c == Ordering::Equal { aa.cmp(bb) } else { c }
68100
}
@@ -74,20 +106,8 @@ impl Ord for StyleSelector {
74106
order_cmp
75107
}
76108
}
77-
(
78-
StyleSelector::Media {
79-
selector: _,
80-
query: _,
81-
},
82-
StyleSelector::Selector(_),
83-
) => Ordering::Greater,
84-
(
85-
StyleSelector::Selector(_),
86-
StyleSelector::Media {
87-
selector: _,
88-
query: _,
89-
},
90-
) => Ordering::Less,
109+
(StyleSelector::At { .. }, StyleSelector::Selector(_)) => Ordering::Greater,
110+
(StyleSelector::Selector(_), StyleSelector::At { .. }) => Ordering::Less,
91111
(StyleSelector::Global(a, _), StyleSelector::Global(b, _)) => {
92112
if a == b {
93113
return Ordering::Equal;
@@ -143,9 +163,10 @@ impl From<&str> for StyleSelector {
143163
} else if let Some(s) = value.strip_prefix("theme-") {
144164
// first character should lower case
145165
StyleSelector::Selector(format!(":root[data-theme={}] &", to_camel_case(s)))
146-
} else if value == "print" {
147-
StyleSelector::Media {
148-
query: "print".to_string(),
166+
} else if matches!(value.as_str(), "print" | "screen" | "speech" | "all") {
167+
StyleSelector::At {
168+
kind: AtRuleKind::Media,
169+
query: value.to_string(),
149170
selector: None,
150171
}
151172
} else {
@@ -201,11 +222,16 @@ impl Display for StyleSelector {
201222
"{}",
202223
match self {
203224
StyleSelector::Selector(value) => value.to_string(),
204-
StyleSelector::Media { query, selector } => {
225+
StyleSelector::At {
226+
kind,
227+
query,
228+
selector,
229+
} => {
230+
let space = if query.starts_with('(') { "" } else { " " };
205231
if let Some(selector) = selector {
206-
format!("@{query} {selector}")
232+
format!("@{kind}{space}{query} {selector}")
207233
} else {
208-
format!("@{query}")
234+
format!("@{kind}{space}{query}")
209235
}
210236
}
211237
StyleSelector::Global(value, _) => value.to_string(),
@@ -255,11 +281,33 @@ mod tests {
255281

256282
#[rstest]
257283
#[case(StyleSelector::Selector("&:hover".to_string()), "&:hover")]
258-
#[case(StyleSelector::Media {
284+
#[case(StyleSelector::At {
285+
kind: AtRuleKind::Media,
259286
query: "screen and (max-width: 600px)".to_string(),
260287
selector: None,
261288
},
262-
"@screen and (max-width: 600px)"
289+
"@media screen and (max-width: 600px)"
290+
)]
291+
#[case(StyleSelector::At {
292+
kind: AtRuleKind::Supports,
293+
query: "(display: grid)".to_string(),
294+
selector: None,
295+
},
296+
"@supports(display: grid)"
297+
)]
298+
#[case(StyleSelector::At {
299+
kind: AtRuleKind::Container,
300+
query: "(min-width: 768px)".to_string(),
301+
selector: None,
302+
},
303+
"@container(min-width: 768px)"
304+
)]
305+
#[case(StyleSelector::At {
306+
kind: AtRuleKind::Container,
307+
query: "sidebar (min-width: 400px)".to_string(),
308+
selector: None,
309+
},
310+
"@container sidebar (min-width: 400px)"
263311
)]
264312
#[case(StyleSelector::Global(":root[data-theme=dark]".to_string(), "file.rs".to_string()), ":root[data-theme=dark]")]
265313
fn test_style_selector_display(#[case] selector: StyleSelector, #[case] expected: &str) {
@@ -269,7 +317,8 @@ mod tests {
269317

270318
#[rstest]
271319
#[case(
272-
StyleSelector::Media {
320+
StyleSelector::At {
321+
kind: AtRuleKind::Media,
273322
query: "screen".to_string(),
274323
selector: None,
275324
},
@@ -282,16 +331,31 @@ mod tests {
282331
std::cmp::Ordering::Less
283332
)]
284333
#[case(
285-
StyleSelector::Media {
334+
StyleSelector::At {
335+
kind: AtRuleKind::Media,
286336
query: "a".to_string(),
287337
selector: None,
288338
},
289-
StyleSelector::Media {
339+
StyleSelector::At {
340+
kind: AtRuleKind::Media,
290341
query: "b".to_string(),
291342
selector: None,
292343
},
293344
std::cmp::Ordering::Less
294345
)]
346+
#[case(
347+
StyleSelector::At {
348+
kind: AtRuleKind::Media,
349+
query: "(min-width: 768px)".to_string(),
350+
selector: None,
351+
},
352+
StyleSelector::At {
353+
kind: AtRuleKind::Supports,
354+
query: "(display: grid)".to_string(),
355+
selector: None,
356+
},
357+
std::cmp::Ordering::Less
358+
)]
295359
#[case(
296360
StyleSelector::Global(":root[data-theme=dark]".to_string(), "file1.rs".to_string()),
297361
StyleSelector::Global(":root[data-theme=light]".to_string(), "file2.rs".to_string()),
@@ -304,7 +368,8 @@ mod tests {
304368
)]
305369
#[case(
306370
StyleSelector::Selector("&:hover".to_string()),
307-
StyleSelector::Media {
371+
StyleSelector::At {
372+
kind: AtRuleKind::Media,
308373
query: "screen".to_string(),
309374
selector: None,
310375
},

0 commit comments

Comments
 (0)