dioxus_tw_components/attributes/
mod.rs

1use dioxus::dioxus_core::{Attribute, AttributeValue, Element};
2use std::str::FromStr;
3use tailwind_fuse::tw_merge;
4
5pub trait UiComp: HasChildren + BuildClass + std::fmt::Display {}
6
7// This trait is used for the docsite
8pub trait HasChildren {
9    fn has_children(&self) -> bool {
10        false
11    }
12
13    fn set_children(&mut self, _children: Element) {}
14}
15
16pub trait Class {
17    fn base(&self) -> &'static str {
18        ""
19    }
20
21    fn color(&self) -> Option<&'static str> {
22        None
23    }
24
25    fn size(&self) -> Option<&'static str> {
26        None
27    }
28
29    fn variant(&self) -> Option<&'static str> {
30        None
31    }
32
33    fn animation(&self) -> Option<&'static str> {
34        None
35    }
36
37    fn orientation(&self) -> Option<&'static str> {
38        None
39    }
40
41    fn side(&self) -> Option<&'static str> {
42        None
43    }
44}
45
46pub trait BuildClass: Class {
47    fn build_class(&self) -> String {
48        let mut class = String::from(self.base());
49
50        if let Some(color) = self.color() {
51            class.push(' ');
52            class.push_str(color);
53        }
54
55        if let Some(size) = self.size() {
56            class.push(' ');
57            class.push_str(size);
58        }
59
60        if let Some(variant) = self.variant() {
61            class.push(' ');
62            class.push_str(variant);
63        }
64
65        if let Some(animation) = self.animation() {
66            class.push(' ');
67            class.push_str(animation);
68        }
69
70        if let Some(orientation) = self.orientation() {
71            class.push(' ');
72            class.push_str(orientation);
73        }
74
75        if let Some(side) = self.side() {
76            class.push(' ');
77            class.push_str(side);
78        }
79
80        tw_merge!(class)
81    }
82
83    fn update_class_attribute(&mut self) {
84        let class = self.build_class();
85
86        // If the component have a vec attributes
87        if let Some(vec_attributes) = self.get_attributes() {
88            // Find the class attribute in the vec and modify it
89            if let Some(class_attribute) =
90                vec_attributes.iter_mut().find(|attr| attr.name == "class")
91            {
92                if let AttributeValue::Text(ref mut value) = class_attribute.value {
93                    *value = tw_merge!(class, value.clone());
94                }
95            } else {
96                // Else push the class attribute in the vec
97                vec_attributes.push(Attribute::new("class", class, None, true));
98            }
99        }
100    }
101
102    fn get_attributes(&mut self) -> Option<&mut Vec<Attribute>> {
103        None
104    }
105
106    // All those methods below are used for the docsite
107    fn has_color(&self) -> bool {
108        self.color().is_some()
109    }
110
111    fn set_color(&mut self, _color: Color) {}
112
113    fn has_size(&self) -> bool {
114        self.size().is_some()
115    }
116
117    fn set_size(&mut self, _size: Size) {}
118
119    fn has_animation(&self) -> bool {
120        self.animation().is_some()
121    }
122
123    fn set_animation(&mut self, _animation: Animation) {}
124
125    fn has_orientation(&self) -> bool {
126        self.orientation().is_some()
127    }
128
129    fn set_orientation(&mut self, _orientation: Orientation) {}
130
131    fn has_side(&self) -> bool {
132        self.side().is_some()
133    }
134
135    fn set_side(&mut self, _side: Side) {}
136}
137
138#[derive(Default, Debug, Clone, Copy, PartialEq)]
139pub enum Color {
140    #[default]
141    Default,
142    Primary,
143    Secondary,
144    Destructive,
145    Success,
146    Accent,
147    Muted,
148}
149
150impl FromStr for Color {
151    type Err = &'static str;
152
153    fn from_str(s: &str) -> Result<Self, Self::Err> {
154        match s.to_lowercase().as_str() {
155            "primary" => Ok(Color::Primary),
156            "secondary" => Ok(Color::Secondary),
157            "destructive" => Ok(Color::Destructive),
158            "success" => Ok(Color::Success),
159            "accent" => Ok(Color::Accent),
160            "muted" => Ok(Color::Muted),
161            _ => Ok(Color::default()),
162        }
163    }
164}
165
166impl std::fmt::Display for Color {
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        let s = match self {
169            Color::Default => "Default",
170            Color::Primary => "Primary",
171            Color::Secondary => "Secondary",
172            Color::Destructive => "Destructive",
173            Color::Success => "Success",
174            Color::Accent => "Accent",
175            Color::Muted => "Muted",
176        };
177        f.write_str(s)
178    }
179}
180
181#[derive(Default, Clone, Copy, PartialEq)]
182pub enum Size {
183    Xs,
184    Sm,
185    #[default]
186    Md,
187    Lg,
188    Xl,
189}
190
191impl FromStr for Size {
192    type Err = &'static str;
193
194    fn from_str(s: &str) -> Result<Self, Self::Err> {
195        match s.to_lowercase().as_str() {
196            "xs" => Ok(Size::Xs),
197            "sm" => Ok(Size::Sm),
198            "md" => Ok(Size::Md),
199            "lg" => Ok(Size::Lg),
200            "xl" => Ok(Size::Xl),
201            _ => Ok(Size::default()),
202        }
203    }
204}
205
206impl std::fmt::Display for Size {
207    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208        let s = match self {
209            Size::Xs => "Xs",
210            Size::Sm => "Sm",
211            Size::Md => "Md",
212            Size::Lg => "Lg",
213            Size::Xl => "Xl",
214        };
215        f.write_str(s)
216    }
217}
218
219#[derive(Default, Clone, Copy, PartialEq)]
220pub enum Orientation {
221    #[default]
222    Horizontal,
223    Vertical,
224}
225
226impl FromStr for Orientation {
227    type Err = &'static str;
228
229    fn from_str(s: &str) -> Result<Self, Self::Err> {
230        match s.to_lowercase().as_str() {
231            "horizontal" => Ok(Orientation::Horizontal),
232            _ => Ok(Orientation::Vertical),
233        }
234    }
235}
236
237impl std::fmt::Display for Orientation {
238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239        let s = match self {
240            Orientation::Vertical => "vertical",
241            Orientation::Horizontal => "horizontal",
242        };
243        f.write_str(s)
244    }
245}
246
247#[derive(Default, Debug, Clone, Copy, PartialEq)]
248pub enum Animation {
249    None,
250    Light,
251    #[default]
252    Full,
253}
254
255impl FromStr for Animation {
256    type Err = &'static str;
257
258    fn from_str(s: &str) -> Result<Self, Self::Err> {
259        match s.to_lowercase().as_str() {
260            "none" => Ok(Animation::None),
261            "light" => Ok(Animation::Light),
262            _ => Ok(Animation::Full),
263        }
264    }
265}
266
267impl std::fmt::Display for Animation {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        let s = match self {
270            Animation::None => "None",
271            Animation::Light => "Light",
272            Animation::Full => "Full",
273        };
274        f.write_str(s)
275    }
276}
277
278#[derive(Default, Clone, Copy, PartialEq)]
279pub enum Side {
280    Top,
281    Bottom,
282    Left,
283    #[default]
284    Right,
285}
286
287impl FromStr for Side {
288    type Err = &'static str;
289
290    fn from_str(s: &str) -> Result<Self, Self::Err> {
291        match s.to_lowercase().as_str() {
292            "top" => Ok(Side::Top),
293            "bottom" => Ok(Side::Bottom),
294            "left" => Ok(Side::Left),
295            _ => Ok(Side::Right),
296        }
297    }
298}
299
300impl std::fmt::Display for Side {
301    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
302        let s = match self {
303            Side::Top => "Top",
304            Side::Bottom => "Bottom",
305            Side::Left => "Left",
306            Side::Right => "Right",
307        };
308        f.write_str(s)
309    }
310}