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
161impl BoxShadow {
162    pub fn to_class_name(&self) -> String {
163        match self {
164            BoxShadow::None => "none".to_string(),
165            BoxShadow::Sm => "sm".to_string(),
166            BoxShadow::Default => "default".to_string(),
167            BoxShadow::Md => "md".to_string(),
168            BoxShadow::Lg => "lg".to_string(),
169            BoxShadow::Xl => "xl".to_string(),
170            BoxShadow::Xl2 => "2xl".to_string(),
171            BoxShadow::Inner => "inner".to_string(),
172        }
173    }
174    
175    pub fn to_css_value(&self) -> String {
176        match self {
177            BoxShadow::None => "none".to_string(),
178            BoxShadow::Sm => "0 1px 2px 0 rgb(0 0 0 / 0.05)".to_string(),
179            BoxShadow::Default => "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)".to_string(),
180            BoxShadow::Md => "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)".to_string(),
181            BoxShadow::Lg => "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)".to_string(),
182            BoxShadow::Xl => "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)".to_string(),
183            BoxShadow::Xl2 => "0 25px 50px -12px rgb(0 0 0 / 0.25)".to_string(),
184            BoxShadow::Inner => "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)".to_string(),
185        }
186    }
187}
188
189impl DropShadow {
190    pub fn to_class_name(&self) -> String {
191        match self {
192            DropShadow::None => "none".to_string(),
193            DropShadow::Sm => "sm".to_string(),
194            DropShadow::Default => "default".to_string(),
195            DropShadow::Md => "md".to_string(),
196            DropShadow::Lg => "lg".to_string(),
197            DropShadow::Xl => "xl".to_string(),
198            DropShadow::Xl2 => "2xl".to_string(),
199            DropShadow::Xl3 => "3xl".to_string(),
200        }
201    }
202    
203    pub fn to_css_value(&self) -> String {
204        match self {
205            DropShadow::None => "none".to_string(),
206            DropShadow::Sm => "0 1px 2px rgb(0 0 0 / 0.05)".to_string(),
207            DropShadow::Default => "0 1px 3px rgb(0 0 0 / 0.1), 0 1px 2px rgb(0 0 0 / 0.06)".to_string(),
208            DropShadow::Md => "0 4px 6px rgb(0 0 0 / 0.07), 0 2px 4px rgb(0 0 0 / 0.06)".to_string(),
209            DropShadow::Lg => "0 10px 15px rgb(0 0 0 / 0.1), 0 4px 6px rgb(0 0 0 / 0.05)".to_string(),
210            DropShadow::Xl => "0 20px 25px rgb(0 0 0 / 0.1), 0 8px 10px rgb(0 0 0 / 0.04)".to_string(),
211            DropShadow::Xl2 => "0 25px 50px rgb(0 0 0 / 0.25)".to_string(),
212            DropShadow::Xl3 => "0 35px 60px rgb(0 0 0 / 0.3)".to_string(),
213        }
214    }
215}
216
217impl Opacity {
218    pub fn to_class_name(&self) -> String {
219        match self {
220            Opacity::Zero => "0".to_string(),
221            Opacity::Five => "5".to_string(),
222            Opacity::Ten => "10".to_string(),
223            Opacity::Twenty => "20".to_string(),
224            Opacity::TwentyFive => "25".to_string(),
225            Opacity::Thirty => "30".to_string(),
226            Opacity::Forty => "40".to_string(),
227            Opacity::Fifty => "50".to_string(),
228            Opacity::Sixty => "60".to_string(),
229            Opacity::Seventy => "70".to_string(),
230            Opacity::SeventyFive => "75".to_string(),
231            Opacity::Eighty => "80".to_string(),
232            Opacity::Ninety => "90".to_string(),
233            Opacity::NinetyFive => "95".to_string(),
234            Opacity::Hundred => "100".to_string(),
235        }
236    }
237    
238    pub fn to_css_value(&self) -> String {
239        match self {
240            Opacity::Zero => "0".to_string(),
241            Opacity::Five => "0.05".to_string(),
242            Opacity::Ten => "0.1".to_string(),
243            Opacity::Twenty => "0.2".to_string(),
244            Opacity::TwentyFive => "0.25".to_string(),
245            Opacity::Thirty => "0.3".to_string(),
246            Opacity::Forty => "0.4".to_string(),
247            Opacity::Fifty => "0.5".to_string(),
248            Opacity::Sixty => "0.6".to_string(),
249            Opacity::Seventy => "0.7".to_string(),
250            Opacity::SeventyFive => "0.75".to_string(),
251            Opacity::Eighty => "0.8".to_string(),
252            Opacity::Ninety => "0.9".to_string(),
253            Opacity::NinetyFive => "0.95".to_string(),
254            Opacity::Hundred => "1".to_string(),
255        }
256    }
257}
258
259impl MixBlendMode {
260    pub fn to_class_name(&self) -> String {
261        match self {
262            MixBlendMode::Normal => "normal".to_string(),
263            MixBlendMode::Multiply => "multiply".to_string(),
264            MixBlendMode::Screen => "screen".to_string(),
265            MixBlendMode::Overlay => "overlay".to_string(),
266            MixBlendMode::Darken => "darken".to_string(),
267            MixBlendMode::Lighten => "lighten".to_string(),
268            MixBlendMode::ColorDodge => "color-dodge".to_string(),
269            MixBlendMode::ColorBurn => "color-burn".to_string(),
270            MixBlendMode::HardLight => "hard-light".to_string(),
271            MixBlendMode::SoftLight => "soft-light".to_string(),
272            MixBlendMode::Difference => "difference".to_string(),
273            MixBlendMode::Exclusion => "exclusion".to_string(),
274            MixBlendMode::Hue => "hue".to_string(),
275            MixBlendMode::Saturation => "saturation".to_string(),
276            MixBlendMode::Color => "color".to_string(),
277            MixBlendMode::Luminosity => "luminosity".to_string(),
278        }
279    }
280    
281    pub fn to_css_value(&self) -> String {
282        match self {
283            MixBlendMode::Normal => "normal".to_string(),
284            MixBlendMode::Multiply => "multiply".to_string(),
285            MixBlendMode::Screen => "screen".to_string(),
286            MixBlendMode::Overlay => "overlay".to_string(),
287            MixBlendMode::Darken => "darken".to_string(),
288            MixBlendMode::Lighten => "lighten".to_string(),
289            MixBlendMode::ColorDodge => "color-dodge".to_string(),
290            MixBlendMode::ColorBurn => "color-burn".to_string(),
291            MixBlendMode::HardLight => "hard-light".to_string(),
292            MixBlendMode::SoftLight => "soft-light".to_string(),
293            MixBlendMode::Difference => "difference".to_string(),
294            MixBlendMode::Exclusion => "exclusion".to_string(),
295            MixBlendMode::Hue => "hue".to_string(),
296            MixBlendMode::Saturation => "saturation".to_string(),
297            MixBlendMode::Color => "color".to_string(),
298            MixBlendMode::Luminosity => "luminosity".to_string(),
299        }
300    }
301}
302
303impl BackgroundBlendMode {
304    pub fn to_class_name(&self) -> String {
305        match self {
306            BackgroundBlendMode::Normal => "normal".to_string(),
307            BackgroundBlendMode::Multiply => "multiply".to_string(),
308            BackgroundBlendMode::Screen => "screen".to_string(),
309            BackgroundBlendMode::Overlay => "overlay".to_string(),
310            BackgroundBlendMode::Darken => "darken".to_string(),
311            BackgroundBlendMode::Lighten => "lighten".to_string(),
312            BackgroundBlendMode::ColorDodge => "color-dodge".to_string(),
313            BackgroundBlendMode::ColorBurn => "color-burn".to_string(),
314            BackgroundBlendMode::HardLight => "hard-light".to_string(),
315            BackgroundBlendMode::SoftLight => "soft-light".to_string(),
316            BackgroundBlendMode::Difference => "difference".to_string(),
317            BackgroundBlendMode::Exclusion => "exclusion".to_string(),
318            BackgroundBlendMode::Hue => "hue".to_string(),
319            BackgroundBlendMode::Saturation => "saturation".to_string(),
320            BackgroundBlendMode::Color => "color".to_string(),
321            BackgroundBlendMode::Luminosity => "luminosity".to_string(),
322        }
323    }
324    
325    pub fn to_css_value(&self) -> String {
326        match self {
327            BackgroundBlendMode::Normal => "normal".to_string(),
328            BackgroundBlendMode::Multiply => "multiply".to_string(),
329            BackgroundBlendMode::Screen => "screen".to_string(),
330            BackgroundBlendMode::Overlay => "overlay".to_string(),
331            BackgroundBlendMode::Darken => "darken".to_string(),
332            BackgroundBlendMode::Lighten => "lighten".to_string(),
333            BackgroundBlendMode::ColorDodge => "color-dodge".to_string(),
334            BackgroundBlendMode::ColorBurn => "color-burn".to_string(),
335            BackgroundBlendMode::HardLight => "hard-light".to_string(),
336            BackgroundBlendMode::SoftLight => "soft-light".to_string(),
337            BackgroundBlendMode::Difference => "difference".to_string(),
338            BackgroundBlendMode::Exclusion => "exclusion".to_string(),
339            BackgroundBlendMode::Hue => "hue".to_string(),
340            BackgroundBlendMode::Saturation => "saturation".to_string(),
341            BackgroundBlendMode::Color => "color".to_string(),
342            BackgroundBlendMode::Luminosity => "luminosity".to_string(),
343        }
344    }
345}
346
347impl fmt::Display for BoxShadow {
348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349        write!(f, "{}", self.to_class_name())
350    }
351}
352
353impl fmt::Display for DropShadow {
354    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
355        write!(f, "{}", self.to_class_name())
356    }
357}
358
359impl fmt::Display for Opacity {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        write!(f, "{}", self.to_class_name())
362    }
363}
364
365impl fmt::Display for MixBlendMode {
366    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367        write!(f, "{}", self.to_class_name())
368    }
369}
370
371impl fmt::Display for BackgroundBlendMode {
372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373        write!(f, "{}", self.to_class_name())
374    }
375}
376
377/// Trait for adding box shadow utilities to a class builder
378pub trait BoxShadowUtilities {
379    fn box_shadow(self, shadow: BoxShadow) -> Self;
380}
381
382impl BoxShadowUtilities for ClassBuilder {
383    fn box_shadow(self, shadow: BoxShadow) -> Self {
384        self.class(format!("shadow-{}", shadow.to_class_name()))
385    }
386}
387
388/// Trait for adding drop shadow utilities to a class builder
389pub trait DropShadowUtilities {
390    fn drop_shadow(self, shadow: DropShadow) -> Self;
391}
392
393impl DropShadowUtilities for ClassBuilder {
394    fn drop_shadow(self, shadow: DropShadow) -> Self {
395        self.class(format!("drop-shadow-{}", shadow.to_class_name()))
396    }
397}
398
399/// Trait for adding opacity utilities to a class builder
400pub trait OpacityUtilities {
401    fn opacity(self, opacity: Opacity) -> Self;
402}
403
404impl OpacityUtilities for ClassBuilder {
405    fn opacity(self, opacity: Opacity) -> Self {
406        self.class(format!("opacity-{}", opacity.to_class_name()))
407    }
408}
409
410/// Trait for adding mix blend mode utilities to a class builder
411pub trait MixBlendModeUtilities {
412    fn mix_blend_mode(self, mode: MixBlendMode) -> Self;
413}
414
415impl MixBlendModeUtilities for ClassBuilder {
416    fn mix_blend_mode(self, mode: MixBlendMode) -> Self {
417        self.class(format!("mix-blend-{}", mode.to_class_name()))
418    }
419}
420
421/// Trait for adding background blend mode utilities to a class builder
422pub trait BackgroundBlendModeUtilities {
423    fn background_blend_mode(self, mode: BackgroundBlendMode) -> Self;
424}
425
426impl BackgroundBlendModeUtilities for ClassBuilder {
427    fn background_blend_mode(self, mode: BackgroundBlendMode) -> Self {
428        self.class(format!("bg-blend-{}", mode.to_class_name()))
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    use super::*;
435    
436    #[test]
437    fn test_box_shadow_utilities() {
438        let classes = ClassBuilder::new()
439            .box_shadow(BoxShadow::None)
440            .box_shadow(BoxShadow::Sm)
441            .box_shadow(BoxShadow::Default)
442            .box_shadow(BoxShadow::Md)
443            .box_shadow(BoxShadow::Lg)
444            .box_shadow(BoxShadow::Xl)
445            .box_shadow(BoxShadow::Xl2)
446            .box_shadow(BoxShadow::Inner)
447            .build();
448        
449        let css_classes = classes.to_css_classes();
450        assert!(css_classes.contains("shadow-none"));
451        assert!(css_classes.contains("shadow-sm"));
452        assert!(css_classes.contains("shadow-default"));
453        assert!(css_classes.contains("shadow-md"));
454        assert!(css_classes.contains("shadow-lg"));
455        assert!(css_classes.contains("shadow-xl"));
456        assert!(css_classes.contains("shadow-2xl"));
457        assert!(css_classes.contains("shadow-inner"));
458    }
459    
460    #[test]
461    fn test_drop_shadow_utilities() {
462        let classes = ClassBuilder::new()
463            .drop_shadow(DropShadow::None)
464            .drop_shadow(DropShadow::Sm)
465            .drop_shadow(DropShadow::Default)
466            .drop_shadow(DropShadow::Md)
467            .drop_shadow(DropShadow::Lg)
468            .drop_shadow(DropShadow::Xl)
469            .drop_shadow(DropShadow::Xl2)
470            .drop_shadow(DropShadow::Xl3)
471            .build();
472        
473        let css_classes = classes.to_css_classes();
474        assert!(css_classes.contains("drop-shadow-none"));
475        assert!(css_classes.contains("drop-shadow-sm"));
476        assert!(css_classes.contains("drop-shadow-default"));
477        assert!(css_classes.contains("drop-shadow-md"));
478        assert!(css_classes.contains("drop-shadow-lg"));
479        assert!(css_classes.contains("drop-shadow-xl"));
480        assert!(css_classes.contains("drop-shadow-2xl"));
481        assert!(css_classes.contains("drop-shadow-3xl"));
482    }
483    
484    #[test]
485    fn test_opacity_utilities() {
486        let classes = ClassBuilder::new()
487            .opacity(Opacity::Zero)
488            .opacity(Opacity::TwentyFive)
489            .opacity(Opacity::Fifty)
490            .opacity(Opacity::SeventyFive)
491            .opacity(Opacity::Hundred)
492            .build();
493        
494        let css_classes = classes.to_css_classes();
495        assert!(css_classes.contains("opacity-0"));
496        assert!(css_classes.contains("opacity-25"));
497        assert!(css_classes.contains("opacity-50"));
498        assert!(css_classes.contains("opacity-75"));
499        assert!(css_classes.contains("opacity-100"));
500    }
501    
502    #[test]
503    fn test_mix_blend_mode_utilities() {
504        let classes = ClassBuilder::new()
505            .mix_blend_mode(MixBlendMode::Normal)
506            .mix_blend_mode(MixBlendMode::Multiply)
507            .mix_blend_mode(MixBlendMode::Screen)
508            .mix_blend_mode(MixBlendMode::Overlay)
509            .mix_blend_mode(MixBlendMode::Difference)
510            .build();
511        
512        let css_classes = classes.to_css_classes();
513        assert!(css_classes.contains("mix-blend-normal"));
514        assert!(css_classes.contains("mix-blend-multiply"));
515        assert!(css_classes.contains("mix-blend-screen"));
516        assert!(css_classes.contains("mix-blend-overlay"));
517        assert!(css_classes.contains("mix-blend-difference"));
518    }
519    
520    #[test]
521    fn test_background_blend_mode_utilities() {
522        let classes = ClassBuilder::new()
523            .background_blend_mode(BackgroundBlendMode::Normal)
524            .background_blend_mode(BackgroundBlendMode::Multiply)
525            .background_blend_mode(BackgroundBlendMode::Screen)
526            .background_blend_mode(BackgroundBlendMode::Overlay)
527            .background_blend_mode(BackgroundBlendMode::Difference)
528            .build();
529        
530        let css_classes = classes.to_css_classes();
531        assert!(css_classes.contains("bg-blend-normal"));
532        assert!(css_classes.contains("bg-blend-multiply"));
533        assert!(css_classes.contains("bg-blend-screen"));
534        assert!(css_classes.contains("bg-blend-overlay"));
535        assert!(css_classes.contains("bg-blend-difference"));
536    }
537    
538    #[test]
539    fn test_complex_effects_combination() {
540        let classes = ClassBuilder::new()
541            .box_shadow(BoxShadow::Lg)
542            .drop_shadow(DropShadow::Md)
543            .opacity(Opacity::Eighty)
544            .mix_blend_mode(MixBlendMode::Multiply)
545            .background_blend_mode(BackgroundBlendMode::Screen)
546            .build();
547        
548        let css_classes = classes.to_css_classes();
549        assert!(css_classes.contains("shadow-lg"));
550        assert!(css_classes.contains("drop-shadow-md"));
551        assert!(css_classes.contains("opacity-80"));
552        assert!(css_classes.contains("mix-blend-multiply"));
553        assert!(css_classes.contains("bg-blend-screen"));
554    }
555    
556    /// Test that all Week 9 shadow and opacity utilities are implemented
557    #[test]
558    fn test_week9_shadow_opacity_utilities() {
559        // Test all Week 9 shadow and opacity utilities
560        let classes = ClassBuilder::new()
561            // Box Shadows
562            .box_shadow(BoxShadow::Sm)
563            .box_shadow(BoxShadow::Default)
564            .box_shadow(BoxShadow::Md)
565            .box_shadow(BoxShadow::Lg)
566            .box_shadow(BoxShadow::Xl)
567            .box_shadow(BoxShadow::Xl2)
568            .box_shadow(BoxShadow::Inner)
569            .box_shadow(BoxShadow::None)
570            // Drop Shadows
571            .drop_shadow(DropShadow::Sm)
572            .drop_shadow(DropShadow::Default)
573            .drop_shadow(DropShadow::Md)
574            .drop_shadow(DropShadow::Lg)
575            .drop_shadow(DropShadow::Xl)
576            .drop_shadow(DropShadow::Xl2)
577            .drop_shadow(DropShadow::None)
578            // Opacity
579            .opacity(Opacity::Zero)
580            .opacity(Opacity::Five)
581            .opacity(Opacity::Ten)
582            .opacity(Opacity::Twenty)
583            .opacity(Opacity::TwentyFive)
584            .opacity(Opacity::Thirty)
585            .opacity(Opacity::Forty)
586            .opacity(Opacity::Fifty)
587            .opacity(Opacity::Sixty)
588            .opacity(Opacity::Seventy)
589            .opacity(Opacity::SeventyFive)
590            .opacity(Opacity::Eighty)
591            .opacity(Opacity::Ninety)
592            .opacity(Opacity::NinetyFive)
593            .opacity(Opacity::Hundred)
594            .build();
595        
596        let css_classes = classes.to_css_classes();
597        
598        // Box Shadows
599        assert!(css_classes.contains("shadow-sm"));
600        assert!(css_classes.contains("shadow"));
601        assert!(css_classes.contains("shadow-md"));
602        assert!(css_classes.contains("shadow-lg"));
603        assert!(css_classes.contains("shadow-xl"));
604        assert!(css_classes.contains("shadow-2xl"));
605        assert!(css_classes.contains("shadow-inner"));
606        assert!(css_classes.contains("shadow-none"));
607        
608        // Drop Shadows
609        assert!(css_classes.contains("drop-shadow-sm"));
610        assert!(css_classes.contains("drop-shadow"));
611        assert!(css_classes.contains("drop-shadow-md"));
612        assert!(css_classes.contains("drop-shadow-lg"));
613        assert!(css_classes.contains("drop-shadow-xl"));
614        assert!(css_classes.contains("drop-shadow-2xl"));
615        assert!(css_classes.contains("drop-shadow-none"));
616        
617        // Opacity
618        assert!(css_classes.contains("opacity-0"));
619        assert!(css_classes.contains("opacity-5"));
620        assert!(css_classes.contains("opacity-10"));
621        assert!(css_classes.contains("opacity-20"));
622        assert!(css_classes.contains("opacity-25"));
623        assert!(css_classes.contains("opacity-30"));
624        assert!(css_classes.contains("opacity-40"));
625        assert!(css_classes.contains("opacity-50"));
626        assert!(css_classes.contains("opacity-60"));
627        assert!(css_classes.contains("opacity-70"));
628        assert!(css_classes.contains("opacity-75"));
629        assert!(css_classes.contains("opacity-80"));
630        assert!(css_classes.contains("opacity-90"));
631        assert!(css_classes.contains("opacity-95"));
632        assert!(css_classes.contains("opacity-100"));
633    }
634}