tailwind_rs_core/utilities/
transforms.rs

1//! Transform utilities for tailwind-rs
2//!
3//! This module provides utilities for CSS transforms including scale, rotate,
4//! translate, skew, and transform origin.
5
6use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// Scale values
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum Scale {
13    /// 0% scale
14    Zero,
15    /// 50% scale
16    Fifty,
17    /// 75% scale
18    SeventyFive,
19    /// 90% scale
20    Ninety,
21    /// 95% scale
22    NinetyFive,
23    /// 100% scale
24    Hundred,
25    /// 105% scale
26    HundredFive,
27    /// 110% scale
28    HundredTen,
29    /// 125% scale
30    HundredTwentyFive,
31    /// 150% scale
32    HundredFifty,
33}
34
35/// Rotate values
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum Rotate {
38    /// 0 degrees
39    Zero,
40    /// 1 degree
41    One,
42    /// 2 degrees
43    Two,
44    /// 3 degrees
45    Three,
46    /// 6 degrees
47    Six,
48    /// 12 degrees
49    Twelve,
50    /// 45 degrees
51    FortyFive,
52    /// 90 degrees
53    Ninety,
54    /// 180 degrees
55    HundredEighty,
56}
57
58/// Translate values
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
60pub enum Translate {
61    /// 0px translate
62    Zero,
63    /// 1px translate
64    One,
65    /// 2px translate
66    Two,
67    /// 3px translate
68    Three,
69    /// 4px translate
70    Four,
71    /// 5px translate
72    Five,
73    /// 6px translate
74    Six,
75    /// 7px translate
76    Seven,
77    /// 8px translate
78    Eight,
79    /// 9px translate
80    Nine,
81    /// 10px translate
82    Ten,
83    /// 11px translate
84    Eleven,
85    /// 12px translate
86    Twelve,
87    /// 14px translate
88    Fourteen,
89    /// 16px translate
90    Sixteen,
91    /// 20px translate
92    Twenty,
93    /// 24px translate
94    TwentyFour,
95    /// 28px translate
96    TwentyEight,
97    /// 32px translate
98    ThirtyTwo,
99    /// 36px translate
100    ThirtySix,
101    /// 40px translate
102    Forty,
103    /// 44px translate
104    FortyFour,
105    /// 48px translate
106    FortyEight,
107    /// 52px translate
108    FiftyTwo,
109    /// 56px translate
110    FiftySix,
111    /// 60px translate
112    Sixty,
113    /// 64px translate
114    SixtyFour,
115    /// 72px translate
116    SeventyTwo,
117    /// 80px translate
118    Eighty,
119    /// 96px translate
120    NinetySix,
121}
122
123/// Skew values
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
125pub enum Skew {
126    /// 0 degrees
127    Zero,
128    /// 1 degree
129    One,
130    /// 2 degrees
131    Two,
132    /// 3 degrees
133    Three,
134    /// 6 degrees
135    Six,
136    /// 12 degrees
137    Twelve,
138}
139
140/// Transform origin values
141#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
142pub enum TransformOrigin {
143    /// Center origin
144    Center,
145    /// Top origin
146    Top,
147    /// Top right origin
148    TopRight,
149    /// Right origin
150    Right,
151    /// Bottom right origin
152    BottomRight,
153    /// Bottom origin
154    Bottom,
155    /// Bottom left origin
156    BottomLeft,
157    /// Left origin
158    Left,
159    /// Top left origin
160    TopLeft,
161}
162
163impl Scale {
164    pub fn to_class_name(&self) -> String {
165        match self {
166            Scale::Zero => "0".to_string(),
167            Scale::Fifty => "50".to_string(),
168            Scale::SeventyFive => "75".to_string(),
169            Scale::Ninety => "90".to_string(),
170            Scale::NinetyFive => "95".to_string(),
171            Scale::Hundred => "100".to_string(),
172            Scale::HundredFive => "105".to_string(),
173            Scale::HundredTen => "110".to_string(),
174            Scale::HundredTwentyFive => "125".to_string(),
175            Scale::HundredFifty => "150".to_string(),
176        }
177    }
178    
179    pub fn to_css_value(&self) -> String {
180        match self {
181            Scale::Zero => "0".to_string(),
182            Scale::Fifty => "0.5".to_string(),
183            Scale::SeventyFive => "0.75".to_string(),
184            Scale::Ninety => "0.9".to_string(),
185            Scale::NinetyFive => "0.95".to_string(),
186            Scale::Hundred => "1".to_string(),
187            Scale::HundredFive => "1.05".to_string(),
188            Scale::HundredTen => "1.1".to_string(),
189            Scale::HundredTwentyFive => "1.25".to_string(),
190            Scale::HundredFifty => "1.5".to_string(),
191        }
192    }
193}
194
195impl Rotate {
196    pub fn to_class_name(&self) -> String {
197        match self {
198            Rotate::Zero => "0".to_string(),
199            Rotate::One => "1".to_string(),
200            Rotate::Two => "2".to_string(),
201            Rotate::Three => "3".to_string(),
202            Rotate::Six => "6".to_string(),
203            Rotate::Twelve => "12".to_string(),
204            Rotate::FortyFive => "45".to_string(),
205            Rotate::Ninety => "90".to_string(),
206            Rotate::HundredEighty => "180".to_string(),
207        }
208    }
209    
210    pub fn to_css_value(&self) -> String {
211        match self {
212            Rotate::Zero => "0deg".to_string(),
213            Rotate::One => "1deg".to_string(),
214            Rotate::Two => "2deg".to_string(),
215            Rotate::Three => "3deg".to_string(),
216            Rotate::Six => "6deg".to_string(),
217            Rotate::Twelve => "12deg".to_string(),
218            Rotate::FortyFive => "45deg".to_string(),
219            Rotate::Ninety => "90deg".to_string(),
220            Rotate::HundredEighty => "180deg".to_string(),
221        }
222    }
223}
224
225impl Translate {
226    pub fn to_class_name(&self) -> String {
227        match self {
228            Translate::Zero => "0".to_string(),
229            Translate::One => "1".to_string(),
230            Translate::Two => "2".to_string(),
231            Translate::Three => "3".to_string(),
232            Translate::Four => "4".to_string(),
233            Translate::Five => "5".to_string(),
234            Translate::Six => "6".to_string(),
235            Translate::Seven => "7".to_string(),
236            Translate::Eight => "8".to_string(),
237            Translate::Nine => "9".to_string(),
238            Translate::Ten => "10".to_string(),
239            Translate::Eleven => "11".to_string(),
240            Translate::Twelve => "12".to_string(),
241            Translate::Fourteen => "14".to_string(),
242            Translate::Sixteen => "16".to_string(),
243            Translate::Twenty => "20".to_string(),
244            Translate::TwentyFour => "24".to_string(),
245            Translate::TwentyEight => "28".to_string(),
246            Translate::ThirtyTwo => "32".to_string(),
247            Translate::ThirtySix => "36".to_string(),
248            Translate::Forty => "40".to_string(),
249            Translate::FortyFour => "44".to_string(),
250            Translate::FortyEight => "48".to_string(),
251            Translate::FiftyTwo => "52".to_string(),
252            Translate::FiftySix => "56".to_string(),
253            Translate::Sixty => "60".to_string(),
254            Translate::SixtyFour => "64".to_string(),
255            Translate::SeventyTwo => "72".to_string(),
256            Translate::Eighty => "80".to_string(),
257            Translate::NinetySix => "96".to_string(),
258        }
259    }
260    
261    pub fn to_css_value(&self) -> String {
262        match self {
263            Translate::Zero => "0px".to_string(),
264            Translate::One => "0.25rem".to_string(),
265            Translate::Two => "0.5rem".to_string(),
266            Translate::Three => "0.75rem".to_string(),
267            Translate::Four => "1rem".to_string(),
268            Translate::Five => "1.25rem".to_string(),
269            Translate::Six => "1.5rem".to_string(),
270            Translate::Seven => "1.75rem".to_string(),
271            Translate::Eight => "2rem".to_string(),
272            Translate::Nine => "2.25rem".to_string(),
273            Translate::Ten => "2.5rem".to_string(),
274            Translate::Eleven => "2.75rem".to_string(),
275            Translate::Twelve => "3rem".to_string(),
276            Translate::Fourteen => "3.5rem".to_string(),
277            Translate::Sixteen => "4rem".to_string(),
278            Translate::Twenty => "5rem".to_string(),
279            Translate::TwentyFour => "6rem".to_string(),
280            Translate::TwentyEight => "7rem".to_string(),
281            Translate::ThirtyTwo => "8rem".to_string(),
282            Translate::ThirtySix => "9rem".to_string(),
283            Translate::Forty => "10rem".to_string(),
284            Translate::FortyFour => "11rem".to_string(),
285            Translate::FortyEight => "12rem".to_string(),
286            Translate::FiftyTwo => "13rem".to_string(),
287            Translate::FiftySix => "14rem".to_string(),
288            Translate::Sixty => "15rem".to_string(),
289            Translate::SixtyFour => "16rem".to_string(),
290            Translate::SeventyTwo => "18rem".to_string(),
291            Translate::Eighty => "20rem".to_string(),
292            Translate::NinetySix => "24rem".to_string(),
293        }
294    }
295}
296
297impl Skew {
298    pub fn to_class_name(&self) -> String {
299        match self {
300            Skew::Zero => "0".to_string(),
301            Skew::One => "1".to_string(),
302            Skew::Two => "2".to_string(),
303            Skew::Three => "3".to_string(),
304            Skew::Six => "6".to_string(),
305            Skew::Twelve => "12".to_string(),
306        }
307    }
308    
309    pub fn to_css_value(&self) -> String {
310        match self {
311            Skew::Zero => "0deg".to_string(),
312            Skew::One => "1deg".to_string(),
313            Skew::Two => "2deg".to_string(),
314            Skew::Three => "3deg".to_string(),
315            Skew::Six => "6deg".to_string(),
316            Skew::Twelve => "12deg".to_string(),
317        }
318    }
319}
320
321impl TransformOrigin {
322    pub fn to_class_name(&self) -> String {
323        match self {
324            TransformOrigin::Center => "center".to_string(),
325            TransformOrigin::Top => "top".to_string(),
326            TransformOrigin::TopRight => "top-right".to_string(),
327            TransformOrigin::Right => "right".to_string(),
328            TransformOrigin::BottomRight => "bottom-right".to_string(),
329            TransformOrigin::Bottom => "bottom".to_string(),
330            TransformOrigin::BottomLeft => "bottom-left".to_string(),
331            TransformOrigin::Left => "left".to_string(),
332            TransformOrigin::TopLeft => "top-left".to_string(),
333        }
334    }
335    
336    pub fn to_css_value(&self) -> String {
337        match self {
338            TransformOrigin::Center => "center".to_string(),
339            TransformOrigin::Top => "top".to_string(),
340            TransformOrigin::TopRight => "top right".to_string(),
341            TransformOrigin::Right => "right".to_string(),
342            TransformOrigin::BottomRight => "bottom right".to_string(),
343            TransformOrigin::Bottom => "bottom".to_string(),
344            TransformOrigin::BottomLeft => "bottom left".to_string(),
345            TransformOrigin::Left => "left".to_string(),
346            TransformOrigin::TopLeft => "top left".to_string(),
347        }
348    }
349}
350
351impl fmt::Display for Scale {
352    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353        write!(f, "{}", self.to_class_name())
354    }
355}
356
357impl fmt::Display for Rotate {
358    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359        write!(f, "{}", self.to_class_name())
360    }
361}
362
363impl fmt::Display for Translate {
364    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
365        write!(f, "{}", self.to_class_name())
366    }
367}
368
369impl fmt::Display for Skew {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        write!(f, "{}", self.to_class_name())
372    }
373}
374
375impl fmt::Display for TransformOrigin {
376    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
377        write!(f, "{}", self.to_class_name())
378    }
379}
380
381/// Trait for adding scale utilities to a class builder
382pub trait ScaleUtilities {
383    fn scale(self, scale: Scale) -> Self;
384    fn scale_x(self, scale: Scale) -> Self;
385    fn scale_y(self, scale: Scale) -> Self;
386}
387
388impl ScaleUtilities for ClassBuilder {
389    fn scale(self, scale: Scale) -> Self {
390        self.class(format!("scale-{}", scale.to_class_name()))
391    }
392    
393    fn scale_x(self, scale: Scale) -> Self {
394        self.class(format!("scale-x-{}", scale.to_class_name()))
395    }
396    
397    fn scale_y(self, scale: Scale) -> Self {
398        self.class(format!("scale-y-{}", scale.to_class_name()))
399    }
400}
401
402/// Trait for adding rotate utilities to a class builder
403pub trait RotateUtilities {
404    fn rotate(self, rotate: Rotate) -> Self;
405}
406
407impl RotateUtilities for ClassBuilder {
408    fn rotate(self, rotate: Rotate) -> Self {
409        self.class(format!("rotate-{}", rotate.to_class_name()))
410    }
411}
412
413/// Trait for adding translate utilities to a class builder
414pub trait TranslateUtilities {
415    fn translate_x(self, translate: Translate) -> Self;
416    fn translate_y(self, translate: Translate) -> Self;
417}
418
419impl TranslateUtilities for ClassBuilder {
420    fn translate_x(self, translate: Translate) -> Self {
421        self.class(format!("translate-x-{}", translate.to_class_name()))
422    }
423    
424    fn translate_y(self, translate: Translate) -> Self {
425        self.class(format!("translate-y-{}", translate.to_class_name()))
426    }
427}
428
429/// Trait for adding skew utilities to a class builder
430pub trait SkewUtilities {
431    fn skew_x(self, skew: Skew) -> Self;
432    fn skew_y(self, skew: Skew) -> Self;
433}
434
435impl SkewUtilities for ClassBuilder {
436    fn skew_x(self, skew: Skew) -> Self {
437        self.class(format!("skew-x-{}", skew.to_class_name()))
438    }
439    
440    fn skew_y(self, skew: Skew) -> Self {
441        self.class(format!("skew-y-{}", skew.to_class_name()))
442    }
443}
444
445/// Trait for adding transform origin utilities to a class builder
446pub trait TransformOriginUtilities {
447    fn transform_origin(self, origin: TransformOrigin) -> Self;
448}
449
450impl TransformOriginUtilities for ClassBuilder {
451    fn transform_origin(self, origin: TransformOrigin) -> Self {
452        self.class(format!("origin-{}", origin.to_class_name()))
453    }
454}
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459    
460    #[test]
461    fn test_scale_utilities() {
462        let classes = ClassBuilder::new()
463            .scale(Scale::Zero)
464            .scale(Scale::Fifty)
465            .scale(Scale::SeventyFive)
466            .scale(Scale::Ninety)
467            .scale(Scale::NinetyFive)
468            .scale(Scale::Hundred)
469            .scale(Scale::HundredFive)
470            .scale(Scale::HundredTen)
471            .scale(Scale::HundredTwentyFive)
472            .scale(Scale::HundredFifty)
473            .scale_x(Scale::Hundred)
474            .scale_y(Scale::Hundred)
475            .build();
476        
477        let css_classes = classes.to_css_classes();
478        assert!(css_classes.contains("scale-0"));
479        assert!(css_classes.contains("scale-50"));
480        assert!(css_classes.contains("scale-75"));
481        assert!(css_classes.contains("scale-90"));
482        assert!(css_classes.contains("scale-95"));
483        assert!(css_classes.contains("scale-100"));
484        assert!(css_classes.contains("scale-105"));
485        assert!(css_classes.contains("scale-110"));
486        assert!(css_classes.contains("scale-125"));
487        assert!(css_classes.contains("scale-150"));
488        assert!(css_classes.contains("scale-x-100"));
489        assert!(css_classes.contains("scale-y-100"));
490    }
491    
492    #[test]
493    fn test_rotate_utilities() {
494        let classes = ClassBuilder::new()
495            .rotate(Rotate::Zero)
496            .rotate(Rotate::One)
497            .rotate(Rotate::Two)
498            .rotate(Rotate::Three)
499            .rotate(Rotate::Six)
500            .rotate(Rotate::Twelve)
501            .rotate(Rotate::FortyFive)
502            .rotate(Rotate::Ninety)
503            .rotate(Rotate::HundredEighty)
504            .build();
505        
506        let css_classes = classes.to_css_classes();
507        assert!(css_classes.contains("rotate-0"));
508        assert!(css_classes.contains("rotate-1"));
509        assert!(css_classes.contains("rotate-2"));
510        assert!(css_classes.contains("rotate-3"));
511        assert!(css_classes.contains("rotate-6"));
512        assert!(css_classes.contains("rotate-12"));
513        assert!(css_classes.contains("rotate-45"));
514        assert!(css_classes.contains("rotate-90"));
515        assert!(css_classes.contains("rotate-180"));
516    }
517    
518    #[test]
519    fn test_translate_utilities() {
520        let classes = ClassBuilder::new()
521            .translate_x(Translate::Zero)
522            .translate_x(Translate::One)
523            .translate_x(Translate::Two)
524            .translate_x(Translate::Three)
525            .translate_x(Translate::Four)
526            .translate_x(Translate::Five)
527            .translate_x(Translate::Six)
528            .translate_x(Translate::Seven)
529            .translate_x(Translate::Eight)
530            .translate_x(Translate::Nine)
531            .translate_x(Translate::Ten)
532            .translate_y(Translate::Zero)
533            .translate_y(Translate::One)
534            .translate_y(Translate::Two)
535            .translate_y(Translate::Three)
536            .translate_y(Translate::Four)
537            .translate_y(Translate::Five)
538            .translate_y(Translate::Six)
539            .translate_y(Translate::Seven)
540            .translate_y(Translate::Eight)
541            .translate_y(Translate::Nine)
542            .translate_y(Translate::Ten)
543            .build();
544        
545        let css_classes = classes.to_css_classes();
546        assert!(css_classes.contains("translate-x-0"));
547        assert!(css_classes.contains("translate-x-1"));
548        assert!(css_classes.contains("translate-x-2"));
549        assert!(css_classes.contains("translate-x-3"));
550        assert!(css_classes.contains("translate-x-4"));
551        assert!(css_classes.contains("translate-x-5"));
552        assert!(css_classes.contains("translate-x-6"));
553        assert!(css_classes.contains("translate-x-7"));
554        assert!(css_classes.contains("translate-x-8"));
555        assert!(css_classes.contains("translate-x-9"));
556        assert!(css_classes.contains("translate-x-10"));
557        assert!(css_classes.contains("translate-y-0"));
558        assert!(css_classes.contains("translate-y-1"));
559        assert!(css_classes.contains("translate-y-2"));
560        assert!(css_classes.contains("translate-y-3"));
561        assert!(css_classes.contains("translate-y-4"));
562        assert!(css_classes.contains("translate-y-5"));
563        assert!(css_classes.contains("translate-y-6"));
564        assert!(css_classes.contains("translate-y-7"));
565        assert!(css_classes.contains("translate-y-8"));
566        assert!(css_classes.contains("translate-y-9"));
567        assert!(css_classes.contains("translate-y-10"));
568    }
569    
570    #[test]
571    fn test_skew_utilities() {
572        let classes = ClassBuilder::new()
573            .skew_x(Skew::Zero)
574            .skew_x(Skew::One)
575            .skew_x(Skew::Two)
576            .skew_x(Skew::Three)
577            .skew_x(Skew::Six)
578            .skew_x(Skew::Twelve)
579            .skew_y(Skew::Zero)
580            .skew_y(Skew::One)
581            .skew_y(Skew::Two)
582            .skew_y(Skew::Three)
583            .skew_y(Skew::Six)
584            .skew_y(Skew::Twelve)
585            .build();
586        
587        let css_classes = classes.to_css_classes();
588        assert!(css_classes.contains("skew-x-0"));
589        assert!(css_classes.contains("skew-x-1"));
590        assert!(css_classes.contains("skew-x-2"));
591        assert!(css_classes.contains("skew-x-3"));
592        assert!(css_classes.contains("skew-x-6"));
593        assert!(css_classes.contains("skew-x-12"));
594        assert!(css_classes.contains("skew-y-0"));
595        assert!(css_classes.contains("skew-y-1"));
596        assert!(css_classes.contains("skew-y-2"));
597        assert!(css_classes.contains("skew-y-3"));
598        assert!(css_classes.contains("skew-y-6"));
599        assert!(css_classes.contains("skew-y-12"));
600    }
601    
602    #[test]
603    fn test_transform_origin_utilities() {
604        let classes = ClassBuilder::new()
605            .transform_origin(TransformOrigin::Center)
606            .transform_origin(TransformOrigin::Top)
607            .transform_origin(TransformOrigin::TopRight)
608            .transform_origin(TransformOrigin::Right)
609            .transform_origin(TransformOrigin::BottomRight)
610            .transform_origin(TransformOrigin::Bottom)
611            .transform_origin(TransformOrigin::BottomLeft)
612            .transform_origin(TransformOrigin::Left)
613            .transform_origin(TransformOrigin::TopLeft)
614            .build();
615        
616        let css_classes = classes.to_css_classes();
617        assert!(css_classes.contains("origin-center"));
618        assert!(css_classes.contains("origin-top"));
619        assert!(css_classes.contains("origin-top-right"));
620        assert!(css_classes.contains("origin-right"));
621        assert!(css_classes.contains("origin-bottom-right"));
622        assert!(css_classes.contains("origin-bottom"));
623        assert!(css_classes.contains("origin-bottom-left"));
624        assert!(css_classes.contains("origin-left"));
625        assert!(css_classes.contains("origin-top-left"));
626    }
627    
628    #[test]
629    fn test_complex_transforms_combination() {
630        let classes = ClassBuilder::new()
631            .scale(Scale::HundredTen)
632            .scale_x(Scale::HundredFive)
633            .scale_y(Scale::HundredFive)
634            .rotate(Rotate::FortyFive)
635            .translate_x(Translate::Four)
636            .translate_y(Translate::Four)
637            .skew_x(Skew::Two)
638            .skew_y(Skew::Two)
639            .transform_origin(TransformOrigin::Center)
640            .build();
641        
642        let css_classes = classes.to_css_classes();
643        assert!(css_classes.contains("scale-110"));
644        assert!(css_classes.contains("scale-x-105"));
645        assert!(css_classes.contains("scale-y-105"));
646        assert!(css_classes.contains("rotate-45"));
647        assert!(css_classes.contains("translate-x-4"));
648        assert!(css_classes.contains("translate-y-4"));
649        assert!(css_classes.contains("skew-x-2"));
650        assert!(css_classes.contains("skew-y-2"));
651        assert!(css_classes.contains("origin-center"));
652    }
653    
654    /// Test that all Week 11 transform utilities are implemented
655    #[test]
656    fn test_week11_transform_utilities() {
657        // Test all Week 11 transform utilities
658        let classes = ClassBuilder::new()
659            // Scale
660            .scale(Scale::Zero)
661            .scale(Scale::Fifty)
662            .scale(Scale::SeventyFive)
663            .scale(Scale::Ninety)
664            .scale(Scale::NinetyFive)
665            .scale(Scale::Hundred)
666            .scale(Scale::HundredFive)
667            .scale(Scale::HundredTen)
668            .scale(Scale::HundredTwentyFive)
669            .scale(Scale::HundredFifty)
670            .scale_x(Scale::Hundred)
671            .scale_y(Scale::Hundred)
672            // Rotate
673            .rotate(Rotate::Zero)
674            .rotate(Rotate::One)
675            .rotate(Rotate::Two)
676            .rotate(Rotate::Three)
677            .rotate(Rotate::Six)
678            .rotate(Rotate::Twelve)
679            .rotate(Rotate::FortyFive)
680            .rotate(Rotate::Ninety)
681            .rotate(Rotate::HundredEighty)
682            // Translate
683            .translate_x(Translate::Zero)
684            .translate_x(Translate::Four)
685            .translate_y(Translate::Two)
686            .translate_y(Translate::Eight)
687            .build();
688        
689        let css_classes = classes.to_css_classes();
690        
691        // Scale
692        assert!(css_classes.contains("scale-0"));
693        assert!(css_classes.contains("scale-50"));
694        assert!(css_classes.contains("scale-75"));
695        assert!(css_classes.contains("scale-90"));
696        assert!(css_classes.contains("scale-95"));
697        assert!(css_classes.contains("scale-100"));
698        assert!(css_classes.contains("scale-105"));
699        assert!(css_classes.contains("scale-110"));
700        assert!(css_classes.contains("scale-125"));
701        assert!(css_classes.contains("scale-150"));
702        assert!(css_classes.contains("scale-x-100"));
703        assert!(css_classes.contains("scale-y-100"));
704        
705        // Rotate
706        assert!(css_classes.contains("rotate-0"));
707        assert!(css_classes.contains("rotate-1"));
708        assert!(css_classes.contains("rotate-2"));
709        assert!(css_classes.contains("rotate-3"));
710        assert!(css_classes.contains("rotate-6"));
711        assert!(css_classes.contains("rotate-12"));
712        assert!(css_classes.contains("rotate-45"));
713        assert!(css_classes.contains("rotate-90"));
714        assert!(css_classes.contains("rotate-180"));
715        
716        // Translate
717        assert!(css_classes.contains("translate-x-0"));
718        assert!(css_classes.contains("translate-x-4"));
719        assert!(css_classes.contains("translate-y-2"));
720        assert!(css_classes.contains("translate-y-8"));
721    }
722}