rustyle_css/css/
selectors.rs

1//! Advanced CSS selector utilities
2//!
3//! Provides type-safe builders for modern CSS selectors including :has(), :is(), :where(), and @scope.
4
5/// :has() selector builder
6#[derive(Clone, Debug)]
7pub struct HasSelector {
8    selector: String,
9}
10
11impl HasSelector {
12    /// Create a new :has() selector
13    pub fn new(selector: &str) -> Self {
14        Self {
15            selector: selector.to_string(),
16        }
17    }
18
19    /// Convert to CSS string
20    pub fn to_css(&self) -> String {
21        format!(":has({})", self.selector)
22    }
23}
24
25/// :is() selector builder
26#[derive(Clone, Debug)]
27pub struct IsSelector {
28    selectors: Vec<String>,
29}
30
31impl IsSelector {
32    /// Create a new :is() selector
33    pub fn new(selectors: Vec<&str>) -> Self {
34        Self {
35            selectors: selectors.iter().map(|s| s.to_string()).collect(),
36        }
37    }
38
39    /// Add a selector
40    pub fn add(mut self, selector: &str) -> Self {
41        self.selectors.push(selector.to_string());
42        self
43    }
44
45    /// Convert to CSS string
46    pub fn to_css(&self) -> String {
47        format!(":is({})", self.selectors.join(", "))
48    }
49}
50
51/// :where() selector builder
52#[derive(Clone, Debug)]
53pub struct WhereSelector {
54    selectors: Vec<String>,
55}
56
57impl WhereSelector {
58    /// Create a new :where() selector
59    pub fn new(selectors: Vec<&str>) -> Self {
60        Self {
61            selectors: selectors.iter().map(|s| s.to_string()).collect(),
62        }
63    }
64
65    /// Add a selector
66    pub fn add(mut self, selector: &str) -> Self {
67        self.selectors.push(selector.to_string());
68        self
69    }
70
71    /// Convert to CSS string
72    pub fn to_css(&self) -> String {
73        format!(":where({})", self.selectors.join(", "))
74    }
75}
76
77/// @scope rule builder
78#[derive(Clone, Debug)]
79pub struct ScopeRule {
80    root: Option<String>,
81    limit: Option<String>,
82    rules: Vec<String>,
83}
84
85impl ScopeRule {
86    /// Create a new @scope rule
87    pub fn new() -> Self {
88        Self {
89            root: None,
90            limit: None,
91            rules: Vec::new(),
92        }
93    }
94
95    /// Set root selector
96    pub fn root(mut self, root: &str) -> Self {
97        self.root = Some(root.to_string());
98        self
99    }
100
101    /// Set limit selector
102    pub fn limit(mut self, limit: &str) -> Self {
103        self.limit = Some(limit.to_string());
104        self
105    }
106
107    /// Add a rule
108    pub fn rule(mut self, rule: &str) -> Self {
109        self.rules.push(rule.to_string());
110        self
111    }
112
113    /// Convert to CSS string
114    pub fn to_css(&self) -> String {
115        let mut css = String::from("@scope");
116
117        if let Some(ref root) = self.root {
118            css.push_str(&format!(" ({})", root));
119        }
120
121        if let Some(ref limit) = self.limit {
122            css.push_str(&format!(" to ({})", limit));
123        }
124
125        css.push_str(" {\n");
126
127        for rule in &self.rules {
128            css.push_str(rule);
129            css.push_str("\n");
130        }
131
132        css.push_str("}\n");
133        css
134    }
135}
136
137impl Default for ScopeRule {
138    fn default() -> Self {
139        Self::new()
140    }
141}
142
143/// @starting-style rule builder
144#[derive(Clone, Debug)]
145pub struct StartingStyle {
146    rules: Vec<String>,
147}
148
149impl StartingStyle {
150    /// Create a new @starting-style rule
151    pub fn new() -> Self {
152        Self { rules: Vec::new() }
153    }
154
155    /// Add a rule
156    pub fn rule(mut self, rule: &str) -> Self {
157        self.rules.push(rule.to_string());
158        self
159    }
160
161    /// Convert to CSS string
162    pub fn to_css(&self) -> String {
163        let mut css = String::from("@starting-style {\n");
164
165        for rule in &self.rules {
166            css.push_str(rule);
167            css.push_str("\n");
168        }
169
170        css.push_str("}\n");
171        css
172    }
173}
174
175impl Default for StartingStyle {
176    fn default() -> Self {
177        Self::new()
178    }
179}