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!(
37                f,
38                "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)"
39            ),
40            TextShadow::Default => write!(
41                f,
42                "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
43            ),
44            TextShadow::Lg => write!(
45                f,
46                "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)"
47            ),
48            TextShadow::Xl => write!(
49                f,
50                "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
51            ),
52            TextShadow::Xl2 => write!(f, "0 25px 50px -12px rgb(0 0 0 / 0.25)"),
53            TextShadow::Inner => write!(f, "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"),
54        }
55    }
56}
57
58impl TextShadow {
59    /// Get the CSS class name for this text shadow
60    pub fn to_class_name(&self) -> String {
61        match self {
62            TextShadow::None => "text-shadow-none".to_string(),
63            TextShadow::Sm => "text-shadow-sm".to_string(),
64            TextShadow::Md => "text-shadow-md".to_string(),
65            TextShadow::Default => "text-shadow".to_string(),
66            TextShadow::Lg => "text-shadow-lg".to_string(),
67            TextShadow::Xl => "text-shadow-xl".to_string(),
68            TextShadow::Xl2 => "text-shadow-2xl".to_string(),
69            TextShadow::Inner => "text-shadow-inner".to_string(),
70        }
71    }
72
73    /// Get the CSS value for this text shadow
74    pub fn to_css_value(&self) -> String {
75        self.to_string()
76    }
77}
78
79/// Trait for adding text shadow utilities to ClassBuilder
80pub trait TextShadowUtilities {
81    /// Set text shadow to none
82    fn text_shadow_none(self) -> Self;
83    /// Set text shadow to small
84    fn text_shadow_sm(self) -> Self;
85    /// Set text shadow to medium
86    fn text_shadow_md(self) -> Self;
87    /// Set text shadow to default
88    fn text_shadow(self) -> Self;
89    /// Set text shadow to large
90    fn text_shadow_lg(self) -> Self;
91    /// Set text shadow to extra large
92    fn text_shadow_xl(self) -> Self;
93    /// Set text shadow to 2XL
94    fn text_shadow_2xl(self) -> Self;
95    /// Set text shadow to inner
96    fn text_shadow_inner(self) -> Self;
97    /// Set text shadow with custom value
98    fn text_shadow_custom(self, shadow: TextShadow) -> Self;
99}
100
101impl TextShadowUtilities for ClassBuilder {
102    fn text_shadow_none(self) -> Self {
103        self.class("text-shadow-none")
104    }
105
106    fn text_shadow_sm(self) -> Self {
107        self.class("text-shadow-sm")
108    }
109
110    fn text_shadow_md(self) -> Self {
111        self.class("text-shadow-md")
112    }
113
114    fn text_shadow(self) -> Self {
115        self.class("text-shadow")
116    }
117
118    fn text_shadow_lg(self) -> Self {
119        self.class("text-shadow-lg")
120    }
121
122    fn text_shadow_xl(self) -> Self {
123        self.class("text-shadow-xl")
124    }
125
126    fn text_shadow_2xl(self) -> Self {
127        self.class("text-shadow-2xl")
128    }
129
130    fn text_shadow_inner(self) -> Self {
131        self.class("text-shadow-inner")
132    }
133
134    fn text_shadow_custom(self, shadow: TextShadow) -> Self {
135        self.class(shadow.to_class_name())
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142    use crate::classes::ClassBuilder;
143
144    #[test]
145    fn test_text_shadow_enum_values() {
146        assert_eq!(TextShadow::None.to_string(), "none");
147        assert_eq!(TextShadow::Sm.to_string(), "0 1px 2px 0 rgb(0 0 0 / 0.05)");
148        assert_eq!(
149            TextShadow::Default.to_string(),
150            "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
151        );
152        assert_eq!(
153            TextShadow::Lg.to_string(),
154            "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)"
155        );
156        assert_eq!(
157            TextShadow::Xl.to_string(),
158            "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
159        );
160        assert_eq!(
161            TextShadow::Xl2.to_string(),
162            "0 25px 50px -12px rgb(0 0 0 / 0.25)"
163        );
164        assert_eq!(
165            TextShadow::Inner.to_string(),
166            "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"
167        );
168    }
169
170    #[test]
171    fn test_text_shadow_class_names() {
172        assert_eq!(TextShadow::None.to_class_name(), "text-shadow-none");
173        assert_eq!(TextShadow::Sm.to_class_name(), "text-shadow-sm");
174        assert_eq!(TextShadow::Default.to_class_name(), "text-shadow");
175        assert_eq!(TextShadow::Lg.to_class_name(), "text-shadow-lg");
176        assert_eq!(TextShadow::Xl.to_class_name(), "text-shadow-xl");
177        assert_eq!(TextShadow::Xl2.to_class_name(), "text-shadow-2xl");
178        assert_eq!(TextShadow::Inner.to_class_name(), "text-shadow-inner");
179    }
180
181    #[test]
182    fn test_text_shadow_utilities() {
183        let classes = ClassBuilder::new()
184            .text_shadow_none()
185            .text_shadow_sm()
186            .text_shadow()
187            .text_shadow_lg()
188            .text_shadow_xl()
189            .text_shadow_2xl()
190            .text_shadow_inner();
191
192        let result = classes.build();
193        assert!(result.classes.contains("text-shadow-none"));
194        assert!(result.classes.contains("text-shadow-sm"));
195        assert!(result.classes.contains("text-shadow"));
196        assert!(result.classes.contains("text-shadow-lg"));
197        assert!(result.classes.contains("text-shadow-xl"));
198        assert!(result.classes.contains("text-shadow-2xl"));
199        assert!(result.classes.contains("text-shadow-inner"));
200    }
201
202    #[test]
203    fn test_text_shadow_css_values() {
204        assert_eq!(TextShadow::None.to_css_value(), "none");
205        assert_eq!(
206            TextShadow::Sm.to_css_value(),
207            "0 1px 2px 0 rgb(0 0 0 / 0.05)"
208        );
209        assert_eq!(
210            TextShadow::Default.to_css_value(),
211            "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"
212        );
213        assert_eq!(
214            TextShadow::Lg.to_css_value(),
215            "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)"
216        );
217        assert_eq!(
218            TextShadow::Xl.to_css_value(),
219            "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)"
220        );
221        assert_eq!(
222            TextShadow::Xl2.to_css_value(),
223            "0 25px 50px -12px rgb(0 0 0 / 0.25)"
224        );
225        assert_eq!(
226            TextShadow::Inner.to_css_value(),
227            "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"
228        );
229    }
230
231    #[test]
232    fn test_text_shadow_serialization() {
233        let shadow = TextShadow::Lg;
234        let serialized = serde_json::to_string(&shadow).unwrap();
235        let deserialized: TextShadow = serde_json::from_str(&serialized).unwrap();
236        assert_eq!(shadow, deserialized);
237    }
238
239    #[test]
240    fn test_text_shadow_comprehensive_usage() {
241        let classes = ClassBuilder::new().text_shadow_sm().text_shadow_lg();
242
243        let result = classes.build();
244        assert!(result.classes.contains("text-shadow-sm"));
245        assert!(result.classes.contains("text-shadow-lg"));
246    }
247
248    #[test]
249    fn test_text_shadow_custom_usage() {
250        let classes = ClassBuilder::new()
251            .text_shadow_custom(TextShadow::Xl)
252            .text_shadow_custom(TextShadow::Inner);
253
254        let result = classes.build();
255        assert!(result.classes.contains("text-shadow-xl"));
256        assert!(result.classes.contains("text-shadow-inner"));
257    }
258}