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