tailwind_rs_core/utilities/
effects.rs

1//! Effects utilities for tailwind-rs
2//!
3//! This module provides utilities for box shadow, drop shadow, opacity, mix blend mode,
4//! background blend mode, and other visual effects.
5
6use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// Box shadow values
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum BoxShadow {
13    /// No shadow
14    None,
15    /// Small shadow
16    Sm,
17    /// Default shadow
18    Default,
19    /// Medium shadow
20    Md,
21    /// Large shadow
22    Lg,
23    /// Extra large shadow
24    Xl,
25    /// 2x large shadow
26    Xl2,
27    /// Inner shadow
28    Inner,
29}
30
31/// Drop shadow values
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
33pub enum DropShadow {
34    /// No shadow
35    None,
36    /// Small shadow
37    Sm,
38    /// Default shadow
39    Default,
40    /// Medium shadow
41    Md,
42    /// Large shadow
43    Lg,
44    /// Extra large shadow
45    Xl,
46    /// 2x large shadow
47    Xl2,
48    /// 3x large shadow
49    Xl3,
50}
51
52/// Opacity values
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54pub enum Opacity {
55    /// 0% opacity
56    Zero,
57    /// 5% opacity
58    Five,
59    /// 10% opacity
60    Ten,
61    /// 20% opacity
62    Twenty,
63    /// 25% opacity
64    TwentyFive,
65    /// 30% opacity
66    Thirty,
67    /// 40% opacity
68    Forty,
69    /// 50% opacity
70    Fifty,
71    /// 60% opacity
72    Sixty,
73    /// 70% opacity
74    Seventy,
75    /// 75% opacity
76    SeventyFive,
77    /// 80% opacity
78    Eighty,
79    /// 90% opacity
80    Ninety,
81    /// 95% opacity
82    NinetyFive,
83    /// 100% opacity
84    Hundred,
85}
86
87/// Mix blend mode values
88#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
89pub enum MixBlendMode {
90    /// Normal blend
91    Normal,
92    /// Multiply blend
93    Multiply,
94    /// Screen blend
95    Screen,
96    /// Overlay blend
97    Overlay,
98    /// Darken blend
99    Darken,
100    /// Lighten blend
101    Lighten,
102    /// Color dodge blend
103    ColorDodge,
104    /// Color burn blend
105    ColorBurn,
106    /// Hard light blend
107    HardLight,
108    /// Soft light blend
109    SoftLight,
110    /// Difference blend
111    Difference,
112    /// Exclusion blend
113    Exclusion,
114    /// Hue blend
115    Hue,
116    /// Saturation blend
117    Saturation,
118    /// Color blend
119    Color,
120    /// Luminosity blend
121    Luminosity,
122}
123
124/// Background blend mode values
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
126pub enum BackgroundBlendMode {
127    /// Normal blend
128    Normal,
129    /// Multiply blend
130    Multiply,
131    /// Screen blend
132    Screen,
133    /// Overlay blend
134    Overlay,
135    /// Darken blend
136    Darken,
137    /// Lighten blend
138    Lighten,
139    /// Color dodge blend
140    ColorDodge,
141    /// Color burn blend
142    ColorBurn,
143    /// Hard light blend
144    HardLight,
145    /// Soft light blend
146    SoftLight,
147    /// Difference blend
148    Difference,
149    /// Exclusion blend
150    Exclusion,
151    /// Hue blend
152    Hue,
153    /// Saturation blend
154    Saturation,
155    /// Color blend
156    Color,
157    /// Luminosity blend
158    Luminosity,
159}
160
161/// Backdrop filter blur values
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
163pub enum BackdropBlur {
164    /// No backdrop blur
165    None,
166    /// backdrop-blur-sm (4px)
167    Sm,
168    /// backdrop-blur (8px)
169    Default,
170    /// backdrop-blur-md (12px)
171    Md,
172    /// backdrop-blur-lg (16px)
173    Lg,
174    /// backdrop-blur-xl (24px)
175    Xl,
176    /// backdrop-blur-2xl (40px)
177    Xl2,
178    /// backdrop-blur-3xl (64px)
179    Xl3,
180}
181
182/// Backdrop filter brightness values
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
184pub enum BackdropBrightness {
185    /// backdrop-brightness-0 (0)
186    Zero,
187    /// backdrop-brightness-50 (0.5)
188    Fifty,
189    /// backdrop-brightness-75 (0.75)
190    SeventyFive,
191    /// backdrop-brightness-90 (0.9)
192    Ninety,
193    /// backdrop-brightness-95 (0.95)
194    NinetyFive,
195    /// backdrop-brightness-100 (1)
196    OneHundred,
197    /// backdrop-brightness-105 (1.05)
198    OneOhFive,
199    /// backdrop-brightness-110 (1.1)
200    OneOneZero,
201    /// backdrop-brightness-125 (1.25)
202    OneTwoFive,
203    /// backdrop-brightness-150 (1.5)
204    OneFifty,
205    /// backdrop-brightness-200 (2)
206    TwoHundred,
207}
208
209/// Backdrop filter contrast values
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
211pub enum BackdropContrast {
212    /// backdrop-contrast-0 (0)
213    Zero,
214    /// backdrop-contrast-50 (0.5)
215    Fifty,
216    /// backdrop-contrast-75 (0.75)
217    SeventyFive,
218    /// backdrop-contrast-100 (1)
219    OneHundred,
220    /// backdrop-contrast-125 (1.25)
221    OneTwoFive,
222    /// backdrop-contrast-150 (1.5)
223    OneFifty,
224    /// backdrop-contrast-200 (2)
225    TwoHundred,
226}
227
228/// Backdrop filter grayscale values
229#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
230pub enum BackdropGrayscale {
231    /// backdrop-grayscale-0 (0)
232    Zero,
233    /// backdrop-grayscale (1)
234    Default,
235}
236
237/// Backdrop filter hue rotate values
238#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
239pub enum BackdropHueRotate {
240    /// backdrop-hue-rotate-0 (0deg)
241    Zero,
242    /// backdrop-hue-rotate-15 (15deg)
243    Fifteen,
244    /// backdrop-hue-rotate-30 (30deg)
245    Thirty,
246    /// backdrop-hue-rotate-60 (60deg)
247    Sixty,
248    /// backdrop-hue-rotate-90 (90deg)
249    Ninety,
250    /// backdrop-hue-rotate-180 (180deg)
251    OneEighty,
252}
253
254/// Backdrop filter invert values
255#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
256pub enum BackdropInvert {
257    /// backdrop-invert-0 (0)
258    Zero,
259    /// backdrop-invert (1)
260    Default,
261}
262
263/// Backdrop filter opacity values
264#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
265pub enum BackdropOpacity {
266    /// backdrop-opacity-0 (0)
267    Zero,
268    /// backdrop-opacity-5 (0.05)
269    Five,
270    /// backdrop-opacity-10 (0.1)
271    Ten,
272    /// backdrop-opacity-20 (0.2)
273    Twenty,
274    /// backdrop-opacity-25 (0.25)
275    TwentyFive,
276    /// backdrop-opacity-30 (0.3)
277    Thirty,
278    /// backdrop-opacity-40 (0.4)
279    Forty,
280    /// backdrop-opacity-50 (0.5)
281    Fifty,
282    /// backdrop-opacity-60 (0.6)
283    Sixty,
284    /// backdrop-opacity-70 (0.7)
285    Seventy,
286    /// backdrop-opacity-75 (0.75)
287    SeventyFive,
288    /// backdrop-opacity-80 (0.8)
289    Eighty,
290    /// backdrop-opacity-90 (0.9)
291    Ninety,
292    /// backdrop-opacity-95 (0.95)
293    NinetyFive,
294    /// backdrop-opacity-100 (1)
295    OneHundred,
296}
297
298/// Backdrop filter saturate values
299#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
300pub enum BackdropSaturate {
301    /// backdrop-saturate-0 (0)
302    Zero,
303    /// backdrop-saturate-50 (0.5)
304    Fifty,
305    /// backdrop-saturate-100 (1)
306    OneHundred,
307    /// backdrop-saturate-150 (1.5)
308    OneFifty,
309    /// backdrop-saturate-200 (2)
310    TwoHundred,
311}
312
313/// Backdrop filter sepia values
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
315pub enum BackdropSepia {
316    /// backdrop-sepia-0 (0)
317    Zero,
318    /// backdrop-sepia (1)
319    Default,
320}
321
322impl BoxShadow {
323    pub fn to_class_name(&self) -> String {
324        match self {
325            BoxShadow::None => "none".to_string(),
326            BoxShadow::Sm => "sm".to_string(),
327            BoxShadow::Default => "default".to_string(),
328            BoxShadow::Md => "md".to_string(),
329            BoxShadow::Lg => "lg".to_string(),
330            BoxShadow::Xl => "xl".to_string(),
331            BoxShadow::Xl2 => "2xl".to_string(),
332            BoxShadow::Inner => "inner".to_string(),
333        }
334    }
335    
336    pub fn to_css_value(&self) -> String {
337        match self {
338            BoxShadow::None => "none".to_string(),
339            BoxShadow::Sm => "0 1px 2px 0 rgb(0 0 0 / 0.05)".to_string(),
340            BoxShadow::Default => "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)".to_string(),
341            BoxShadow::Md => "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)".to_string(),
342            BoxShadow::Lg => "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)".to_string(),
343            BoxShadow::Xl => "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)".to_string(),
344            BoxShadow::Xl2 => "0 25px 50px -12px rgb(0 0 0 / 0.25)".to_string(),
345            BoxShadow::Inner => "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)".to_string(),
346        }
347    }
348}
349
350impl DropShadow {
351    pub fn to_class_name(&self) -> String {
352        match self {
353            DropShadow::None => "none".to_string(),
354            DropShadow::Sm => "sm".to_string(),
355            DropShadow::Default => "default".to_string(),
356            DropShadow::Md => "md".to_string(),
357            DropShadow::Lg => "lg".to_string(),
358            DropShadow::Xl => "xl".to_string(),
359            DropShadow::Xl2 => "2xl".to_string(),
360            DropShadow::Xl3 => "3xl".to_string(),
361        }
362    }
363    
364    pub fn to_css_value(&self) -> String {
365        match self {
366            DropShadow::None => "none".to_string(),
367            DropShadow::Sm => "0 1px 2px rgb(0 0 0 / 0.05)".to_string(),
368            DropShadow::Default => "0 1px 3px rgb(0 0 0 / 0.1), 0 1px 2px rgb(0 0 0 / 0.06)".to_string(),
369            DropShadow::Md => "0 4px 6px rgb(0 0 0 / 0.07), 0 2px 4px rgb(0 0 0 / 0.06)".to_string(),
370            DropShadow::Lg => "0 10px 15px rgb(0 0 0 / 0.1), 0 4px 6px rgb(0 0 0 / 0.05)".to_string(),
371            DropShadow::Xl => "0 20px 25px rgb(0 0 0 / 0.1), 0 8px 10px rgb(0 0 0 / 0.04)".to_string(),
372            DropShadow::Xl2 => "0 25px 50px rgb(0 0 0 / 0.25)".to_string(),
373            DropShadow::Xl3 => "0 35px 60px rgb(0 0 0 / 0.3)".to_string(),
374        }
375    }
376}
377
378impl Opacity {
379    pub fn to_class_name(&self) -> String {
380        match self {
381            Opacity::Zero => "0".to_string(),
382            Opacity::Five => "5".to_string(),
383            Opacity::Ten => "10".to_string(),
384            Opacity::Twenty => "20".to_string(),
385            Opacity::TwentyFive => "25".to_string(),
386            Opacity::Thirty => "30".to_string(),
387            Opacity::Forty => "40".to_string(),
388            Opacity::Fifty => "50".to_string(),
389            Opacity::Sixty => "60".to_string(),
390            Opacity::Seventy => "70".to_string(),
391            Opacity::SeventyFive => "75".to_string(),
392            Opacity::Eighty => "80".to_string(),
393            Opacity::Ninety => "90".to_string(),
394            Opacity::NinetyFive => "95".to_string(),
395            Opacity::Hundred => "100".to_string(),
396        }
397    }
398    
399    pub fn to_css_value(&self) -> String {
400        match self {
401            Opacity::Zero => "0".to_string(),
402            Opacity::Five => "0.05".to_string(),
403            Opacity::Ten => "0.1".to_string(),
404            Opacity::Twenty => "0.2".to_string(),
405            Opacity::TwentyFive => "0.25".to_string(),
406            Opacity::Thirty => "0.3".to_string(),
407            Opacity::Forty => "0.4".to_string(),
408            Opacity::Fifty => "0.5".to_string(),
409            Opacity::Sixty => "0.6".to_string(),
410            Opacity::Seventy => "0.7".to_string(),
411            Opacity::SeventyFive => "0.75".to_string(),
412            Opacity::Eighty => "0.8".to_string(),
413            Opacity::Ninety => "0.9".to_string(),
414            Opacity::NinetyFive => "0.95".to_string(),
415            Opacity::Hundred => "1".to_string(),
416        }
417    }
418}
419
420impl MixBlendMode {
421    pub fn to_class_name(&self) -> String {
422        match self {
423            MixBlendMode::Normal => "normal".to_string(),
424            MixBlendMode::Multiply => "multiply".to_string(),
425            MixBlendMode::Screen => "screen".to_string(),
426            MixBlendMode::Overlay => "overlay".to_string(),
427            MixBlendMode::Darken => "darken".to_string(),
428            MixBlendMode::Lighten => "lighten".to_string(),
429            MixBlendMode::ColorDodge => "color-dodge".to_string(),
430            MixBlendMode::ColorBurn => "color-burn".to_string(),
431            MixBlendMode::HardLight => "hard-light".to_string(),
432            MixBlendMode::SoftLight => "soft-light".to_string(),
433            MixBlendMode::Difference => "difference".to_string(),
434            MixBlendMode::Exclusion => "exclusion".to_string(),
435            MixBlendMode::Hue => "hue".to_string(),
436            MixBlendMode::Saturation => "saturation".to_string(),
437            MixBlendMode::Color => "color".to_string(),
438            MixBlendMode::Luminosity => "luminosity".to_string(),
439        }
440    }
441    
442    pub fn to_css_value(&self) -> String {
443        match self {
444            MixBlendMode::Normal => "normal".to_string(),
445            MixBlendMode::Multiply => "multiply".to_string(),
446            MixBlendMode::Screen => "screen".to_string(),
447            MixBlendMode::Overlay => "overlay".to_string(),
448            MixBlendMode::Darken => "darken".to_string(),
449            MixBlendMode::Lighten => "lighten".to_string(),
450            MixBlendMode::ColorDodge => "color-dodge".to_string(),
451            MixBlendMode::ColorBurn => "color-burn".to_string(),
452            MixBlendMode::HardLight => "hard-light".to_string(),
453            MixBlendMode::SoftLight => "soft-light".to_string(),
454            MixBlendMode::Difference => "difference".to_string(),
455            MixBlendMode::Exclusion => "exclusion".to_string(),
456            MixBlendMode::Hue => "hue".to_string(),
457            MixBlendMode::Saturation => "saturation".to_string(),
458            MixBlendMode::Color => "color".to_string(),
459            MixBlendMode::Luminosity => "luminosity".to_string(),
460        }
461    }
462}
463
464impl BackgroundBlendMode {
465    pub fn to_class_name(&self) -> String {
466        match self {
467            BackgroundBlendMode::Normal => "normal".to_string(),
468            BackgroundBlendMode::Multiply => "multiply".to_string(),
469            BackgroundBlendMode::Screen => "screen".to_string(),
470            BackgroundBlendMode::Overlay => "overlay".to_string(),
471            BackgroundBlendMode::Darken => "darken".to_string(),
472            BackgroundBlendMode::Lighten => "lighten".to_string(),
473            BackgroundBlendMode::ColorDodge => "color-dodge".to_string(),
474            BackgroundBlendMode::ColorBurn => "color-burn".to_string(),
475            BackgroundBlendMode::HardLight => "hard-light".to_string(),
476            BackgroundBlendMode::SoftLight => "soft-light".to_string(),
477            BackgroundBlendMode::Difference => "difference".to_string(),
478            BackgroundBlendMode::Exclusion => "exclusion".to_string(),
479            BackgroundBlendMode::Hue => "hue".to_string(),
480            BackgroundBlendMode::Saturation => "saturation".to_string(),
481            BackgroundBlendMode::Color => "color".to_string(),
482            BackgroundBlendMode::Luminosity => "luminosity".to_string(),
483        }
484    }
485    
486    pub fn to_css_value(&self) -> String {
487        match self {
488            BackgroundBlendMode::Normal => "normal".to_string(),
489            BackgroundBlendMode::Multiply => "multiply".to_string(),
490            BackgroundBlendMode::Screen => "screen".to_string(),
491            BackgroundBlendMode::Overlay => "overlay".to_string(),
492            BackgroundBlendMode::Darken => "darken".to_string(),
493            BackgroundBlendMode::Lighten => "lighten".to_string(),
494            BackgroundBlendMode::ColorDodge => "color-dodge".to_string(),
495            BackgroundBlendMode::ColorBurn => "color-burn".to_string(),
496            BackgroundBlendMode::HardLight => "hard-light".to_string(),
497            BackgroundBlendMode::SoftLight => "soft-light".to_string(),
498            BackgroundBlendMode::Difference => "difference".to_string(),
499            BackgroundBlendMode::Exclusion => "exclusion".to_string(),
500            BackgroundBlendMode::Hue => "hue".to_string(),
501            BackgroundBlendMode::Saturation => "saturation".to_string(),
502            BackgroundBlendMode::Color => "color".to_string(),
503            BackgroundBlendMode::Luminosity => "luminosity".to_string(),
504        }
505    }
506}
507
508impl BackdropBlur {
509    pub fn to_class_name(&self) -> String {
510        match self {
511            BackdropBlur::None => "backdrop-blur-none".to_string(),
512            BackdropBlur::Sm => "backdrop-blur-sm".to_string(),
513            BackdropBlur::Default => "backdrop-blur".to_string(),
514            BackdropBlur::Md => "backdrop-blur-md".to_string(),
515            BackdropBlur::Lg => "backdrop-blur-lg".to_string(),
516            BackdropBlur::Xl => "backdrop-blur-xl".to_string(),
517            BackdropBlur::Xl2 => "backdrop-blur-2xl".to_string(),
518            BackdropBlur::Xl3 => "backdrop-blur-3xl".to_string(),
519        }
520    }
521
522    pub fn to_css_value(&self) -> String {
523        match self {
524            BackdropBlur::None => "blur(0px)".to_string(),
525            BackdropBlur::Sm => "blur(4px)".to_string(),
526            BackdropBlur::Default => "blur(8px)".to_string(),
527            BackdropBlur::Md => "blur(12px)".to_string(),
528            BackdropBlur::Lg => "blur(16px)".to_string(),
529            BackdropBlur::Xl => "blur(24px)".to_string(),
530            BackdropBlur::Xl2 => "blur(40px)".to_string(),
531            BackdropBlur::Xl3 => "blur(64px)".to_string(),
532        }
533    }
534}
535
536impl BackdropBrightness {
537    pub fn to_class_name(&self) -> String {
538        match self {
539            BackdropBrightness::Zero => "backdrop-brightness-0".to_string(),
540            BackdropBrightness::Fifty => "backdrop-brightness-50".to_string(),
541            BackdropBrightness::SeventyFive => "backdrop-brightness-75".to_string(),
542            BackdropBrightness::Ninety => "backdrop-brightness-90".to_string(),
543            BackdropBrightness::NinetyFive => "backdrop-brightness-95".to_string(),
544            BackdropBrightness::OneHundred => "backdrop-brightness-100".to_string(),
545            BackdropBrightness::OneOhFive => "backdrop-brightness-105".to_string(),
546            BackdropBrightness::OneOneZero => "backdrop-brightness-110".to_string(),
547            BackdropBrightness::OneTwoFive => "backdrop-brightness-125".to_string(),
548            BackdropBrightness::OneFifty => "backdrop-brightness-150".to_string(),
549            BackdropBrightness::TwoHundred => "backdrop-brightness-200".to_string(),
550        }
551    }
552
553    pub fn to_css_value(&self) -> String {
554        match self {
555            BackdropBrightness::Zero => "brightness(0)".to_string(),
556            BackdropBrightness::Fifty => "brightness(0.5)".to_string(),
557            BackdropBrightness::SeventyFive => "brightness(0.75)".to_string(),
558            BackdropBrightness::Ninety => "brightness(0.9)".to_string(),
559            BackdropBrightness::NinetyFive => "brightness(0.95)".to_string(),
560            BackdropBrightness::OneHundred => "brightness(1)".to_string(),
561            BackdropBrightness::OneOhFive => "brightness(1.05)".to_string(),
562            BackdropBrightness::OneOneZero => "brightness(1.1)".to_string(),
563            BackdropBrightness::OneTwoFive => "brightness(1.25)".to_string(),
564            BackdropBrightness::OneFifty => "brightness(1.5)".to_string(),
565            BackdropBrightness::TwoHundred => "brightness(2)".to_string(),
566        }
567    }
568}
569
570impl BackdropContrast {
571    pub fn to_class_name(&self) -> String {
572        match self {
573            BackdropContrast::Zero => "backdrop-contrast-0".to_string(),
574            BackdropContrast::Fifty => "backdrop-contrast-50".to_string(),
575            BackdropContrast::SeventyFive => "backdrop-contrast-75".to_string(),
576            BackdropContrast::OneHundred => "backdrop-contrast-100".to_string(),
577            BackdropContrast::OneTwoFive => "backdrop-contrast-125".to_string(),
578            BackdropContrast::OneFifty => "backdrop-contrast-150".to_string(),
579            BackdropContrast::TwoHundred => "backdrop-contrast-200".to_string(),
580        }
581    }
582
583    pub fn to_css_value(&self) -> String {
584        match self {
585            BackdropContrast::Zero => "contrast(0)".to_string(),
586            BackdropContrast::Fifty => "contrast(0.5)".to_string(),
587            BackdropContrast::SeventyFive => "contrast(0.75)".to_string(),
588            BackdropContrast::OneHundred => "contrast(1)".to_string(),
589            BackdropContrast::OneTwoFive => "contrast(1.25)".to_string(),
590            BackdropContrast::OneFifty => "contrast(1.5)".to_string(),
591            BackdropContrast::TwoHundred => "contrast(2)".to_string(),
592        }
593    }
594}
595
596impl BackdropGrayscale {
597    pub fn to_class_name(&self) -> String {
598        match self {
599            BackdropGrayscale::Zero => "backdrop-grayscale-0".to_string(),
600            BackdropGrayscale::Default => "backdrop-grayscale".to_string(),
601        }
602    }
603
604    pub fn to_css_value(&self) -> String {
605        match self {
606            BackdropGrayscale::Zero => "grayscale(0)".to_string(),
607            BackdropGrayscale::Default => "grayscale(1)".to_string(),
608        }
609    }
610}
611
612impl BackdropHueRotate {
613    pub fn to_class_name(&self) -> String {
614        match self {
615            BackdropHueRotate::Zero => "backdrop-hue-rotate-0".to_string(),
616            BackdropHueRotate::Fifteen => "backdrop-hue-rotate-15".to_string(),
617            BackdropHueRotate::Thirty => "backdrop-hue-rotate-30".to_string(),
618            BackdropHueRotate::Sixty => "backdrop-hue-rotate-60".to_string(),
619            BackdropHueRotate::Ninety => "backdrop-hue-rotate-90".to_string(),
620            BackdropHueRotate::OneEighty => "backdrop-hue-rotate-180".to_string(),
621        }
622    }
623
624    pub fn to_css_value(&self) -> String {
625        match self {
626            BackdropHueRotate::Zero => "hue-rotate(0deg)".to_string(),
627            BackdropHueRotate::Fifteen => "hue-rotate(15deg)".to_string(),
628            BackdropHueRotate::Thirty => "hue-rotate(30deg)".to_string(),
629            BackdropHueRotate::Sixty => "hue-rotate(60deg)".to_string(),
630            BackdropHueRotate::Ninety => "hue-rotate(90deg)".to_string(),
631            BackdropHueRotate::OneEighty => "hue-rotate(180deg)".to_string(),
632        }
633    }
634}
635
636impl BackdropInvert {
637    pub fn to_class_name(&self) -> String {
638        match self {
639            BackdropInvert::Zero => "backdrop-invert-0".to_string(),
640            BackdropInvert::Default => "backdrop-invert".to_string(),
641        }
642    }
643
644    pub fn to_css_value(&self) -> String {
645        match self {
646            BackdropInvert::Zero => "invert(0)".to_string(),
647            BackdropInvert::Default => "invert(1)".to_string(),
648        }
649    }
650}
651
652impl BackdropOpacity {
653    pub fn to_class_name(&self) -> String {
654        match self {
655            BackdropOpacity::Zero => "backdrop-opacity-0".to_string(),
656            BackdropOpacity::Five => "backdrop-opacity-5".to_string(),
657            BackdropOpacity::Ten => "backdrop-opacity-10".to_string(),
658            BackdropOpacity::Twenty => "backdrop-opacity-20".to_string(),
659            BackdropOpacity::TwentyFive => "backdrop-opacity-25".to_string(),
660            BackdropOpacity::Thirty => "backdrop-opacity-30".to_string(),
661            BackdropOpacity::Forty => "backdrop-opacity-40".to_string(),
662            BackdropOpacity::Fifty => "backdrop-opacity-50".to_string(),
663            BackdropOpacity::Sixty => "backdrop-opacity-60".to_string(),
664            BackdropOpacity::Seventy => "backdrop-opacity-70".to_string(),
665            BackdropOpacity::SeventyFive => "backdrop-opacity-75".to_string(),
666            BackdropOpacity::Eighty => "backdrop-opacity-80".to_string(),
667            BackdropOpacity::Ninety => "backdrop-opacity-90".to_string(),
668            BackdropOpacity::NinetyFive => "backdrop-opacity-95".to_string(),
669            BackdropOpacity::OneHundred => "backdrop-opacity-100".to_string(),
670        }
671    }
672
673    pub fn to_css_value(&self) -> String {
674        match self {
675            BackdropOpacity::Zero => "opacity(0)".to_string(),
676            BackdropOpacity::Five => "opacity(0.05)".to_string(),
677            BackdropOpacity::Ten => "opacity(0.1)".to_string(),
678            BackdropOpacity::Twenty => "opacity(0.2)".to_string(),
679            BackdropOpacity::TwentyFive => "opacity(0.25)".to_string(),
680            BackdropOpacity::Thirty => "opacity(0.3)".to_string(),
681            BackdropOpacity::Forty => "opacity(0.4)".to_string(),
682            BackdropOpacity::Fifty => "opacity(0.5)".to_string(),
683            BackdropOpacity::Sixty => "opacity(0.6)".to_string(),
684            BackdropOpacity::Seventy => "opacity(0.7)".to_string(),
685            BackdropOpacity::SeventyFive => "opacity(0.75)".to_string(),
686            BackdropOpacity::Eighty => "opacity(0.8)".to_string(),
687            BackdropOpacity::Ninety => "opacity(0.9)".to_string(),
688            BackdropOpacity::NinetyFive => "opacity(0.95)".to_string(),
689            BackdropOpacity::OneHundred => "opacity(1)".to_string(),
690        }
691    }
692}
693
694impl BackdropSaturate {
695    pub fn to_class_name(&self) -> String {
696        match self {
697            BackdropSaturate::Zero => "backdrop-saturate-0".to_string(),
698            BackdropSaturate::Fifty => "backdrop-saturate-50".to_string(),
699            BackdropSaturate::OneHundred => "backdrop-saturate-100".to_string(),
700            BackdropSaturate::OneFifty => "backdrop-saturate-150".to_string(),
701            BackdropSaturate::TwoHundred => "backdrop-saturate-200".to_string(),
702        }
703    }
704
705    pub fn to_css_value(&self) -> String {
706        match self {
707            BackdropSaturate::Zero => "saturate(0)".to_string(),
708            BackdropSaturate::Fifty => "saturate(0.5)".to_string(),
709            BackdropSaturate::OneHundred => "saturate(1)".to_string(),
710            BackdropSaturate::OneFifty => "saturate(1.5)".to_string(),
711            BackdropSaturate::TwoHundred => "saturate(2)".to_string(),
712        }
713    }
714}
715
716impl BackdropSepia {
717    pub fn to_class_name(&self) -> String {
718        match self {
719            BackdropSepia::Zero => "backdrop-sepia-0".to_string(),
720            BackdropSepia::Default => "backdrop-sepia".to_string(),
721        }
722    }
723
724    pub fn to_css_value(&self) -> String {
725        match self {
726            BackdropSepia::Zero => "sepia(0)".to_string(),
727            BackdropSepia::Default => "sepia(1)".to_string(),
728        }
729    }
730}
731
732impl fmt::Display for BoxShadow {
733    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734        write!(f, "{}", self.to_class_name())
735    }
736}
737
738impl fmt::Display for DropShadow {
739    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
740        write!(f, "{}", self.to_class_name())
741    }
742}
743
744impl fmt::Display for Opacity {
745    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
746        write!(f, "{}", self.to_class_name())
747    }
748}
749
750impl fmt::Display for MixBlendMode {
751    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
752        write!(f, "{}", self.to_class_name())
753    }
754}
755
756impl fmt::Display for BackgroundBlendMode {
757    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
758        write!(f, "{}", self.to_class_name())
759    }
760}
761
762impl fmt::Display for BackdropBlur {
763    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
764        write!(f, "{}", self.to_class_name())
765    }
766}
767
768impl fmt::Display for BackdropBrightness {
769    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770        write!(f, "{}", self.to_class_name())
771    }
772}
773
774impl fmt::Display for BackdropContrast {
775    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776        write!(f, "{}", self.to_class_name())
777    }
778}
779
780impl fmt::Display for BackdropGrayscale {
781    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
782        write!(f, "{}", self.to_class_name())
783    }
784}
785
786impl fmt::Display for BackdropHueRotate {
787    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
788        write!(f, "{}", self.to_class_name())
789    }
790}
791
792impl fmt::Display for BackdropInvert {
793    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
794        write!(f, "{}", self.to_class_name())
795    }
796}
797
798impl fmt::Display for BackdropOpacity {
799    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
800        write!(f, "{}", self.to_class_name())
801    }
802}
803
804impl fmt::Display for BackdropSaturate {
805    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
806        write!(f, "{}", self.to_class_name())
807    }
808}
809
810impl fmt::Display for BackdropSepia {
811    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
812        write!(f, "{}", self.to_class_name())
813    }
814}
815
816/// Trait for adding box shadow utilities to a class builder
817pub trait BoxShadowUtilities {
818    fn box_shadow(self, shadow: BoxShadow) -> Self;
819}
820
821impl BoxShadowUtilities for ClassBuilder {
822    fn box_shadow(self, shadow: BoxShadow) -> Self {
823        self.class(format!("shadow-{}", shadow.to_class_name()))
824    }
825}
826
827/// Trait for adding drop shadow utilities to a class builder
828pub trait DropShadowUtilities {
829    fn drop_shadow(self, shadow: DropShadow) -> Self;
830}
831
832impl DropShadowUtilities for ClassBuilder {
833    fn drop_shadow(self, shadow: DropShadow) -> Self {
834        self.class(format!("drop-shadow-{}", shadow.to_class_name()))
835    }
836}
837
838/// Trait for adding opacity utilities to a class builder
839pub trait OpacityUtilities {
840    fn opacity(self, opacity: Opacity) -> Self;
841}
842
843impl OpacityUtilities for ClassBuilder {
844    fn opacity(self, opacity: Opacity) -> Self {
845        self.class(format!("opacity-{}", opacity.to_class_name()))
846    }
847}
848
849/// Trait for adding mix blend mode utilities to a class builder
850pub trait MixBlendModeUtilities {
851    fn mix_blend_mode(self, mode: MixBlendMode) -> Self;
852}
853
854impl MixBlendModeUtilities for ClassBuilder {
855    fn mix_blend_mode(self, mode: MixBlendMode) -> Self {
856        self.class(format!("mix-blend-{}", mode.to_class_name()))
857    }
858}
859
860/// Trait for adding background blend mode utilities to a class builder
861pub trait BackgroundBlendModeUtilities {
862    fn background_blend_mode(self, mode: BackgroundBlendMode) -> Self;
863}
864
865impl BackgroundBlendModeUtilities for ClassBuilder {
866    fn background_blend_mode(self, mode: BackgroundBlendMode) -> Self {
867        self.class(format!("bg-blend-{}", mode.to_class_name()))
868    }
869}
870
871#[cfg(test)]
872mod tests {
873    use super::*;
874    
875    #[test]
876    fn test_box_shadow_utilities() {
877        let classes = ClassBuilder::new()
878            .box_shadow(BoxShadow::None)
879            .box_shadow(BoxShadow::Sm)
880            .box_shadow(BoxShadow::Default)
881            .box_shadow(BoxShadow::Md)
882            .box_shadow(BoxShadow::Lg)
883            .box_shadow(BoxShadow::Xl)
884            .box_shadow(BoxShadow::Xl2)
885            .box_shadow(BoxShadow::Inner)
886            .build();
887        
888        let css_classes = classes.to_css_classes();
889        assert!(css_classes.contains("shadow-none"));
890        assert!(css_classes.contains("shadow-sm"));
891        assert!(css_classes.contains("shadow-default"));
892        assert!(css_classes.contains("shadow-md"));
893        assert!(css_classes.contains("shadow-lg"));
894        assert!(css_classes.contains("shadow-xl"));
895        assert!(css_classes.contains("shadow-2xl"));
896        assert!(css_classes.contains("shadow-inner"));
897    }
898    
899    #[test]
900    fn test_drop_shadow_utilities() {
901        let classes = ClassBuilder::new()
902            .drop_shadow(DropShadow::None)
903            .drop_shadow(DropShadow::Sm)
904            .drop_shadow(DropShadow::Default)
905            .drop_shadow(DropShadow::Md)
906            .drop_shadow(DropShadow::Lg)
907            .drop_shadow(DropShadow::Xl)
908            .drop_shadow(DropShadow::Xl2)
909            .drop_shadow(DropShadow::Xl3)
910            .build();
911        
912        let css_classes = classes.to_css_classes();
913        assert!(css_classes.contains("drop-shadow-none"));
914        assert!(css_classes.contains("drop-shadow-sm"));
915        assert!(css_classes.contains("drop-shadow-default"));
916        assert!(css_classes.contains("drop-shadow-md"));
917        assert!(css_classes.contains("drop-shadow-lg"));
918        assert!(css_classes.contains("drop-shadow-xl"));
919        assert!(css_classes.contains("drop-shadow-2xl"));
920        assert!(css_classes.contains("drop-shadow-3xl"));
921    }
922    
923    #[test]
924    fn test_opacity_utilities() {
925        let classes = ClassBuilder::new()
926            .opacity(Opacity::Zero)
927            .opacity(Opacity::TwentyFive)
928            .opacity(Opacity::Fifty)
929            .opacity(Opacity::SeventyFive)
930            .opacity(Opacity::Hundred)
931            .build();
932        
933        let css_classes = classes.to_css_classes();
934        assert!(css_classes.contains("opacity-0"));
935        assert!(css_classes.contains("opacity-25"));
936        assert!(css_classes.contains("opacity-50"));
937        assert!(css_classes.contains("opacity-75"));
938        assert!(css_classes.contains("opacity-100"));
939    }
940    
941    #[test]
942    fn test_mix_blend_mode_utilities() {
943        let classes = ClassBuilder::new()
944            .mix_blend_mode(MixBlendMode::Normal)
945            .mix_blend_mode(MixBlendMode::Multiply)
946            .mix_blend_mode(MixBlendMode::Screen)
947            .mix_blend_mode(MixBlendMode::Overlay)
948            .mix_blend_mode(MixBlendMode::Difference)
949            .build();
950        
951        let css_classes = classes.to_css_classes();
952        assert!(css_classes.contains("mix-blend-normal"));
953        assert!(css_classes.contains("mix-blend-multiply"));
954        assert!(css_classes.contains("mix-blend-screen"));
955        assert!(css_classes.contains("mix-blend-overlay"));
956        assert!(css_classes.contains("mix-blend-difference"));
957    }
958    
959    #[test]
960    fn test_background_blend_mode_utilities() {
961        let classes = ClassBuilder::new()
962            .background_blend_mode(BackgroundBlendMode::Normal)
963            .background_blend_mode(BackgroundBlendMode::Multiply)
964            .background_blend_mode(BackgroundBlendMode::Screen)
965            .background_blend_mode(BackgroundBlendMode::Overlay)
966            .background_blend_mode(BackgroundBlendMode::Difference)
967            .build();
968        
969        let css_classes = classes.to_css_classes();
970        assert!(css_classes.contains("bg-blend-normal"));
971        assert!(css_classes.contains("bg-blend-multiply"));
972        assert!(css_classes.contains("bg-blend-screen"));
973        assert!(css_classes.contains("bg-blend-overlay"));
974        assert!(css_classes.contains("bg-blend-difference"));
975    }
976    
977    #[test]
978    fn test_complex_effects_combination() {
979        let classes = ClassBuilder::new()
980            .box_shadow(BoxShadow::Lg)
981            .drop_shadow(DropShadow::Md)
982            .opacity(Opacity::Eighty)
983            .mix_blend_mode(MixBlendMode::Multiply)
984            .background_blend_mode(BackgroundBlendMode::Screen)
985            .build();
986        
987        let css_classes = classes.to_css_classes();
988        assert!(css_classes.contains("shadow-lg"));
989        assert!(css_classes.contains("drop-shadow-md"));
990        assert!(css_classes.contains("opacity-80"));
991        assert!(css_classes.contains("mix-blend-multiply"));
992        assert!(css_classes.contains("bg-blend-screen"));
993    }
994    
995    /// Test that all Week 9 shadow and opacity utilities are implemented
996    #[test]
997    fn test_week9_shadow_opacity_utilities() {
998        // Test all Week 9 shadow and opacity utilities
999        let classes = ClassBuilder::new()
1000            // Box Shadows
1001            .box_shadow(BoxShadow::Sm)
1002            .box_shadow(BoxShadow::Default)
1003            .box_shadow(BoxShadow::Md)
1004            .box_shadow(BoxShadow::Lg)
1005            .box_shadow(BoxShadow::Xl)
1006            .box_shadow(BoxShadow::Xl2)
1007            .box_shadow(BoxShadow::Inner)
1008            .box_shadow(BoxShadow::None)
1009            // Drop Shadows
1010            .drop_shadow(DropShadow::Sm)
1011            .drop_shadow(DropShadow::Default)
1012            .drop_shadow(DropShadow::Md)
1013            .drop_shadow(DropShadow::Lg)
1014            .drop_shadow(DropShadow::Xl)
1015            .drop_shadow(DropShadow::Xl2)
1016            .drop_shadow(DropShadow::None)
1017            // Opacity
1018            .opacity(Opacity::Zero)
1019            .opacity(Opacity::Five)
1020            .opacity(Opacity::Ten)
1021            .opacity(Opacity::Twenty)
1022            .opacity(Opacity::TwentyFive)
1023            .opacity(Opacity::Thirty)
1024            .opacity(Opacity::Forty)
1025            .opacity(Opacity::Fifty)
1026            .opacity(Opacity::Sixty)
1027            .opacity(Opacity::Seventy)
1028            .opacity(Opacity::SeventyFive)
1029            .opacity(Opacity::Eighty)
1030            .opacity(Opacity::Ninety)
1031            .opacity(Opacity::NinetyFive)
1032            .opacity(Opacity::Hundred)
1033            .build();
1034        
1035        let css_classes = classes.to_css_classes();
1036        
1037        // Box Shadows
1038        assert!(css_classes.contains("shadow-sm"));
1039        assert!(css_classes.contains("shadow"));
1040        assert!(css_classes.contains("shadow-md"));
1041        assert!(css_classes.contains("shadow-lg"));
1042        assert!(css_classes.contains("shadow-xl"));
1043        assert!(css_classes.contains("shadow-2xl"));
1044        assert!(css_classes.contains("shadow-inner"));
1045        assert!(css_classes.contains("shadow-none"));
1046        
1047        // Drop Shadows
1048        assert!(css_classes.contains("drop-shadow-sm"));
1049        assert!(css_classes.contains("drop-shadow"));
1050        assert!(css_classes.contains("drop-shadow-md"));
1051        assert!(css_classes.contains("drop-shadow-lg"));
1052        assert!(css_classes.contains("drop-shadow-xl"));
1053        assert!(css_classes.contains("drop-shadow-2xl"));
1054        assert!(css_classes.contains("drop-shadow-none"));
1055        
1056        // Opacity
1057        assert!(css_classes.contains("opacity-0"));
1058        assert!(css_classes.contains("opacity-5"));
1059        assert!(css_classes.contains("opacity-10"));
1060        assert!(css_classes.contains("opacity-20"));
1061        assert!(css_classes.contains("opacity-25"));
1062        assert!(css_classes.contains("opacity-30"));
1063        assert!(css_classes.contains("opacity-40"));
1064        assert!(css_classes.contains("opacity-50"));
1065        assert!(css_classes.contains("opacity-60"));
1066        assert!(css_classes.contains("opacity-70"));
1067        assert!(css_classes.contains("opacity-75"));
1068        assert!(css_classes.contains("opacity-80"));
1069        assert!(css_classes.contains("opacity-90"));
1070        assert!(css_classes.contains("opacity-95"));
1071        assert!(css_classes.contains("opacity-100"));
1072    }
1073
1074    #[test]
1075    fn test_box_shadow_display() {
1076        // Test that BoxShadow displays correctly
1077        assert_eq!(format!("{}", BoxShadow::None), "none");
1078        assert_eq!(format!("{}", BoxShadow::Sm), "sm");
1079        assert_eq!(format!("{}", BoxShadow::Default), "default");
1080        assert_eq!(format!("{}", BoxShadow::Md), "md");
1081        assert_eq!(format!("{}", BoxShadow::Lg), "lg");
1082        assert_eq!(format!("{}", BoxShadow::Xl), "xl");
1083        assert_eq!(format!("{}", BoxShadow::Xl2), "2xl");
1084        assert_eq!(format!("{}", BoxShadow::Inner), "inner");
1085    }
1086
1087    #[test]
1088    fn test_drop_shadow_display() {
1089        // Test that DropShadow displays correctly
1090        assert_eq!(format!("{}", DropShadow::None), "none");
1091        assert_eq!(format!("{}", DropShadow::Sm), "sm");
1092        assert_eq!(format!("{}", DropShadow::Default), "default");
1093        assert_eq!(format!("{}", DropShadow::Md), "md");
1094        assert_eq!(format!("{}", DropShadow::Lg), "lg");
1095        assert_eq!(format!("{}", DropShadow::Xl), "xl");
1096        assert_eq!(format!("{}", DropShadow::Xl2), "2xl");
1097        assert_eq!(format!("{}", DropShadow::Xl3), "3xl");
1098    }
1099
1100    #[test]
1101    fn test_opacity_display() {
1102        // Test that Opacity displays correctly
1103        assert_eq!(format!("{}", Opacity::Zero), "0");
1104        assert_eq!(format!("{}", Opacity::Five), "5");
1105        assert_eq!(format!("{}", Opacity::Ten), "10");
1106        assert_eq!(format!("{}", Opacity::Twenty), "20");
1107        assert_eq!(format!("{}", Opacity::TwentyFive), "25");
1108        assert_eq!(format!("{}", Opacity::Thirty), "30");
1109        assert_eq!(format!("{}", Opacity::Forty), "40");
1110        assert_eq!(format!("{}", Opacity::Fifty), "50");
1111        assert_eq!(format!("{}", Opacity::Sixty), "60");
1112        assert_eq!(format!("{}", Opacity::Seventy), "70");
1113        assert_eq!(format!("{}", Opacity::SeventyFive), "75");
1114        assert_eq!(format!("{}", Opacity::Eighty), "80");
1115        assert_eq!(format!("{}", Opacity::Ninety), "90");
1116        assert_eq!(format!("{}", Opacity::NinetyFive), "95");
1117        assert_eq!(format!("{}", Opacity::Hundred), "100");
1118    }
1119
1120    #[test]
1121    fn test_mix_blend_mode_display() {
1122        // Test that MixBlendMode displays correctly
1123        assert_eq!(format!("{}", MixBlendMode::Normal), "normal");
1124        assert_eq!(format!("{}", MixBlendMode::Multiply), "multiply");
1125        assert_eq!(format!("{}", MixBlendMode::Screen), "screen");
1126        assert_eq!(format!("{}", MixBlendMode::Overlay), "overlay");
1127        assert_eq!(format!("{}", MixBlendMode::Darken), "darken");
1128        assert_eq!(format!("{}", MixBlendMode::Lighten), "lighten");
1129        assert_eq!(format!("{}", MixBlendMode::ColorDodge), "color-dodge");
1130        assert_eq!(format!("{}", MixBlendMode::ColorBurn), "color-burn");
1131        assert_eq!(format!("{}", MixBlendMode::HardLight), "hard-light");
1132        assert_eq!(format!("{}", MixBlendMode::SoftLight), "soft-light");
1133        assert_eq!(format!("{}", MixBlendMode::Difference), "difference");
1134        assert_eq!(format!("{}", MixBlendMode::Exclusion), "exclusion");
1135        assert_eq!(format!("{}", MixBlendMode::Hue), "hue");
1136        assert_eq!(format!("{}", MixBlendMode::Saturation), "saturation");
1137        assert_eq!(format!("{}", MixBlendMode::Color), "color");
1138        assert_eq!(format!("{}", MixBlendMode::Luminosity), "luminosity");
1139    }
1140
1141    #[test]
1142    fn test_background_blend_mode_display() {
1143        // Test that BackgroundBlendMode displays correctly
1144        assert_eq!(format!("{}", BackgroundBlendMode::Normal), "normal");
1145        assert_eq!(format!("{}", BackgroundBlendMode::Multiply), "multiply");
1146        assert_eq!(format!("{}", BackgroundBlendMode::Screen), "screen");
1147        assert_eq!(format!("{}", BackgroundBlendMode::Overlay), "overlay");
1148        assert_eq!(format!("{}", BackgroundBlendMode::Darken), "darken");
1149        assert_eq!(format!("{}", BackgroundBlendMode::Lighten), "lighten");
1150        assert_eq!(format!("{}", BackgroundBlendMode::ColorDodge), "color-dodge");
1151        assert_eq!(format!("{}", BackgroundBlendMode::ColorBurn), "color-burn");
1152        assert_eq!(format!("{}", BackgroundBlendMode::HardLight), "hard-light");
1153        assert_eq!(format!("{}", BackgroundBlendMode::SoftLight), "soft-light");
1154        assert_eq!(format!("{}", BackgroundBlendMode::Difference), "difference");
1155        assert_eq!(format!("{}", BackgroundBlendMode::Exclusion), "exclusion");
1156        assert_eq!(format!("{}", BackgroundBlendMode::Hue), "hue");
1157        assert_eq!(format!("{}", BackgroundBlendMode::Saturation), "saturation");
1158        assert_eq!(format!("{}", BackgroundBlendMode::Color), "color");
1159        assert_eq!(format!("{}", BackgroundBlendMode::Luminosity), "luminosity");
1160    }
1161
1162    #[test]
1163    fn test_box_shadow_css_values() {
1164        // Test that BoxShadow generates correct CSS values
1165        assert_eq!(BoxShadow::None.to_css_value(), "none");
1166        assert_eq!(BoxShadow::Sm.to_css_value(), "0 1px 2px 0 rgb(0 0 0 / 0.05)");
1167        assert_eq!(BoxShadow::Default.to_css_value(), "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)");
1168        assert_eq!(BoxShadow::Md.to_css_value(), "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)");
1169        assert_eq!(BoxShadow::Lg.to_css_value(), "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)");
1170        assert_eq!(BoxShadow::Xl.to_css_value(), "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)");
1171        assert_eq!(BoxShadow::Xl2.to_css_value(), "0 25px 50px -12px rgb(0 0 0 / 0.25)");
1172        assert_eq!(BoxShadow::Inner.to_css_value(), "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)");
1173    }
1174
1175    #[test]
1176    fn test_drop_shadow_css_values() {
1177        // Test that DropShadow generates correct CSS values
1178        assert_eq!(DropShadow::None.to_css_value(), "none");
1179        assert_eq!(DropShadow::Sm.to_css_value(), "0 1px 2px rgb(0 0 0 / 0.05)");
1180        assert_eq!(DropShadow::Default.to_css_value(), "0 1px 3px rgb(0 0 0 / 0.1), 0 1px 2px rgb(0 0 0 / 0.06)");
1181        assert_eq!(DropShadow::Md.to_css_value(), "0 4px 6px rgb(0 0 0 / 0.07), 0 2px 4px rgb(0 0 0 / 0.06)");
1182        assert_eq!(DropShadow::Lg.to_css_value(), "0 10px 15px rgb(0 0 0 / 0.1), 0 4px 6px rgb(0 0 0 / 0.05)");
1183        assert_eq!(DropShadow::Xl.to_css_value(), "0 20px 25px rgb(0 0 0 / 0.1), 0 8px 10px rgb(0 0 0 / 0.04)");
1184        assert_eq!(DropShadow::Xl2.to_css_value(), "0 25px 50px rgb(0 0 0 / 0.25)");
1185        assert_eq!(DropShadow::Xl3.to_css_value(), "0 35px 60px rgb(0 0 0 / 0.3)");
1186    }
1187
1188    #[test]
1189    fn test_opacity_css_values() {
1190        // Test that Opacity generates correct CSS values
1191        assert_eq!(Opacity::Zero.to_css_value(), "0");
1192        assert_eq!(Opacity::Five.to_css_value(), "0.05");
1193        assert_eq!(Opacity::Ten.to_css_value(), "0.1");
1194        assert_eq!(Opacity::Twenty.to_css_value(), "0.2");
1195        assert_eq!(Opacity::TwentyFive.to_css_value(), "0.25");
1196        assert_eq!(Opacity::Thirty.to_css_value(), "0.3");
1197        assert_eq!(Opacity::Forty.to_css_value(), "0.4");
1198        assert_eq!(Opacity::Fifty.to_css_value(), "0.5");
1199        assert_eq!(Opacity::Sixty.to_css_value(), "0.6");
1200        assert_eq!(Opacity::Seventy.to_css_value(), "0.7");
1201        assert_eq!(Opacity::SeventyFive.to_css_value(), "0.75");
1202        assert_eq!(Opacity::Eighty.to_css_value(), "0.8");
1203        assert_eq!(Opacity::Ninety.to_css_value(), "0.9");
1204        assert_eq!(Opacity::NinetyFive.to_css_value(), "0.95");
1205        assert_eq!(Opacity::Hundred.to_css_value(), "1");
1206    }
1207
1208    #[test]
1209    fn test_mix_blend_mode_css_values() {
1210        // Test that MixBlendMode generates correct CSS values
1211        assert_eq!(MixBlendMode::Normal.to_css_value(), "normal");
1212        assert_eq!(MixBlendMode::Multiply.to_css_value(), "multiply");
1213        assert_eq!(MixBlendMode::Screen.to_css_value(), "screen");
1214        assert_eq!(MixBlendMode::Overlay.to_css_value(), "overlay");
1215        assert_eq!(MixBlendMode::Darken.to_css_value(), "darken");
1216        assert_eq!(MixBlendMode::Lighten.to_css_value(), "lighten");
1217        assert_eq!(MixBlendMode::ColorDodge.to_css_value(), "color-dodge");
1218        assert_eq!(MixBlendMode::ColorBurn.to_css_value(), "color-burn");
1219        assert_eq!(MixBlendMode::HardLight.to_css_value(), "hard-light");
1220        assert_eq!(MixBlendMode::SoftLight.to_css_value(), "soft-light");
1221        assert_eq!(MixBlendMode::Difference.to_css_value(), "difference");
1222        assert_eq!(MixBlendMode::Exclusion.to_css_value(), "exclusion");
1223        assert_eq!(MixBlendMode::Hue.to_css_value(), "hue");
1224        assert_eq!(MixBlendMode::Saturation.to_css_value(), "saturation");
1225        assert_eq!(MixBlendMode::Color.to_css_value(), "color");
1226        assert_eq!(MixBlendMode::Luminosity.to_css_value(), "luminosity");
1227    }
1228
1229    #[test]
1230    fn test_background_blend_mode_css_values() {
1231        // Test that BackgroundBlendMode generates correct CSS values
1232        assert_eq!(BackgroundBlendMode::Normal.to_css_value(), "normal");
1233        assert_eq!(BackgroundBlendMode::Multiply.to_css_value(), "multiply");
1234        assert_eq!(BackgroundBlendMode::Screen.to_css_value(), "screen");
1235        assert_eq!(BackgroundBlendMode::Overlay.to_css_value(), "overlay");
1236        assert_eq!(BackgroundBlendMode::Darken.to_css_value(), "darken");
1237        assert_eq!(BackgroundBlendMode::Lighten.to_css_value(), "lighten");
1238        assert_eq!(BackgroundBlendMode::ColorDodge.to_css_value(), "color-dodge");
1239        assert_eq!(BackgroundBlendMode::ColorBurn.to_css_value(), "color-burn");
1240        assert_eq!(BackgroundBlendMode::HardLight.to_css_value(), "hard-light");
1241        assert_eq!(BackgroundBlendMode::SoftLight.to_css_value(), "soft-light");
1242        assert_eq!(BackgroundBlendMode::Difference.to_css_value(), "difference");
1243        assert_eq!(BackgroundBlendMode::Exclusion.to_css_value(), "exclusion");
1244        assert_eq!(BackgroundBlendMode::Hue.to_css_value(), "hue");
1245        assert_eq!(BackgroundBlendMode::Saturation.to_css_value(), "saturation");
1246        assert_eq!(BackgroundBlendMode::Color.to_css_value(), "color");
1247        assert_eq!(BackgroundBlendMode::Luminosity.to_css_value(), "luminosity");
1248    }
1249
1250    #[test]
1251    fn test_effects_serialization() {
1252        // Test that effects can be serialized and deserialized
1253        let box_shadow = BoxShadow::Lg;
1254        let serialized = serde_json::to_string(&box_shadow).unwrap();
1255        let deserialized: BoxShadow = serde_json::from_str(&serialized).unwrap();
1256        assert_eq!(box_shadow, deserialized);
1257
1258        let drop_shadow = DropShadow::Md;
1259        let serialized = serde_json::to_string(&drop_shadow).unwrap();
1260        let deserialized: DropShadow = serde_json::from_str(&serialized).unwrap();
1261        assert_eq!(drop_shadow, deserialized);
1262
1263        let opacity = Opacity::Fifty;
1264        let serialized = serde_json::to_string(&opacity).unwrap();
1265        let deserialized: Opacity = serde_json::from_str(&serialized).unwrap();
1266        assert_eq!(opacity, deserialized);
1267
1268        let mix_blend_mode = MixBlendMode::Multiply;
1269        let serialized = serde_json::to_string(&mix_blend_mode).unwrap();
1270        let deserialized: MixBlendMode = serde_json::from_str(&serialized).unwrap();
1271        assert_eq!(mix_blend_mode, deserialized);
1272
1273        let background_blend_mode = BackgroundBlendMode::Screen;
1274        let serialized = serde_json::to_string(&background_blend_mode).unwrap();
1275        let deserialized: BackgroundBlendMode = serde_json::from_str(&serialized).unwrap();
1276        assert_eq!(background_blend_mode, deserialized);
1277    }
1278
1279    #[test]
1280    fn test_effects_equality_and_hash() {
1281        // Test that effects can be compared for equality and hashed
1282        let box_shadow1 = BoxShadow::Lg;
1283        let box_shadow2 = BoxShadow::Lg;
1284        let box_shadow3 = BoxShadow::Md;
1285        
1286        assert_eq!(box_shadow1, box_shadow2);
1287        assert_ne!(box_shadow1, box_shadow3);
1288        
1289        // Test that equal effects have the same hash
1290        use std::collections::hash_map::DefaultHasher;
1291        use std::hash::{Hash, Hasher};
1292        
1293        let mut hasher1 = DefaultHasher::new();
1294        let mut hasher2 = DefaultHasher::new();
1295        box_shadow1.hash(&mut hasher1);
1296        box_shadow2.hash(&mut hasher2);
1297        assert_eq!(hasher1.finish(), hasher2.finish());
1298    }
1299
1300    #[test]
1301    fn test_comprehensive_effects_utilities() {
1302        // Test comprehensive usage of all effects utility methods
1303        let classes = ClassBuilder::new()
1304            // Box shadows
1305            .box_shadow(BoxShadow::None)
1306            .box_shadow(BoxShadow::Sm)
1307            .box_shadow(BoxShadow::Default)
1308            .box_shadow(BoxShadow::Md)
1309            .box_shadow(BoxShadow::Lg)
1310            .box_shadow(BoxShadow::Xl)
1311            .box_shadow(BoxShadow::Xl2)
1312            .box_shadow(BoxShadow::Inner)
1313            
1314            // Drop shadows
1315            .drop_shadow(DropShadow::None)
1316            .drop_shadow(DropShadow::Sm)
1317            .drop_shadow(DropShadow::Default)
1318            .drop_shadow(DropShadow::Md)
1319            .drop_shadow(DropShadow::Lg)
1320            .drop_shadow(DropShadow::Xl)
1321            .drop_shadow(DropShadow::Xl2)
1322            .drop_shadow(DropShadow::Xl3)
1323            
1324            // Opacity
1325            .opacity(Opacity::Zero)
1326            .opacity(Opacity::TwentyFive)
1327            .opacity(Opacity::Fifty)
1328            .opacity(Opacity::SeventyFive)
1329            .opacity(Opacity::Hundred)
1330            
1331            // Mix blend modes
1332            .mix_blend_mode(MixBlendMode::Normal)
1333            .mix_blend_mode(MixBlendMode::Multiply)
1334            .mix_blend_mode(MixBlendMode::Screen)
1335            .mix_blend_mode(MixBlendMode::Overlay)
1336            .mix_blend_mode(MixBlendMode::Difference)
1337            
1338            // Background blend modes
1339            .background_blend_mode(BackgroundBlendMode::Normal)
1340            .background_blend_mode(BackgroundBlendMode::Multiply)
1341            .background_blend_mode(BackgroundBlendMode::Screen)
1342            .background_blend_mode(BackgroundBlendMode::Overlay)
1343            .background_blend_mode(BackgroundBlendMode::Difference)
1344            .build();
1345        
1346        let css_classes = classes.to_css_classes();
1347        
1348        // Verify box shadows
1349        assert!(css_classes.contains("shadow-none"));
1350        assert!(css_classes.contains("shadow-sm"));
1351        assert!(css_classes.contains("shadow-default"));
1352        assert!(css_classes.contains("shadow-md"));
1353        assert!(css_classes.contains("shadow-lg"));
1354        assert!(css_classes.contains("shadow-xl"));
1355        assert!(css_classes.contains("shadow-2xl"));
1356        assert!(css_classes.contains("shadow-inner"));
1357        
1358        // Verify drop shadows
1359        assert!(css_classes.contains("drop-shadow-none"));
1360        assert!(css_classes.contains("drop-shadow-sm"));
1361        assert!(css_classes.contains("drop-shadow-default"));
1362        assert!(css_classes.contains("drop-shadow-md"));
1363        assert!(css_classes.contains("drop-shadow-lg"));
1364        assert!(css_classes.contains("drop-shadow-xl"));
1365        assert!(css_classes.contains("drop-shadow-2xl"));
1366        assert!(css_classes.contains("drop-shadow-3xl"));
1367        
1368        // Verify opacity
1369        assert!(css_classes.contains("opacity-0"));
1370        assert!(css_classes.contains("opacity-25"));
1371        assert!(css_classes.contains("opacity-50"));
1372        assert!(css_classes.contains("opacity-75"));
1373        assert!(css_classes.contains("opacity-100"));
1374        
1375        // Verify mix blend modes
1376        assert!(css_classes.contains("mix-blend-normal"));
1377        assert!(css_classes.contains("mix-blend-multiply"));
1378        assert!(css_classes.contains("mix-blend-screen"));
1379        assert!(css_classes.contains("mix-blend-overlay"));
1380        assert!(css_classes.contains("mix-blend-difference"));
1381        
1382        // Verify background blend modes
1383        assert!(css_classes.contains("bg-blend-normal"));
1384        assert!(css_classes.contains("bg-blend-multiply"));
1385        assert!(css_classes.contains("bg-blend-screen"));
1386        assert!(css_classes.contains("bg-blend-overlay"));
1387        assert!(css_classes.contains("bg-blend-difference"));
1388    }
1389}