tailwind_rs_core/utilities/
mask.rs

1//! Mask utilities for tailwind-rs
2//!
3//! This module provides utilities for CSS mask properties.
4//! It includes all Tailwind CSS mask variants.
5
6use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// Mask type values
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum MaskType {
13    /// No mask
14    None,
15    /// Alpha mask
16    Alpha,
17    /// Luminance mask
18    Luminance,
19}
20
21impl fmt::Display for MaskType {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            MaskType::None => write!(f, "none"),
25            MaskType::Alpha => write!(f, "alpha"),
26            MaskType::Luminance => write!(f, "luminance"),
27        }
28    }
29}
30
31/// Mask mode values
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
33pub enum MaskMode {
34    /// Alpha mask mode
35    Alpha,
36    /// Luminance mask mode
37    Luminance,
38    /// Match source mask mode
39    MatchSource,
40}
41
42impl fmt::Display for MaskMode {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            MaskMode::Alpha => write!(f, "alpha"),
46            MaskMode::Luminance => write!(f, "luminance"),
47            MaskMode::MatchSource => write!(f, "match-source"),
48        }
49    }
50}
51
52/// Mask composite values
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54pub enum MaskComposite {
55    /// Add composite
56    Add,
57    /// Subtract composite
58    Subtract,
59    /// Intersect composite
60    Intersect,
61    /// Exclude composite
62    Exclude,
63}
64
65impl fmt::Display for MaskComposite {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        match self {
68            MaskComposite::Add => write!(f, "add"),
69            MaskComposite::Subtract => write!(f, "subtract"),
70            MaskComposite::Intersect => write!(f, "intersect"),
71            MaskComposite::Exclude => write!(f, "exclude"),
72        }
73    }
74}
75
76/// Mask repeat values
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
78pub enum MaskRepeat {
79    /// No repeat
80    NoRepeat,
81    /// Repeat
82    Repeat,
83    /// Repeat X
84    RepeatX,
85    /// Repeat Y
86    RepeatY,
87    /// Round repeat
88    Round,
89    /// Space repeat
90    Space,
91}
92
93impl fmt::Display for MaskRepeat {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            MaskRepeat::NoRepeat => write!(f, "no-repeat"),
97            MaskRepeat::Repeat => write!(f, "repeat"),
98            MaskRepeat::RepeatX => write!(f, "repeat-x"),
99            MaskRepeat::RepeatY => write!(f, "repeat-y"),
100            MaskRepeat::Round => write!(f, "round"),
101            MaskRepeat::Space => write!(f, "space"),
102        }
103    }
104}
105
106/// Mask size values
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
108pub enum MaskSize {
109    /// Auto size
110    Auto,
111    /// Cover size
112    Cover,
113    /// Contain size
114    Contain,
115}
116
117impl fmt::Display for MaskSize {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        match self {
120            MaskSize::Auto => write!(f, "auto"),
121            MaskSize::Cover => write!(f, "cover"),
122            MaskSize::Contain => write!(f, "contain"),
123        }
124    }
125}
126
127/// Mask position values
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
129pub enum MaskPosition {
130    /// Center position
131    Center,
132    /// Top position
133    Top,
134    /// Bottom position
135    Bottom,
136    /// Left position
137    Left,
138    /// Right position
139    Right,
140    /// Top left position
141    TopLeft,
142    /// Top right position
143    TopRight,
144    /// Bottom left position
145    BottomLeft,
146    /// Bottom right position
147    BottomRight,
148}
149
150impl fmt::Display for MaskPosition {
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        match self {
153            MaskPosition::Center => write!(f, "center"),
154            MaskPosition::Top => write!(f, "top"),
155            MaskPosition::Bottom => write!(f, "bottom"),
156            MaskPosition::Left => write!(f, "left"),
157            MaskPosition::Right => write!(f, "right"),
158            MaskPosition::TopLeft => write!(f, "top left"),
159            MaskPosition::TopRight => write!(f, "top right"),
160            MaskPosition::BottomLeft => write!(f, "bottom left"),
161            MaskPosition::BottomRight => write!(f, "bottom right"),
162        }
163    }
164}
165
166/// Mask clip values
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
168pub enum MaskClip {
169    /// Border box clip
170    BorderBox,
171    /// Padding box clip
172    PaddingBox,
173    /// Content box clip
174    ContentBox,
175    /// Text clip
176    Text,
177}
178
179impl fmt::Display for MaskClip {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        match self {
182            MaskClip::BorderBox => write!(f, "border-box"),
183            MaskClip::PaddingBox => write!(f, "padding-box"),
184            MaskClip::ContentBox => write!(f, "content-box"),
185            MaskClip::Text => write!(f, "text"),
186        }
187    }
188}
189
190/// Mask origin values
191#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
192pub enum MaskOrigin {
193    /// Border box origin
194    BorderBox,
195    /// Padding box origin
196    PaddingBox,
197    /// Content box origin
198    ContentBox,
199}
200
201impl fmt::Display for MaskOrigin {
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        match self {
204            MaskOrigin::BorderBox => write!(f, "border-box"),
205            MaskOrigin::PaddingBox => write!(f, "padding-box"),
206            MaskOrigin::ContentBox => write!(f, "content-box"),
207        }
208    }
209}
210
211/// Trait for adding mask utilities to ClassBuilder
212pub trait MaskUtilities {
213    /// Set mask to none
214    fn mask_none(self) -> Self;
215    /// Set mask to alpha
216    fn mask_alpha(self) -> Self;
217    /// Set mask to luminance
218    fn mask_luminance(self) -> Self;
219    /// Set mask repeat to none
220    fn mask_repeat_none(self) -> Self;
221    /// Set mask repeat to default
222    fn mask_repeat(self) -> Self;
223    /// Set mask repeat to X
224    fn mask_repeat_x(self) -> Self;
225    /// Set mask repeat to Y
226    fn mask_repeat_y(self) -> Self;
227    /// Set mask repeat to round
228    fn mask_repeat_round(self) -> Self;
229    /// Set mask repeat to space
230    fn mask_repeat_space(self) -> Self;
231    /// Set mask size to auto
232    fn mask_size_auto(self) -> Self;
233    /// Set mask size to cover
234    fn mask_size_cover(self) -> Self;
235    /// Set mask size to contain
236    fn mask_size_contain(self) -> Self;
237    /// Set mask position to center
238    fn mask_center(self) -> Self;
239    /// Set mask position to top
240    fn mask_top(self) -> Self;
241    /// Set mask position to bottom
242    fn mask_bottom(self) -> Self;
243    /// Set mask position to left
244    fn mask_left(self) -> Self;
245    /// Set mask position to right
246    fn mask_right(self) -> Self;
247    /// Set mask position to top left
248    fn mask_top_left(self) -> Self;
249    /// Set mask position to top right
250    fn mask_top_right(self) -> Self;
251    /// Set mask position to bottom left
252    fn mask_bottom_left(self) -> Self;
253    /// Set mask position to bottom right
254    fn mask_bottom_right(self) -> Self;
255    /// Set mask clip to border
256    fn mask_clip_border(self) -> Self;
257    /// Set mask clip to padding
258    fn mask_clip_padding(self) -> Self;
259    /// Set mask clip to content
260    fn mask_clip_content(self) -> Self;
261    /// Set mask clip to text
262    fn mask_clip_text(self) -> Self;
263    /// Set mask origin to border
264    fn mask_origin_border(self) -> Self;
265    /// Set mask origin to padding
266    fn mask_origin_padding(self) -> Self;
267    /// Set mask origin to content
268    fn mask_origin_content(self) -> Self;
269}
270
271impl MaskUtilities for ClassBuilder {
272    fn mask_none(self) -> Self {
273        self.class("mask-none")
274    }
275
276    fn mask_alpha(self) -> Self {
277        self.class("mask-alpha")
278    }
279
280    fn mask_luminance(self) -> Self {
281        self.class("mask-luminance")
282    }
283
284    fn mask_repeat_none(self) -> Self {
285        self.class("mask-repeat-none")
286    }
287
288    fn mask_repeat(self) -> Self {
289        self.class("mask-repeat")
290    }
291
292    fn mask_repeat_x(self) -> Self {
293        self.class("mask-repeat-x")
294    }
295
296    fn mask_repeat_y(self) -> Self {
297        self.class("mask-repeat-y")
298    }
299
300    fn mask_repeat_round(self) -> Self {
301        self.class("mask-repeat-round")
302    }
303
304    fn mask_repeat_space(self) -> Self {
305        self.class("mask-repeat-space")
306    }
307
308    fn mask_size_auto(self) -> Self {
309        self.class("mask-size-auto")
310    }
311
312    fn mask_size_cover(self) -> Self {
313        self.class("mask-size-cover")
314    }
315
316    fn mask_size_contain(self) -> Self {
317        self.class("mask-size-contain")
318    }
319
320    fn mask_center(self) -> Self {
321        self.class("mask-center")
322    }
323
324    fn mask_top(self) -> Self {
325        self.class("mask-top")
326    }
327
328    fn mask_bottom(self) -> Self {
329        self.class("mask-bottom")
330    }
331
332    fn mask_left(self) -> Self {
333        self.class("mask-left")
334    }
335
336    fn mask_right(self) -> Self {
337        self.class("mask-right")
338    }
339
340    fn mask_top_left(self) -> Self {
341        self.class("mask-top-left")
342    }
343
344    fn mask_top_right(self) -> Self {
345        self.class("mask-top-right")
346    }
347
348    fn mask_bottom_left(self) -> Self {
349        self.class("mask-bottom-left")
350    }
351
352    fn mask_bottom_right(self) -> Self {
353        self.class("mask-bottom-right")
354    }
355
356    fn mask_clip_border(self) -> Self {
357        self.class("mask-clip-border")
358    }
359
360    fn mask_clip_padding(self) -> Self {
361        self.class("mask-clip-padding")
362    }
363
364    fn mask_clip_content(self) -> Self {
365        self.class("mask-clip-content")
366    }
367
368    fn mask_clip_text(self) -> Self {
369        self.class("mask-clip-text")
370    }
371
372    fn mask_origin_border(self) -> Self {
373        self.class("mask-origin-border")
374    }
375
376    fn mask_origin_padding(self) -> Self {
377        self.class("mask-origin-padding")
378    }
379
380    fn mask_origin_content(self) -> Self {
381        self.class("mask-origin-content")
382    }
383}
384
385#[cfg(test)]
386mod tests {
387    use super::*;
388    use crate::classes::ClassBuilder;
389
390    #[test]
391    fn test_mask_type_enum_values() {
392        assert_eq!(MaskType::None.to_string(), "none");
393        assert_eq!(MaskType::Alpha.to_string(), "alpha");
394        assert_eq!(MaskType::Luminance.to_string(), "luminance");
395    }
396
397    #[test]
398    fn test_mask_mode_enum_values() {
399        assert_eq!(MaskMode::Alpha.to_string(), "alpha");
400        assert_eq!(MaskMode::Luminance.to_string(), "luminance");
401        assert_eq!(MaskMode::MatchSource.to_string(), "match-source");
402    }
403
404    #[test]
405    fn test_mask_composite_enum_values() {
406        assert_eq!(MaskComposite::Add.to_string(), "add");
407        assert_eq!(MaskComposite::Subtract.to_string(), "subtract");
408        assert_eq!(MaskComposite::Intersect.to_string(), "intersect");
409        assert_eq!(MaskComposite::Exclude.to_string(), "exclude");
410    }
411
412    #[test]
413    fn test_mask_repeat_enum_values() {
414        assert_eq!(MaskRepeat::NoRepeat.to_string(), "no-repeat");
415        assert_eq!(MaskRepeat::Repeat.to_string(), "repeat");
416        assert_eq!(MaskRepeat::RepeatX.to_string(), "repeat-x");
417        assert_eq!(MaskRepeat::RepeatY.to_string(), "repeat-y");
418        assert_eq!(MaskRepeat::Round.to_string(), "round");
419        assert_eq!(MaskRepeat::Space.to_string(), "space");
420    }
421
422    #[test]
423    fn test_mask_size_enum_values() {
424        assert_eq!(MaskSize::Auto.to_string(), "auto");
425        assert_eq!(MaskSize::Cover.to_string(), "cover");
426        assert_eq!(MaskSize::Contain.to_string(), "contain");
427    }
428
429    #[test]
430    fn test_mask_position_enum_values() {
431        assert_eq!(MaskPosition::Center.to_string(), "center");
432        assert_eq!(MaskPosition::Top.to_string(), "top");
433        assert_eq!(MaskPosition::Bottom.to_string(), "bottom");
434        assert_eq!(MaskPosition::Left.to_string(), "left");
435        assert_eq!(MaskPosition::Right.to_string(), "right");
436        assert_eq!(MaskPosition::TopLeft.to_string(), "top left");
437        assert_eq!(MaskPosition::TopRight.to_string(), "top right");
438        assert_eq!(MaskPosition::BottomLeft.to_string(), "bottom left");
439        assert_eq!(MaskPosition::BottomRight.to_string(), "bottom right");
440    }
441
442    #[test]
443    fn test_mask_clip_enum_values() {
444        assert_eq!(MaskClip::BorderBox.to_string(), "border-box");
445        assert_eq!(MaskClip::PaddingBox.to_string(), "padding-box");
446        assert_eq!(MaskClip::ContentBox.to_string(), "content-box");
447        assert_eq!(MaskClip::Text.to_string(), "text");
448    }
449
450    #[test]
451    fn test_mask_origin_enum_values() {
452        assert_eq!(MaskOrigin::BorderBox.to_string(), "border-box");
453        assert_eq!(MaskOrigin::PaddingBox.to_string(), "padding-box");
454        assert_eq!(MaskOrigin::ContentBox.to_string(), "content-box");
455    }
456
457    #[test]
458    fn test_mask_utilities() {
459        let classes = ClassBuilder::new()
460            .mask_alpha()
461            .mask_repeat_round()
462            .mask_size_cover()
463            .mask_center()
464            .mask_clip_border()
465            .mask_origin_padding();
466
467        let result = classes.build();
468        assert!(result.classes.contains("mask-alpha"));
469        assert!(result.classes.contains("mask-repeat-round"));
470        assert!(result.classes.contains("mask-size-cover"));
471        assert!(result.classes.contains("mask-center"));
472        assert!(result.classes.contains("mask-clip-border"));
473        assert!(result.classes.contains("mask-origin-padding"));
474    }
475
476    #[test]
477    fn test_mask_serialization() {
478        let mask_type = MaskType::Alpha;
479        let serialized = serde_json::to_string(&mask_type).unwrap();
480        let deserialized: MaskType = serde_json::from_str(&serialized).unwrap();
481        assert_eq!(mask_type, deserialized);
482    }
483
484    #[test]
485    fn test_mask_comprehensive_usage() {
486        let classes = ClassBuilder::new()
487            .mask_luminance()
488            .mask_repeat_round()
489            .mask_size_contain()
490            .mask_top_left();
491
492        let result = classes.build();
493        assert!(result.classes.contains("mask-luminance"));
494        assert!(result.classes.contains("mask-repeat-round"));
495        assert!(result.classes.contains("mask-size-contain"));
496        assert!(result.classes.contains("mask-top-left"));
497    }
498}