rustyle_css/
composition.rs1use std::collections::HashMap;
6
7pub struct StyleComposition;
9
10impl StyleComposition {
11 pub fn merge(css_strings: &[&str]) -> String {
13 css_strings.join(" ")
14 }
15
16 pub fn apply(base: &str, overrides: &str) -> String {
18 format!("{} {}", base, overrides)
20 }
21
22 pub fn inherit(parent: &str, child: &str) -> String {
24 format!("{} {}", parent, child)
25 }
26
27 pub fn merge_with_resolution(css_strings: &[&str]) -> String {
29 let mut properties: HashMap<String, String> = HashMap::new();
31
32 for css in css_strings {
33 for part in css.split(';') {
35 let part = part.trim();
36 if let Some((prop, val)) = part.split_once(':') {
37 properties.insert(prop.trim().to_string(), val.trim().to_string());
38 }
39 }
40 }
41
42 properties
44 .iter()
45 .map(|(prop, val)| format!("{}: {}", prop, val))
46 .collect::<Vec<_>>()
47 .join("; ")
48 }
49}
50
51#[derive(Clone, Debug)]
53pub struct StyleMixin {
54 pub name: String,
55 pub css: String,
56 pub parameters: Vec<String>,
57}
58
59impl StyleMixin {
60 pub fn new(name: &str, css: &str) -> Self {
62 Self {
63 name: name.to_string(),
64 css: css.to_string(),
65 parameters: Vec::new(),
66 }
67 }
68
69 pub fn parameterized(name: &str, css_template: &str, parameters: Vec<&str>) -> Self {
71 Self {
72 name: name.to_string(),
73 css: css_template.to_string(),
74 parameters: parameters.iter().map(|s| s.to_string()).collect(),
75 }
76 }
77
78 pub fn apply_with_params(&self, params: &HashMap<&str, &str>) -> String {
80 let mut result = self.css.clone();
81
82 for (key, value) in params {
84 let placeholder = format!("${}", key);
85 result = result.replace(&placeholder, value);
86 }
87
88 result
89 }
90
91 pub fn apply(&self) -> &str {
93 &self.css
94 }
95
96 pub fn parameters(&self) -> &[String] {
98 &self.parameters
99 }
100}
101
102pub struct MixinRegistry {
104 mixins: HashMap<String, StyleMixin>,
105}
106
107impl MixinRegistry {
108 pub fn new() -> Self {
110 Self {
111 mixins: HashMap::new(),
112 }
113 }
114
115 pub fn register(&mut self, mixin: StyleMixin) {
117 self.mixins.insert(mixin.name.clone(), mixin);
118 }
119
120 pub fn get(&self, name: &str) -> Option<&StyleMixin> {
122 self.mixins.get(name)
123 }
124
125 pub fn apply(&self, name: &str, params: &HashMap<&str, &str>) -> Option<String> {
127 self.mixins.get(name).map(|mixin| {
128 if mixin.parameters.is_empty() {
129 mixin.css.clone()
130 } else {
131 mixin.apply_with_params(params)
132 }
133 })
134 }
135
136 pub fn compose(&self, mixin_names: &[&str], params: &HashMap<&str, &str>) -> String {
138 let mut result = Vec::new();
139
140 for name in mixin_names {
141 if let Some(css) = self.apply(name, params) {
142 result.push(css);
143 }
144 }
145
146 result.join(" ")
147 }
148
149 pub fn has(&self, name: &str) -> bool {
151 self.mixins.contains_key(name)
152 }
153
154 pub fn names(&self) -> Vec<String> {
156 self.mixins.keys().cloned().collect()
157 }
158}
159
160impl Default for MixinRegistry {
161 fn default() -> Self {
162 Self::new()
163 }
164}