Skip to main content

fret_ui_kit/
styled.rs

1use crate::{ChromeRefinement, Space};
2
3pub trait RefineStyle: Sized {
4    fn refine_style(self, style: ChromeRefinement) -> Self;
5}
6
7pub trait Stylable: Sized {
8    fn apply_style(self, style: ChromeRefinement) -> Self;
9}
10
11impl<T: RefineStyle> Stylable for T {
12    fn apply_style(self, style: ChromeRefinement) -> Self {
13        RefineStyle::refine_style(self, style)
14    }
15}
16
17pub struct Styled<T> {
18    inner: T,
19    style: ChromeRefinement,
20}
21
22impl<T> Styled<T> {
23    pub fn new(inner: T) -> Self {
24        Self {
25            inner,
26            style: ChromeRefinement::default(),
27        }
28    }
29
30    pub fn refine_style(mut self, style: ChromeRefinement) -> Self {
31        self.style = self.style.merge(style);
32        self
33    }
34
35    pub fn px_1(mut self) -> Self {
36        self.style = self.style.px_1();
37        self
38    }
39
40    pub fn px_0p5(mut self) -> Self {
41        self.style = self.style.px_0p5();
42        self
43    }
44
45    pub fn px_0(mut self) -> Self {
46        self.style = self.style.px_0();
47        self
48    }
49
50    pub fn px_1p5(mut self) -> Self {
51        self.style = self.style.px_1p5();
52        self
53    }
54
55    pub fn px_2(mut self) -> Self {
56        self.style = self.style.px_2();
57        self
58    }
59
60    pub fn px_2p5(mut self) -> Self {
61        self.style = self.style.px_2p5();
62        self
63    }
64
65    pub fn px_3(mut self) -> Self {
66        self.style = self.style.px_3();
67        self
68    }
69
70    pub fn px_4(mut self) -> Self {
71        self.style = self.style.px_4();
72        self
73    }
74
75    pub fn py_1(mut self) -> Self {
76        self.style = self.style.py_1();
77        self
78    }
79
80    pub fn py_0p5(mut self) -> Self {
81        self.style = self.style.py_0p5();
82        self
83    }
84
85    pub fn py_0(mut self) -> Self {
86        self.style = self.style.py_0();
87        self
88    }
89
90    pub fn py_1p5(mut self) -> Self {
91        self.style = self.style.py_1p5();
92        self
93    }
94
95    pub fn py_2(mut self) -> Self {
96        self.style = self.style.py_2();
97        self
98    }
99
100    pub fn py_2p5(mut self) -> Self {
101        self.style = self.style.py_2p5();
102        self
103    }
104
105    pub fn py_3(mut self) -> Self {
106        self.style = self.style.py_3();
107        self
108    }
109
110    pub fn py_4(mut self) -> Self {
111        self.style = self.style.py_4();
112        self
113    }
114
115    pub fn pt(mut self, space: Space) -> Self {
116        self.style = self.style.pt(space);
117        self
118    }
119
120    pub fn pr(mut self, space: Space) -> Self {
121        self.style = self.style.pr(space);
122        self
123    }
124
125    pub fn pb(mut self, space: Space) -> Self {
126        self.style = self.style.pb(space);
127        self
128    }
129
130    pub fn pl(mut self, space: Space) -> Self {
131        self.style = self.style.pl(space);
132        self
133    }
134
135    pub fn p_1(mut self) -> Self {
136        self.style = self.style.p_1();
137        self
138    }
139
140    pub fn p_0(mut self) -> Self {
141        self.style = self.style.p_0();
142        self
143    }
144
145    pub fn p_0p5(mut self) -> Self {
146        self.style = self.style.p_0p5();
147        self
148    }
149
150    pub fn p_1p5(mut self) -> Self {
151        self.style = self.style.p_1p5();
152        self
153    }
154
155    pub fn p_2(mut self) -> Self {
156        self.style = self.style.p_2();
157        self
158    }
159
160    pub fn p_2p5(mut self) -> Self {
161        self.style = self.style.p_2p5();
162        self
163    }
164
165    pub fn p_3(mut self) -> Self {
166        self.style = self.style.p_3();
167        self
168    }
169
170    pub fn p_4(mut self) -> Self {
171        self.style = self.style.p_4();
172        self
173    }
174
175    pub fn rounded_md(mut self) -> Self {
176        self.style = self.style.rounded_md();
177        self
178    }
179
180    pub fn border_1(mut self) -> Self {
181        self.style = self.style.border_1();
182        self
183    }
184}
185
186impl<T: Stylable> Styled<T> {
187    pub fn finish(self) -> T {
188        self.inner.apply_style(self.style)
189    }
190}
191
192pub trait StyledExt: RefineStyle + Sized {
193    fn styled(self) -> Styled<Self> {
194        Styled::new(self)
195    }
196}
197
198impl<T: RefineStyle> StyledExt for T {}
199
200// Intentionally no blanket `RefineStyle` impls here: the public component surface is
201// declarative-only, and concrete types that support `RefineStyle` live in downstream crates.
202
203#[cfg(test)]
204mod tests {
205    use super::*;
206    use crate::{MetricRef, Space};
207
208    #[derive(Debug, Default, Clone)]
209    struct Dummy {
210        style: ChromeRefinement,
211    }
212
213    impl RefineStyle for Dummy {
214        fn refine_style(mut self, style: ChromeRefinement) -> Self {
215            self.style = style;
216            self
217        }
218    }
219
220    #[test]
221    fn styled_ext_builds_a_refinement_chain() {
222        let dummy = Dummy::default()
223            .styled()
224            .px_3()
225            .py_2()
226            .border_1()
227            .rounded_md()
228            .finish();
229
230        let padding = dummy.style.padding.expect("expected padding refinement");
231        match padding.left {
232            Some(MetricRef::Token { key, .. }) => assert_eq!(key, Space::N3.token_key()),
233            _ => panic!("expected left padding token"),
234        }
235        match padding.right {
236            Some(MetricRef::Token { key, .. }) => assert_eq!(key, Space::N3.token_key()),
237            _ => panic!("expected right padding token"),
238        }
239        match padding.top {
240            Some(MetricRef::Token { key, .. }) => assert_eq!(key, Space::N2.token_key()),
241            _ => panic!("expected top padding token"),
242        }
243        match padding.bottom {
244            Some(MetricRef::Token { key, .. }) => assert_eq!(key, Space::N2.token_key()),
245            _ => panic!("expected bottom padding token"),
246        }
247        assert!(dummy.style.border_width.is_some());
248        assert!(dummy.style.radius.is_some());
249    }
250}