tailwind_rs_core/utilities/
text_shadow.rs

1//! Text shadow utilities for tailwind-rs
2//!
3//! This module provides utilities for text-shadow CSS property.
4//! It includes all Tailwind CSS text-shadow variants.
5
6use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// Text shadow values
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum TextShadow {
13    /// No text shadow
14    None,
15    /// Small text shadow (0 1px 2px 0 rgb(0 0 0 / 0.05))
16    Sm,
17    /// Medium text shadow (0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1))
18    Md,
19    /// Default text shadow (0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1))
20    Default,
21    /// Large text shadow (0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1))
22    Lg,
23    /// Extra large text shadow (0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1))
24    Xl,
25    /// 2XL text shadow (0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1))
26    Xl2,
27    /// Inner text shadow (inset 0 2px 4px 0 rgb(0 0 0 / 0.05))
28    Inner,
29}
30
31impl fmt::Display for TextShadow {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        match self {
34            TextShadow::None => write!(f, "none"),
35            TextShadow::Sm => write!(f, "0 1px 2px 0 rgb(0 0 0 / 0.05)"),
36            TextShadow::Md => write!(f, "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)"),
37            TextShadow::Default => write!(f, "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"),
38            TextShadow::Lg => write!(f, "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)"),
39            TextShadow::Xl => write!(f, "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"),
40            TextShadow::Xl2 => write!(f, "0 25px 50px -12px rgb(0 0 0 / 0.25)"),
41            TextShadow::Inner => write!(f, "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"),
42        }
43    }
44}
45
46impl TextShadow {
47    /// Get the CSS class name for this text shadow
48    pub fn to_class_name(&self) -> String {
49        match self {
50            TextShadow::None => "text-shadow-none".to_string(),
51            TextShadow::Sm => "text-shadow-sm".to_string(),
52            TextShadow::Md => "text-shadow-md".to_string(),
53            TextShadow::Default => "text-shadow".to_string(),
54            TextShadow::Lg => "text-shadow-lg".to_string(),
55            TextShadow::Xl => "text-shadow-xl".to_string(),
56            TextShadow::Xl2 => "text-shadow-2xl".to_string(),
57            TextShadow::Inner => "text-shadow-inner".to_string(),
58        }
59    }
60
61    /// Get the CSS value for this text shadow
62    pub fn to_css_value(&self) -> String {
63        self.to_string()
64    }
65}
66
67/// Trait for adding text shadow utilities to ClassBuilder
68pub trait TextShadowUtilities {
69    /// Set text shadow to none
70    fn text_shadow_none(self) -> Self;
71    /// Set text shadow to small
72    fn text_shadow_sm(self) -> Self;
73    /// Set text shadow to medium
74    fn text_shadow_md(self) -> Self;
75    /// Set text shadow to default
76    fn text_shadow(self) -> Self;
77    /// Set text shadow to large
78    fn text_shadow_lg(self) -> Self;
79    /// Set text shadow to extra large
80    fn text_shadow_xl(self) -> Self;
81    /// Set text shadow to 2XL
82    fn text_shadow_2xl(self) -> Self;
83    /// Set text shadow to inner
84    fn text_shadow_inner(self) -> Self;
85    /// Set text shadow with custom value
86    fn text_shadow_custom(self, shadow: TextShadow) -> Self;
87}
88
89impl TextShadowUtilities for ClassBuilder {
90    fn text_shadow_none(self) -> Self {
91        self.class("text-shadow-none")
92    }
93
94    fn text_shadow_sm(self) -> Self {
95        self.class("text-shadow-sm")
96    }
97
98    fn text_shadow_md(self) -> Self {
99        self.class("text-shadow-md")
100    }
101
102    fn text_shadow(self) -> Self {
103        self.class("text-shadow")
104    }
105
106    fn text_shadow_lg(self) -> Self {
107        self.class("text-shadow-lg")
108    }
109
110    fn text_shadow_xl(self) -> Self {
111        self.class("text-shadow-xl")
112    }
113
114    fn text_shadow_2xl(self) -> Self {
115        self.class("text-shadow-2xl")
116    }
117
118    fn text_shadow_inner(self) -> Self {
119        self.class("text-shadow-inner")
120    }
121
122    fn text_shadow_custom(self, shadow: TextShadow) -> Self {
123        self.class(&shadow.to_class_name())
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    use crate::classes::ClassBuilder;
131
132    #[test]
133    fn test_text_shadow_enum_values() {
134        assert_eq!(TextShadow::None.to_string(), "none");
135        assert_eq!(TextShadow::Sm.to_string(), "0 1px 2px 0 rgb(0 0 0 / 0.05)");
136        assert_eq!(TextShadow::Default.to_string(), "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)");
137        assert_eq!(TextShadow::Lg.to_string(), "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)");
138        assert_eq!(TextShadow::Xl.to_string(), "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)");
139        assert_eq!(TextShadow::Xl2.to_string(), "0 25px 50px -12px rgb(0 0 0 / 0.25)");
140        assert_eq!(TextShadow::Inner.to_string(), "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)");
141    }
142
143    #[test]
144    fn test_text_shadow_class_names() {
145        assert_eq!(TextShadow::None.to_class_name(), "text-shadow-none");
146        assert_eq!(TextShadow::Sm.to_class_name(), "text-shadow-sm");
147        assert_eq!(TextShadow::Default.to_class_name(), "text-shadow");
148        assert_eq!(TextShadow::Lg.to_class_name(), "text-shadow-lg");
149        assert_eq!(TextShadow::Xl.to_class_name(), "text-shadow-xl");
150        assert_eq!(TextShadow::Xl2.to_class_name(), "text-shadow-2xl");
151        assert_eq!(TextShadow::Inner.to_class_name(), "text-shadow-inner");
152    }
153
154    #[test]
155    fn test_text_shadow_utilities() {
156        let classes = ClassBuilder::new()
157            .text_shadow_none()
158            .text_shadow_sm()
159            .text_shadow()
160            .text_shadow_lg()
161            .text_shadow_xl()
162            .text_shadow_2xl()
163            .text_shadow_inner();
164
165        let result = classes.build();
166        assert!(result.classes.contains("text-shadow-none"));
167        assert!(result.classes.contains("text-shadow-sm"));
168        assert!(result.classes.contains("text-shadow"));
169        assert!(result.classes.contains("text-shadow-lg"));
170        assert!(result.classes.contains("text-shadow-xl"));
171        assert!(result.classes.contains("text-shadow-2xl"));
172        assert!(result.classes.contains("text-shadow-inner"));
173    }
174
175    #[test]
176    fn test_text_shadow_css_values() {
177        assert_eq!(TextShadow::None.to_css_value(), "none");
178        assert_eq!(TextShadow::Sm.to_css_value(), "0 1px 2px 0 rgb(0 0 0 / 0.05)");
179        assert_eq!(TextShadow::Default.to_css_value(), "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)");
180        assert_eq!(TextShadow::Lg.to_css_value(), "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)");
181        assert_eq!(TextShadow::Xl.to_css_value(), "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)");
182        assert_eq!(TextShadow::Xl2.to_css_value(), "0 25px 50px -12px rgb(0 0 0 / 0.25)");
183        assert_eq!(TextShadow::Inner.to_css_value(), "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)");
184    }
185
186    #[test]
187    fn test_text_shadow_serialization() {
188        let shadow = TextShadow::Lg;
189        let serialized = serde_json::to_string(&shadow).unwrap();
190        let deserialized: TextShadow = serde_json::from_str(&serialized).unwrap();
191        assert_eq!(shadow, deserialized);
192    }
193
194    #[test]
195    fn test_text_shadow_comprehensive_usage() {
196        let classes = ClassBuilder::new()
197            .text_shadow_sm()
198            .text_shadow_lg();
199
200        let result = classes.build();
201        assert!(result.classes.contains("text-shadow-sm"));
202        assert!(result.classes.contains("text-shadow-lg"));
203    }
204
205    #[test]
206    fn test_text_shadow_custom_usage() {
207        let classes = ClassBuilder::new()
208            .text_shadow_custom(TextShadow::Xl)
209            .text_shadow_custom(TextShadow::Inner);
210
211        let result = classes.build();
212        assert!(result.classes.contains("text-shadow-xl"));
213        assert!(result.classes.contains("text-shadow-inner"));
214    }
215}