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