tailwind_rs_core/utilities/
typography.rs

1//! Typography utilities for tailwind-rs
2//!
3//! This module provides utilities for font families, font sizes, font weights,
4//! text alignment, line height, letter spacing, and other typography-related properties.
5
6use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10/// Font family values
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum FontFamily {
13    /// Sans-serif font family
14    Sans,
15    /// Serif font family
16    Serif,
17    /// Monospace font family
18    Mono,
19}
20
21/// Font size values
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum FontSize {
24    /// Extra small font size
25    Xs,
26    /// Small font size
27    Sm,
28    /// Base font size
29    Base,
30    /// Large font size
31    Lg,
32    /// Extra large font size
33    Xl,
34    /// 2x large font size
35    Xl2,
36    /// 3x large font size
37    Xl3,
38    /// 4x large font size
39    Xl4,
40    /// 5x large font size
41    Xl5,
42    /// 6x large font size
43    Xl6,
44    /// 7x large font size
45    Xl7,
46    /// 8x large font size
47    Xl8,
48    /// 9x large font size
49    Xl9,
50}
51
52/// Font weight values
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54pub enum FontWeight {
55    /// Thin font weight (100)
56    Thin,
57    /// Extra light font weight (200)
58    ExtraLight,
59    /// Light font weight (300)
60    Light,
61    /// Normal font weight (400)
62    Normal,
63    /// Medium font weight (500)
64    Medium,
65    /// Semi-bold font weight (600)
66    SemiBold,
67    /// Bold font weight (700)
68    Bold,
69    /// Extra bold font weight (800)
70    ExtraBold,
71    /// Black font weight (900)
72    Black,
73}
74
75/// Text alignment values
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
77pub enum TextAlign {
78    /// Left align
79    Left,
80    /// Center align
81    Center,
82    /// Right align
83    Right,
84    /// Justify align
85    Justify,
86    /// Start align (left in LTR, right in RTL)
87    Start,
88    /// End align (right in LTR, left in RTL)
89    End,
90}
91
92/// Line height values
93#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
94pub enum LineHeight {
95    /// None line height
96    None,
97    /// leading-3 (0.75rem / 12px)
98    Three,
99    /// leading-4 (1rem / 16px)
100    Four,
101    /// leading-5 (1.25rem / 20px)
102    Five,
103    /// leading-6 (1.5rem / 24px)
104    Six,
105    /// leading-7 (1.75rem / 28px)
106    Seven,
107    /// leading-8 (2rem / 32px)
108    Eight,
109    /// leading-9 (2.25rem / 36px)
110    Nine,
111    /// leading-10 (2.5rem / 40px)
112    Ten,
113    /// Tight line height
114    Tight,
115    /// Snug line height
116    Snug,
117    /// Normal line height
118    Normal,
119    /// Relaxed line height
120    Relaxed,
121    /// Loose line height
122    Loose,
123    /// Custom line height (f32)
124    Custom(f32),
125}
126
127/// Letter spacing values
128#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
129pub enum LetterSpacing {
130    /// Tighter letter spacing
131    Tighter,
132    /// Tight letter spacing
133    Tight,
134    /// Normal letter spacing
135    Normal,
136    /// Wide letter spacing
137    Wide,
138    /// Wider letter spacing
139    Wider,
140    /// Widest letter spacing
141    Widest,
142    /// Custom letter spacing (f32)
143    Custom(f32),
144}
145
146/// Text decoration values
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
148pub enum TextDecoration {
149    /// No decoration
150    None,
151    /// Underline decoration
152    Underline,
153    /// Overline decoration
154    Overline,
155    /// Line-through decoration
156    LineThrough,
157}
158
159/// Text decoration style values
160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
161pub enum TextDecorationStyle {
162    /// Solid decoration style
163    Solid,
164    /// Double decoration style
165    Double,
166    /// Dotted decoration style
167    Dotted,
168    /// Dashed decoration style
169    Dashed,
170    /// Wavy decoration style
171    Wavy,
172}
173
174/// Text decoration thickness values
175#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
176pub enum TextDecorationThickness {
177    /// Auto thickness
178    Auto,
179    /// From font thickness
180    FromFont,
181    /// 0px thickness
182    Zero,
183    /// 1px thickness
184    One,
185    /// 2px thickness
186    Two,
187    /// 4px thickness
188    Four,
189    /// 8px thickness
190    Eight,
191}
192
193/// Text underline offset values
194#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
195pub enum TextUnderlineOffset {
196    /// Auto offset
197    Auto,
198    /// 0px offset
199    Zero,
200    /// 1px offset
201    One,
202    /// 2px offset
203    Two,
204    /// 4px offset
205    Four,
206    /// 8px offset
207    Eight,
208}
209
210/// Text transform values
211#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
212pub enum TextTransform {
213    /// No transform
214    None,
215    /// Uppercase transform
216    Uppercase,
217    /// Lowercase transform
218    Lowercase,
219    /// Capitalize transform
220    Capitalize,
221}
222
223/// Text overflow values
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
225pub enum TextOverflow {
226    /// Truncate text overflow
227    Truncate,
228    /// Ellipsis text overflow
229    Ellipsis,
230    /// Clip text overflow
231    Clip,
232}
233
234/// White space values
235#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
236pub enum WhiteSpace {
237    /// Normal white space
238    Normal,
239    /// Nowrap white space
240    Nowrap,
241    /// Pre white space
242    Pre,
243    /// Pre-line white space
244    PreLine,
245    /// Pre-wrap white space
246    PreWrap,
247    /// Break-spaces white space
248    BreakSpaces,
249}
250
251/// Word break values
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
253pub enum WordBreak {
254    /// Normal word break
255    Normal,
256    /// Break-all word break
257    BreakAll,
258    /// Break-words word break
259    BreakWords,
260    /// Keep-all word break
261    KeepAll,
262}
263
264impl std::hash::Hash for LineHeight {
265    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
266        match self {
267            LineHeight::None => 0u8.hash(state),
268            LineHeight::Three => 1u8.hash(state),
269            LineHeight::Four => 2u8.hash(state),
270            LineHeight::Five => 3u8.hash(state),
271            LineHeight::Six => 4u8.hash(state),
272            LineHeight::Seven => 5u8.hash(state),
273            LineHeight::Eight => 6u8.hash(state),
274            LineHeight::Nine => 7u8.hash(state),
275            LineHeight::Ten => 8u8.hash(state),
276            LineHeight::Tight => 9u8.hash(state),
277            LineHeight::Snug => 10u8.hash(state),
278            LineHeight::Normal => 11u8.hash(state),
279            LineHeight::Relaxed => 12u8.hash(state),
280            LineHeight::Loose => 13u8.hash(state),
281            LineHeight::Custom(f) => {
282                14u8.hash(state);
283                ((f * 1000.0) as u32).hash(state);
284            }
285        }
286    }
287}
288
289impl std::hash::Hash for LetterSpacing {
290    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
291        match self {
292            LetterSpacing::Tighter => 0u8.hash(state),
293            LetterSpacing::Tight => 1u8.hash(state),
294            LetterSpacing::Normal => 2u8.hash(state),
295            LetterSpacing::Wide => 3u8.hash(state),
296            LetterSpacing::Wider => 4u8.hash(state),
297            LetterSpacing::Widest => 5u8.hash(state),
298            LetterSpacing::Custom(f) => {
299                6u8.hash(state);
300                ((f * 1000.0) as u32).hash(state);
301            }
302        }
303    }
304}
305
306impl std::cmp::Eq for LineHeight {}
307impl std::cmp::Eq for LetterSpacing {}
308
309impl FontFamily {
310    pub fn to_class_name(&self) -> String {
311        match self {
312            FontFamily::Sans => "sans".to_string(),
313            FontFamily::Serif => "serif".to_string(),
314            FontFamily::Mono => "mono".to_string(),
315        }
316    }
317    
318    pub fn to_css_value(&self) -> String {
319        match self {
320            FontFamily::Sans => "ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"".to_string(),
321            FontFamily::Serif => "ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif".to_string(),
322            FontFamily::Mono => "ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace".to_string(),
323        }
324    }
325}
326
327impl FontSize {
328    pub fn to_class_name(&self) -> String {
329        match self {
330            FontSize::Xs => "xs".to_string(),
331            FontSize::Sm => "sm".to_string(),
332            FontSize::Base => "base".to_string(),
333            FontSize::Lg => "lg".to_string(),
334            FontSize::Xl => "xl".to_string(),
335            FontSize::Xl2 => "2xl".to_string(),
336            FontSize::Xl3 => "3xl".to_string(),
337            FontSize::Xl4 => "4xl".to_string(),
338            FontSize::Xl5 => "5xl".to_string(),
339            FontSize::Xl6 => "6xl".to_string(),
340            FontSize::Xl7 => "7xl".to_string(),
341            FontSize::Xl8 => "8xl".to_string(),
342            FontSize::Xl9 => "9xl".to_string(),
343        }
344    }
345    
346    pub fn to_css_value(&self) -> String {
347        match self {
348            FontSize::Xs => "0.75rem".to_string(),
349            FontSize::Sm => "0.875rem".to_string(),
350            FontSize::Base => "1rem".to_string(),
351            FontSize::Lg => "1.125rem".to_string(),
352            FontSize::Xl => "1.25rem".to_string(),
353            FontSize::Xl2 => "1.5rem".to_string(),
354            FontSize::Xl3 => "1.875rem".to_string(),
355            FontSize::Xl4 => "2.25rem".to_string(),
356            FontSize::Xl5 => "3rem".to_string(),
357            FontSize::Xl6 => "3.75rem".to_string(),
358            FontSize::Xl7 => "4.5rem".to_string(),
359            FontSize::Xl8 => "6rem".to_string(),
360            FontSize::Xl9 => "8rem".to_string(),
361        }
362    }
363}
364
365impl FontWeight {
366    pub fn to_class_name(&self) -> String {
367        match self {
368            FontWeight::Thin => "thin".to_string(),
369            FontWeight::ExtraLight => "extralight".to_string(),
370            FontWeight::Light => "light".to_string(),
371            FontWeight::Normal => "normal".to_string(),
372            FontWeight::Medium => "medium".to_string(),
373            FontWeight::SemiBold => "semibold".to_string(),
374            FontWeight::Bold => "bold".to_string(),
375            FontWeight::ExtraBold => "extrabold".to_string(),
376            FontWeight::Black => "black".to_string(),
377        }
378    }
379    
380    pub fn to_css_value(&self) -> String {
381        match self {
382            FontWeight::Thin => "100".to_string(),
383            FontWeight::ExtraLight => "200".to_string(),
384            FontWeight::Light => "300".to_string(),
385            FontWeight::Normal => "400".to_string(),
386            FontWeight::Medium => "500".to_string(),
387            FontWeight::SemiBold => "600".to_string(),
388            FontWeight::Bold => "700".to_string(),
389            FontWeight::ExtraBold => "800".to_string(),
390            FontWeight::Black => "900".to_string(),
391        }
392    }
393}
394
395impl TextAlign {
396    pub fn to_class_name(&self) -> String {
397        match self {
398            TextAlign::Left => "left".to_string(),
399            TextAlign::Center => "center".to_string(),
400            TextAlign::Right => "right".to_string(),
401            TextAlign::Justify => "justify".to_string(),
402            TextAlign::Start => "start".to_string(),
403            TextAlign::End => "end".to_string(),
404        }
405    }
406    
407    pub fn to_css_value(&self) -> String {
408        match self {
409            TextAlign::Left => "left".to_string(),
410            TextAlign::Center => "center".to_string(),
411            TextAlign::Right => "right".to_string(),
412            TextAlign::Justify => "justify".to_string(),
413            TextAlign::Start => "start".to_string(),
414            TextAlign::End => "end".to_string(),
415        }
416    }
417}
418
419impl LineHeight {
420    pub fn to_class_name(&self) -> String {
421        match self {
422            LineHeight::None => "none".to_string(),
423            LineHeight::Three => "3".to_string(),
424            LineHeight::Four => "4".to_string(),
425            LineHeight::Five => "5".to_string(),
426            LineHeight::Six => "6".to_string(),
427            LineHeight::Seven => "7".to_string(),
428            LineHeight::Eight => "8".to_string(),
429            LineHeight::Nine => "9".to_string(),
430            LineHeight::Ten => "10".to_string(),
431            LineHeight::Tight => "tight".to_string(),
432            LineHeight::Snug => "snug".to_string(),
433            LineHeight::Normal => "normal".to_string(),
434            LineHeight::Relaxed => "relaxed".to_string(),
435            LineHeight::Loose => "loose".to_string(),
436            LineHeight::Custom(f) => format!("{}", f),
437        }
438    }
439
440    pub fn to_css_value(&self) -> String {
441        match self {
442            LineHeight::None => "1".to_string(),
443            LineHeight::Three => "0.75rem".to_string(),
444            LineHeight::Four => "1rem".to_string(),
445            LineHeight::Five => "1.25rem".to_string(),
446            LineHeight::Six => "1.5rem".to_string(),
447            LineHeight::Seven => "1.75rem".to_string(),
448            LineHeight::Eight => "2rem".to_string(),
449            LineHeight::Nine => "2.25rem".to_string(),
450            LineHeight::Ten => "2.5rem".to_string(),
451            LineHeight::Tight => "1.25".to_string(),
452            LineHeight::Snug => "1.375".to_string(),
453            LineHeight::Normal => "1.5".to_string(),
454            LineHeight::Relaxed => "1.625".to_string(),
455            LineHeight::Loose => "2".to_string(),
456            LineHeight::Custom(f) => f.to_string(),
457        }
458    }
459
460    /// Get all available line height values
461    pub fn all_values() -> Vec<LineHeight> {
462        vec![
463            LineHeight::None,
464            LineHeight::Three,
465            LineHeight::Four,
466            LineHeight::Five,
467            LineHeight::Six,
468            LineHeight::Seven,
469            LineHeight::Eight,
470            LineHeight::Nine,
471            LineHeight::Ten,
472            LineHeight::Tight,
473            LineHeight::Snug,
474            LineHeight::Normal,
475            LineHeight::Relaxed,
476            LineHeight::Loose,
477        ]
478    }
479}
480
481impl LetterSpacing {
482    pub fn to_class_name(&self) -> String {
483        match self {
484            LetterSpacing::Tighter => "tighter".to_string(),
485            LetterSpacing::Tight => "tight".to_string(),
486            LetterSpacing::Normal => "normal".to_string(),
487            LetterSpacing::Wide => "wide".to_string(),
488            LetterSpacing::Wider => "wider".to_string(),
489            LetterSpacing::Widest => "widest".to_string(),
490            LetterSpacing::Custom(f) => format!("{}", f),
491        }
492    }
493    
494    pub fn to_css_value(&self) -> String {
495        match self {
496            LetterSpacing::Tighter => "-0.05em".to_string(),
497            LetterSpacing::Tight => "-0.025em".to_string(),
498            LetterSpacing::Normal => "0em".to_string(),
499            LetterSpacing::Wide => "0.025em".to_string(),
500            LetterSpacing::Wider => "0.05em".to_string(),
501            LetterSpacing::Widest => "0.1em".to_string(),
502            LetterSpacing::Custom(f) => format!("{}em", f),
503        }
504    }
505}
506
507impl TextDecoration {
508    pub fn to_class_name(&self) -> String {
509        match self {
510            TextDecoration::None => "no-underline".to_string(),
511            TextDecoration::Underline => "underline".to_string(),
512            TextDecoration::Overline => "overline".to_string(),
513            TextDecoration::LineThrough => "line-through".to_string(),
514        }
515    }
516
517    pub fn to_css_value(&self) -> String {
518        match self {
519            TextDecoration::None => "none".to_string(),
520            TextDecoration::Underline => "underline".to_string(),
521            TextDecoration::Overline => "overline".to_string(),
522            TextDecoration::LineThrough => "line-through".to_string(),
523        }
524    }
525}
526
527impl TextDecorationStyle {
528    pub fn to_class_name(&self) -> String {
529        match self {
530            TextDecorationStyle::Solid => "decoration-solid".to_string(),
531            TextDecorationStyle::Double => "decoration-double".to_string(),
532            TextDecorationStyle::Dotted => "decoration-dotted".to_string(),
533            TextDecorationStyle::Dashed => "decoration-dashed".to_string(),
534            TextDecorationStyle::Wavy => "decoration-wavy".to_string(),
535        }
536    }
537
538    pub fn to_css_value(&self) -> String {
539        match self {
540            TextDecorationStyle::Solid => "solid".to_string(),
541            TextDecorationStyle::Double => "double".to_string(),
542            TextDecorationStyle::Dotted => "dotted".to_string(),
543            TextDecorationStyle::Dashed => "dashed".to_string(),
544            TextDecorationStyle::Wavy => "wavy".to_string(),
545        }
546    }
547}
548
549impl TextDecorationThickness {
550    pub fn to_class_name(&self) -> String {
551        match self {
552            TextDecorationThickness::Auto => "decoration-auto".to_string(),
553            TextDecorationThickness::FromFont => "decoration-from-font".to_string(),
554            TextDecorationThickness::Zero => "decoration-0".to_string(),
555            TextDecorationThickness::One => "decoration-1".to_string(),
556            TextDecorationThickness::Two => "decoration-2".to_string(),
557            TextDecorationThickness::Four => "decoration-4".to_string(),
558            TextDecorationThickness::Eight => "decoration-8".to_string(),
559        }
560    }
561
562    pub fn to_css_value(&self) -> String {
563        match self {
564            TextDecorationThickness::Auto => "auto".to_string(),
565            TextDecorationThickness::FromFont => "from-font".to_string(),
566            TextDecorationThickness::Zero => "0px".to_string(),
567            TextDecorationThickness::One => "1px".to_string(),
568            TextDecorationThickness::Two => "2px".to_string(),
569            TextDecorationThickness::Four => "4px".to_string(),
570            TextDecorationThickness::Eight => "8px".to_string(),
571        }
572    }
573}
574
575impl TextUnderlineOffset {
576    pub fn to_class_name(&self) -> String {
577        match self {
578            TextUnderlineOffset::Auto => "underline-offset-auto".to_string(),
579            TextUnderlineOffset::Zero => "underline-offset-0".to_string(),
580            TextUnderlineOffset::One => "underline-offset-1".to_string(),
581            TextUnderlineOffset::Two => "underline-offset-2".to_string(),
582            TextUnderlineOffset::Four => "underline-offset-4".to_string(),
583            TextUnderlineOffset::Eight => "underline-offset-8".to_string(),
584        }
585    }
586
587    pub fn to_css_value(&self) -> String {
588        match self {
589            TextUnderlineOffset::Auto => "auto".to_string(),
590            TextUnderlineOffset::Zero => "0px".to_string(),
591            TextUnderlineOffset::One => "1px".to_string(),
592            TextUnderlineOffset::Two => "2px".to_string(),
593            TextUnderlineOffset::Four => "4px".to_string(),
594            TextUnderlineOffset::Eight => "8px".to_string(),
595        }
596    }
597}
598
599impl TextTransform {
600    pub fn to_class_name(&self) -> String {
601        match self {
602            TextTransform::None => "normal-case".to_string(),
603            TextTransform::Uppercase => "uppercase".to_string(),
604            TextTransform::Lowercase => "lowercase".to_string(),
605            TextTransform::Capitalize => "capitalize".to_string(),
606        }
607    }
608    
609    pub fn to_css_value(&self) -> String {
610        match self {
611            TextTransform::None => "none".to_string(),
612            TextTransform::Uppercase => "uppercase".to_string(),
613            TextTransform::Lowercase => "lowercase".to_string(),
614            TextTransform::Capitalize => "capitalize".to_string(),
615        }
616    }
617}
618
619impl TextOverflow {
620    pub fn to_class_name(&self) -> String {
621        match self {
622            TextOverflow::Truncate => "truncate".to_string(),
623            TextOverflow::Ellipsis => "text-ellipsis".to_string(),
624            TextOverflow::Clip => "text-clip".to_string(),
625        }
626    }
627    
628    pub fn to_css_value(&self) -> String {
629        match self {
630            TextOverflow::Truncate => "truncate".to_string(),
631            TextOverflow::Ellipsis => "ellipsis".to_string(),
632            TextOverflow::Clip => "clip".to_string(),
633        }
634    }
635}
636
637impl WhiteSpace {
638    pub fn to_class_name(&self) -> String {
639        match self {
640            WhiteSpace::Normal => "whitespace-normal".to_string(),
641            WhiteSpace::Nowrap => "whitespace-nowrap".to_string(),
642            WhiteSpace::Pre => "whitespace-pre".to_string(),
643            WhiteSpace::PreLine => "whitespace-pre-line".to_string(),
644            WhiteSpace::PreWrap => "whitespace-pre-wrap".to_string(),
645            WhiteSpace::BreakSpaces => "whitespace-break-spaces".to_string(),
646        }
647    }
648    
649    pub fn to_css_value(&self) -> String {
650        match self {
651            WhiteSpace::Normal => "normal".to_string(),
652            WhiteSpace::Nowrap => "nowrap".to_string(),
653            WhiteSpace::Pre => "pre".to_string(),
654            WhiteSpace::PreLine => "pre-line".to_string(),
655            WhiteSpace::PreWrap => "pre-wrap".to_string(),
656            WhiteSpace::BreakSpaces => "break-spaces".to_string(),
657        }
658    }
659}
660
661impl WordBreak {
662    pub fn to_class_name(&self) -> String {
663        match self {
664            WordBreak::Normal => "break-normal".to_string(),
665            WordBreak::BreakAll => "break-all".to_string(),
666            WordBreak::BreakWords => "break-words".to_string(),
667            WordBreak::KeepAll => "break-keep".to_string(),
668        }
669    }
670    
671    pub fn to_css_value(&self) -> String {
672        match self {
673            WordBreak::Normal => "normal".to_string(),
674            WordBreak::BreakAll => "break-all".to_string(),
675            WordBreak::BreakWords => "break-words".to_string(),
676            WordBreak::KeepAll => "keep-all".to_string(),
677        }
678    }
679}
680
681impl fmt::Display for FontFamily {
682    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683        write!(f, "{}", self.to_class_name())
684    }
685}
686
687impl fmt::Display for FontSize {
688    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
689        write!(f, "{}", self.to_class_name())
690    }
691}
692
693impl fmt::Display for FontWeight {
694    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
695        write!(f, "{}", self.to_class_name())
696    }
697}
698
699impl fmt::Display for TextAlign {
700    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
701        write!(f, "{}", self.to_class_name())
702    }
703}
704
705impl fmt::Display for LineHeight {
706    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707        write!(f, "{}", self.to_class_name())
708    }
709}
710
711impl fmt::Display for LetterSpacing {
712    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713        write!(f, "{}", self.to_class_name())
714    }
715}
716
717impl fmt::Display for TextDecoration {
718    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719        write!(f, "{}", self.to_class_name())
720    }
721}
722
723impl fmt::Display for TextDecorationStyle {
724    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725        write!(f, "{}", self.to_class_name())
726    }
727}
728
729impl fmt::Display for TextDecorationThickness {
730    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
731        write!(f, "{}", self.to_class_name())
732    }
733}
734
735impl fmt::Display for TextUnderlineOffset {
736    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
737        write!(f, "{}", self.to_class_name())
738    }
739}
740
741impl fmt::Display for TextTransform {
742    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
743        write!(f, "{}", self.to_class_name())
744    }
745}
746
747/// Trait for adding font family utilities to a class builder
748pub trait FontFamilyUtilities {
749    /// Set font family
750    fn font_family(self, family: FontFamily) -> Self;
751}
752
753impl FontFamilyUtilities for ClassBuilder {
754    fn font_family(self, family: FontFamily) -> Self {
755        self.class(format!("font-{}", family.to_class_name()))
756    }
757}
758
759/// Trait for adding font size utilities to a class builder
760pub trait FontSizeUtilities {
761    /// Set font size
762    fn font_size(self, size: FontSize) -> Self;
763}
764
765impl FontSizeUtilities for ClassBuilder {
766    fn font_size(self, size: FontSize) -> Self {
767        self.class(format!("text-{}", size.to_class_name()))
768    }
769}
770
771/// Trait for adding font weight utilities to a class builder
772pub trait FontWeightUtilities {
773    /// Set font weight
774    fn font_weight(self, weight: FontWeight) -> Self;
775}
776
777impl FontWeightUtilities for ClassBuilder {
778    fn font_weight(self, weight: FontWeight) -> Self {
779        self.class(format!("font-{}", weight.to_class_name()))
780    }
781}
782
783/// Trait for adding text alignment utilities to a class builder
784pub trait TextAlignUtilities {
785    /// Set text alignment
786    fn text_align(self, align: TextAlign) -> Self;
787}
788
789impl TextAlignUtilities for ClassBuilder {
790    fn text_align(self, align: TextAlign) -> Self {
791        self.class(format!("text-{}", align.to_class_name()))
792    }
793}
794
795/// Trait for adding line height utilities to a class builder
796pub trait LineHeightUtilities {
797    /// Set line height
798    fn line_height(self, height: LineHeight) -> Self;
799}
800
801impl LineHeightUtilities for ClassBuilder {
802    fn line_height(self, height: LineHeight) -> Self {
803        self.class(format!("leading-{}", height.to_class_name()))
804    }
805}
806
807/// Trait for adding letter spacing utilities to a class builder
808pub trait LetterSpacingUtilities {
809    /// Set letter spacing
810    fn letter_spacing(self, spacing: LetterSpacing) -> Self;
811}
812
813impl LetterSpacingUtilities for ClassBuilder {
814    fn letter_spacing(self, spacing: LetterSpacing) -> Self {
815        self.class(format!("tracking-{}", spacing.to_class_name()))
816    }
817}
818
819/// Trait for adding text decoration utilities to a class builder
820pub trait TextDecorationUtilities {
821    /// Set text decoration
822    fn text_decoration(self, decoration: TextDecoration) -> Self;
823}
824
825impl TextDecorationUtilities for ClassBuilder {
826    fn text_decoration(self, decoration: TextDecoration) -> Self {
827        self.class(decoration.to_class_name())
828    }
829}
830
831/// Trait for adding text transform utilities to a class builder
832pub trait TextTransformUtilities {
833    /// Set text transform
834    fn text_transform(self, transform: TextTransform) -> Self;
835}
836
837impl TextTransformUtilities for ClassBuilder {
838    fn text_transform(self, transform: TextTransform) -> Self {
839        self.class(transform.to_class_name())
840    }
841}
842
843/// Trait for adding text overflow utilities to a class builder
844pub trait TextOverflowUtilities {
845    /// Set text overflow
846    fn text_overflow(self, overflow: TextOverflow) -> Self;
847}
848
849impl TextOverflowUtilities for ClassBuilder {
850    fn text_overflow(self, overflow: TextOverflow) -> Self {
851        self.class(overflow.to_class_name())
852    }
853}
854
855/// Trait for adding white space utilities to a class builder
856pub trait WhiteSpaceUtilities {
857    /// Set white space
858    fn white_space(self, space: WhiteSpace) -> Self;
859}
860
861impl WhiteSpaceUtilities for ClassBuilder {
862    fn white_space(self, space: WhiteSpace) -> Self {
863        self.class(space.to_class_name())
864    }
865}
866
867/// Trait for adding word break utilities to a class builder
868pub trait WordBreakUtilities {
869    /// Set word break
870    fn word_break(self, break_type: WordBreak) -> Self;
871}
872
873impl WordBreakUtilities for ClassBuilder {
874    fn word_break(self, break_type: WordBreak) -> Self {
875        self.class(break_type.to_class_name())
876    }
877}
878
879/// Trait for adding text decoration style utilities to a class builder
880pub trait TextDecorationStyleUtilities {
881    /// Set text decoration style
882    fn text_decoration_style(self, style: TextDecorationStyle) -> Self;
883}
884
885impl TextDecorationStyleUtilities for ClassBuilder {
886    fn text_decoration_style(self, style: TextDecorationStyle) -> Self {
887        self.class(style.to_class_name())
888    }
889}
890
891/// Trait for adding text decoration thickness utilities to a class builder
892pub trait TextDecorationThicknessUtilities {
893    /// Set text decoration thickness
894    fn text_decoration_thickness(self, thickness: TextDecorationThickness) -> Self;
895}
896
897impl TextDecorationThicknessUtilities for ClassBuilder {
898    fn text_decoration_thickness(self, thickness: TextDecorationThickness) -> Self {
899        self.class(thickness.to_class_name())
900    }
901}
902
903/// Trait for adding text underline offset utilities to a class builder
904pub trait TextUnderlineOffsetUtilities {
905    /// Set text underline offset
906    fn text_underline_offset(self, offset: TextUnderlineOffset) -> Self;
907}
908
909impl TextUnderlineOffsetUtilities for ClassBuilder {
910    fn text_underline_offset(self, offset: TextUnderlineOffset) -> Self {
911        self.class(offset.to_class_name())
912    }
913}
914
915#[cfg(test)]
916mod tests {
917    use super::*;
918    
919    #[test]
920    fn test_font_family_utilities() {
921        let classes = ClassBuilder::new()
922            .font_family(FontFamily::Sans)
923            .font_family(FontFamily::Serif)
924            .font_family(FontFamily::Mono)
925            .build();
926        
927        let css_classes = classes.to_css_classes();
928        assert!(css_classes.contains("font-sans"));
929        assert!(css_classes.contains("font-serif"));
930        assert!(css_classes.contains("font-mono"));
931    }
932    
933    #[test]
934    fn test_font_size_utilities() {
935        let classes = ClassBuilder::new()
936            .font_size(FontSize::Xs)
937            .font_size(FontSize::Sm)
938            .font_size(FontSize::Base)
939            .font_size(FontSize::Lg)
940            .font_size(FontSize::Xl)
941            .build();
942        
943        let css_classes = classes.to_css_classes();
944        assert!(css_classes.contains("text-xs"));
945        assert!(css_classes.contains("text-sm"));
946        assert!(css_classes.contains("text-base"));
947        assert!(css_classes.contains("text-lg"));
948        assert!(css_classes.contains("text-xl"));
949    }
950    
951    #[test]
952    fn test_font_weight_utilities() {
953        let classes = ClassBuilder::new()
954            .font_weight(FontWeight::Thin)
955            .font_weight(FontWeight::Normal)
956            .font_weight(FontWeight::Bold)
957            .font_weight(FontWeight::Black)
958            .build();
959        
960        let css_classes = classes.to_css_classes();
961        assert!(css_classes.contains("font-thin"));
962        assert!(css_classes.contains("font-normal"));
963        assert!(css_classes.contains("font-bold"));
964        assert!(css_classes.contains("font-black"));
965    }
966    
967    #[test]
968    fn test_text_align_utilities() {
969        let classes = ClassBuilder::new()
970            .text_align(TextAlign::Left)
971            .text_align(TextAlign::Center)
972            .text_align(TextAlign::Right)
973            .text_align(TextAlign::Justify)
974            .build();
975        
976        let css_classes = classes.to_css_classes();
977        assert!(css_classes.contains("text-left"));
978        assert!(css_classes.contains("text-center"));
979        assert!(css_classes.contains("text-right"));
980        assert!(css_classes.contains("text-justify"));
981    }
982    
983    #[test]
984    fn test_line_height_utilities() {
985        let classes = ClassBuilder::new()
986            .line_height(LineHeight::Tight)
987            .line_height(LineHeight::Normal)
988            .line_height(LineHeight::Relaxed)
989            .line_height(LineHeight::Custom(1.75))
990            .build();
991        
992        let css_classes = classes.to_css_classes();
993        assert!(css_classes.contains("leading-tight"));
994        assert!(css_classes.contains("leading-normal"));
995        assert!(css_classes.contains("leading-relaxed"));
996        assert!(css_classes.contains("leading-1.75"));
997    }
998    
999    #[test]
1000    fn test_letter_spacing_utilities() {
1001        let classes = ClassBuilder::new()
1002            .letter_spacing(LetterSpacing::Tight)
1003            .letter_spacing(LetterSpacing::Normal)
1004            .letter_spacing(LetterSpacing::Wide)
1005            .letter_spacing(LetterSpacing::Custom(0.1))
1006            .build();
1007        
1008        let css_classes = classes.to_css_classes();
1009        assert!(css_classes.contains("tracking-tight"));
1010        assert!(css_classes.contains("tracking-normal"));
1011        assert!(css_classes.contains("tracking-wide"));
1012        assert!(css_classes.contains("tracking-0.1"));
1013    }
1014    
1015    #[test]
1016    fn test_text_decoration_utilities() {
1017        let classes = ClassBuilder::new()
1018            .text_decoration(TextDecoration::None)
1019            .text_decoration(TextDecoration::Underline)
1020            .text_decoration(TextDecoration::LineThrough)
1021            .build();
1022        
1023        let css_classes = classes.to_css_classes();
1024        assert!(css_classes.contains("no-underline"));
1025        assert!(css_classes.contains("underline"));
1026        assert!(css_classes.contains("line-through"));
1027    }
1028    
1029    #[test]
1030    fn test_text_transform_utilities() {
1031        let classes = ClassBuilder::new()
1032            .text_transform(TextTransform::None)
1033            .text_transform(TextTransform::Uppercase)
1034            .text_transform(TextTransform::Lowercase)
1035            .text_transform(TextTransform::Capitalize)
1036            .build();
1037        
1038        let css_classes = classes.to_css_classes();
1039        assert!(css_classes.contains("normal-case"));
1040        assert!(css_classes.contains("uppercase"));
1041        assert!(css_classes.contains("lowercase"));
1042        assert!(css_classes.contains("capitalize"));
1043    }
1044    
1045    #[test]
1046    fn test_text_overflow_utilities() {
1047        let classes = ClassBuilder::new()
1048            .text_overflow(TextOverflow::Truncate)
1049            .text_overflow(TextOverflow::Ellipsis)
1050            .text_overflow(TextOverflow::Clip)
1051            .build();
1052        
1053        let css_classes = classes.to_css_classes();
1054        assert!(css_classes.contains("truncate"));
1055        assert!(css_classes.contains("text-ellipsis"));
1056        assert!(css_classes.contains("text-clip"));
1057    }
1058    
1059    #[test]
1060    fn test_white_space_utilities() {
1061        let classes = ClassBuilder::new()
1062            .white_space(WhiteSpace::Normal)
1063            .white_space(WhiteSpace::Nowrap)
1064            .white_space(WhiteSpace::Pre)
1065            .build();
1066        
1067        let css_classes = classes.to_css_classes();
1068        assert!(css_classes.contains("whitespace-normal"));
1069        assert!(css_classes.contains("whitespace-nowrap"));
1070        assert!(css_classes.contains("whitespace-pre"));
1071    }
1072    
1073    #[test]
1074    fn test_word_break_utilities() {
1075        let classes = ClassBuilder::new()
1076            .word_break(WordBreak::Normal)
1077            .word_break(WordBreak::BreakAll)
1078            .word_break(WordBreak::BreakWords)
1079            .build();
1080        
1081        let css_classes = classes.to_css_classes();
1082        assert!(css_classes.contains("break-normal"));
1083        assert!(css_classes.contains("break-all"));
1084        assert!(css_classes.contains("break-words"));
1085    }
1086    
1087    #[test]
1088    fn test_complex_typography_combination() {
1089        let classes = ClassBuilder::new()
1090            .font_family(FontFamily::Sans)
1091            .font_size(FontSize::Lg)
1092            .font_weight(FontWeight::Bold)
1093            .text_align(TextAlign::Center)
1094            .line_height(LineHeight::Relaxed)
1095            .letter_spacing(LetterSpacing::Wide)
1096            .text_decoration(TextDecoration::Underline)
1097            .text_transform(TextTransform::Uppercase)
1098            .build();
1099        
1100        let css_classes = classes.to_css_classes();
1101        assert!(css_classes.contains("font-sans"));
1102        assert!(css_classes.contains("text-lg"));
1103        assert!(css_classes.contains("font-bold"));
1104        assert!(css_classes.contains("text-center"));
1105        assert!(css_classes.contains("leading-relaxed"));
1106        assert!(css_classes.contains("tracking-wide"));
1107        assert!(css_classes.contains("underline"));
1108        assert!(css_classes.contains("uppercase"));
1109    }
1110    
1111    /// Test that all Tailwind CSS font sizes are supported
1112    #[test]
1113    fn test_all_tailwind_font_sizes() {
1114        // Test all standard Tailwind CSS font sizes (text-xs through text-9xl)
1115        let test_values = vec![
1116            (FontSize::Xs, "text-xs"),
1117            (FontSize::Sm, "text-sm"),
1118            (FontSize::Base, "text-base"),
1119            (FontSize::Lg, "text-lg"),
1120            (FontSize::Xl, "text-xl"),
1121            (FontSize::Xl2, "text-2xl"),
1122            (FontSize::Xl3, "text-3xl"),
1123            (FontSize::Xl4, "text-4xl"),
1124            (FontSize::Xl5, "text-5xl"),
1125            (FontSize::Xl6, "text-6xl"),
1126            (FontSize::Xl7, "text-7xl"),
1127            (FontSize::Xl8, "text-8xl"),
1128            (FontSize::Xl9, "text-9xl"),
1129        ];
1130        
1131        for (value, expected_class) in test_values {
1132            let classes = ClassBuilder::new().font_size(value).build();
1133            let css_classes = classes.to_css_classes();
1134            assert!(css_classes.contains(expected_class), 
1135                "Missing font size: {} (expected class: {})", 
1136                format!("{:?}", value), expected_class);
1137        }
1138    }
1139    
1140    /// Test that all Week 4 typography utilities are implemented
1141    #[test]
1142    fn test_week4_typography_utilities() {
1143        // Test all Week 4 typography utilities
1144        let classes = ClassBuilder::new()
1145            // Font sizes (text-xs through text-9xl) - already tested above
1146            .font_size(FontSize::Xs)
1147            .font_size(FontSize::Xl9)
1148            // Font weights (font-thin through font-black)
1149            .font_weight(FontWeight::Thin)
1150            .font_weight(FontWeight::Black)
1151            // Line heights (leading-3 through leading-10)
1152            .line_height(LineHeight::Tight)
1153            .line_height(LineHeight::Relaxed)
1154            // Letter spacing (tracking-tighter through tracking-widest)
1155            .letter_spacing(LetterSpacing::Tighter)
1156            .letter_spacing(LetterSpacing::Widest)
1157            // Text decoration (underline, no-underline, line-through)
1158            .text_decoration(TextDecoration::Underline)
1159            .text_decoration(TextDecoration::None)
1160            .text_decoration(TextDecoration::LineThrough)
1161            // Text transform (uppercase, lowercase, capitalize)
1162            .text_transform(TextTransform::Uppercase)
1163            .text_transform(TextTransform::Lowercase)
1164            .text_transform(TextTransform::Capitalize)
1165            .build();
1166        
1167        let css_classes = classes.to_css_classes();
1168        
1169        // Font sizes
1170        assert!(css_classes.contains("text-xs"));
1171        assert!(css_classes.contains("text-9xl"));
1172        
1173        // Font weights
1174        assert!(css_classes.contains("font-thin"));
1175        assert!(css_classes.contains("font-black"));
1176        
1177        // Line heights
1178        assert!(css_classes.contains("leading-tight"));
1179        assert!(css_classes.contains("leading-relaxed"));
1180        
1181        // Letter spacing
1182        assert!(css_classes.contains("tracking-tighter"));
1183        assert!(css_classes.contains("tracking-widest"));
1184        
1185        // Text decoration
1186        assert!(css_classes.contains("underline"));
1187        assert!(css_classes.contains("no-underline"));
1188        assert!(css_classes.contains("line-through"));
1189        
1190        // Text transform
1191        assert!(css_classes.contains("uppercase"));
1192        assert!(css_classes.contains("lowercase"));
1193        assert!(css_classes.contains("capitalize"));
1194    }
1195
1196    /// Test extended numeric line height utilities (leading-3 through leading-10)
1197    #[test]
1198    fn test_extended_line_height_utilities() {
1199        let classes = ClassBuilder::new()
1200            .line_height(LineHeight::Three)
1201            .line_height(LineHeight::Four)
1202            .line_height(LineHeight::Five)
1203            .line_height(LineHeight::Six)
1204            .line_height(LineHeight::Seven)
1205            .line_height(LineHeight::Eight)
1206            .line_height(LineHeight::Nine)
1207            .line_height(LineHeight::Ten)
1208            .build();
1209
1210        let css_classes = classes.to_css_classes();
1211        assert!(css_classes.contains("leading-3"));
1212        assert!(css_classes.contains("leading-4"));
1213        assert!(css_classes.contains("leading-5"));
1214        assert!(css_classes.contains("leading-6"));
1215        assert!(css_classes.contains("leading-7"));
1216        assert!(css_classes.contains("leading-8"));
1217        assert!(css_classes.contains("leading-9"));
1218        assert!(css_classes.contains("leading-10"));
1219    }
1220
1221    /// Test extended text decoration utilities
1222    #[test]
1223    fn test_extended_text_decoration_utilities() {
1224        let classes = ClassBuilder::new()
1225            .text_decoration_style(TextDecorationStyle::Solid)
1226            .text_decoration_style(TextDecorationStyle::Double)
1227            .text_decoration_style(TextDecorationStyle::Dotted)
1228            .text_decoration_style(TextDecorationStyle::Dashed)
1229            .text_decoration_style(TextDecorationStyle::Wavy)
1230            .text_decoration_thickness(TextDecorationThickness::Auto)
1231            .text_decoration_thickness(TextDecorationThickness::FromFont)
1232            .text_decoration_thickness(TextDecorationThickness::One)
1233            .text_decoration_thickness(TextDecorationThickness::Two)
1234            .text_decoration_thickness(TextDecorationThickness::Four)
1235            .text_underline_offset(TextUnderlineOffset::Auto)
1236            .text_underline_offset(TextUnderlineOffset::Zero)
1237            .text_underline_offset(TextUnderlineOffset::One)
1238            .text_underline_offset(TextUnderlineOffset::Two)
1239            .text_underline_offset(TextUnderlineOffset::Four)
1240            .build();
1241
1242        let css_classes = classes.to_css_classes();
1243
1244        // Text decoration styles
1245        assert!(css_classes.contains("decoration-solid"));
1246        assert!(css_classes.contains("decoration-double"));
1247        assert!(css_classes.contains("decoration-dotted"));
1248        assert!(css_classes.contains("decoration-dashed"));
1249        assert!(css_classes.contains("decoration-wavy"));
1250
1251        // Text decoration thickness
1252        assert!(css_classes.contains("decoration-auto"));
1253        assert!(css_classes.contains("decoration-from-font"));
1254        assert!(css_classes.contains("decoration-1"));
1255        assert!(css_classes.contains("decoration-2"));
1256        assert!(css_classes.contains("decoration-4"));
1257
1258        // Text underline offset
1259        assert!(css_classes.contains("underline-offset-auto"));
1260        assert!(css_classes.contains("underline-offset-0"));
1261        assert!(css_classes.contains("underline-offset-1"));
1262        assert!(css_classes.contains("underline-offset-2"));
1263        assert!(css_classes.contains("underline-offset-4"));
1264    }
1265
1266    /// Test comprehensive extended typography features
1267    #[test]
1268    fn test_comprehensive_extended_typography() {
1269        let classes = ClassBuilder::new()
1270            // Extended line heights
1271            .line_height(LineHeight::Three)
1272            .line_height(LineHeight::Ten)
1273            // Extended text decorations
1274            .text_decoration(TextDecoration::Underline)
1275            .text_decoration_style(TextDecorationStyle::Wavy)
1276            .text_decoration_thickness(TextDecorationThickness::Two)
1277            .text_underline_offset(TextUnderlineOffset::Four)
1278            // Existing features
1279            .font_size(FontSize::Xl2)
1280            .font_weight(FontWeight::Bold)
1281            .text_transform(TextTransform::Uppercase)
1282            .letter_spacing(LetterSpacing::Wide)
1283            .build();
1284
1285        let css_classes = classes.to_css_classes();
1286
1287        // Extended line heights
1288        assert!(css_classes.contains("leading-3"));
1289        assert!(css_classes.contains("leading-10"));
1290
1291        // Extended text decorations
1292        assert!(css_classes.contains("underline"));
1293        assert!(css_classes.contains("decoration-wavy"));
1294        assert!(css_classes.contains("decoration-2"));
1295        assert!(css_classes.contains("underline-offset-4"));
1296
1297        // Existing features still work
1298        assert!(css_classes.contains("text-2xl"));
1299        assert!(css_classes.contains("font-bold"));
1300        assert!(css_classes.contains("uppercase"));
1301        assert!(css_classes.contains("tracking-wide"));
1302    }
1303
1304    /// Test LineHeight::all_values utility function
1305    #[test]
1306    fn test_line_height_all_values() {
1307        let all_values = LineHeight::all_values();
1308        assert_eq!(all_values.len(), 14); // 8 numeric + 6 named values
1309
1310        // Test that all values are present
1311        assert!(all_values.contains(&LineHeight::None));
1312        assert!(all_values.contains(&LineHeight::Three));
1313        assert!(all_values.contains(&LineHeight::Four));
1314        assert!(all_values.contains(&LineHeight::Five));
1315        assert!(all_values.contains(&LineHeight::Six));
1316        assert!(all_values.contains(&LineHeight::Seven));
1317        assert!(all_values.contains(&LineHeight::Eight));
1318        assert!(all_values.contains(&LineHeight::Nine));
1319        assert!(all_values.contains(&LineHeight::Ten));
1320        assert!(all_values.contains(&LineHeight::Tight));
1321        assert!(all_values.contains(&LineHeight::Snug));
1322        assert!(all_values.contains(&LineHeight::Normal));
1323        assert!(all_values.contains(&LineHeight::Relaxed));
1324        assert!(all_values.contains(&LineHeight::Loose));
1325    }
1326
1327    #[test]
1328    fn test_font_family_display() {
1329        // Test that FontFamily displays correctly
1330        assert_eq!(format!("{}", FontFamily::Sans), "sans");
1331        assert_eq!(format!("{}", FontFamily::Serif), "serif");
1332        assert_eq!(format!("{}", FontFamily::Mono), "mono");
1333    }
1334
1335    #[test]
1336    fn test_font_size_display() {
1337        // Test that FontSize displays correctly
1338        assert_eq!(format!("{}", FontSize::Xs), "xs");
1339        assert_eq!(format!("{}", FontSize::Sm), "sm");
1340        assert_eq!(format!("{}", FontSize::Base), "base");
1341        assert_eq!(format!("{}", FontSize::Lg), "lg");
1342        assert_eq!(format!("{}", FontSize::Xl), "xl");
1343        assert_eq!(format!("{}", FontSize::Xl2), "2xl");
1344        assert_eq!(format!("{}", FontSize::Xl3), "3xl");
1345        assert_eq!(format!("{}", FontSize::Xl4), "4xl");
1346        assert_eq!(format!("{}", FontSize::Xl5), "5xl");
1347        assert_eq!(format!("{}", FontSize::Xl6), "6xl");
1348        assert_eq!(format!("{}", FontSize::Xl7), "7xl");
1349        assert_eq!(format!("{}", FontSize::Xl8), "8xl");
1350        assert_eq!(format!("{}", FontSize::Xl9), "9xl");
1351    }
1352
1353    #[test]
1354    fn test_font_weight_display() {
1355        // Test that FontWeight displays correctly
1356        assert_eq!(format!("{}", FontWeight::Thin), "thin");
1357        assert_eq!(format!("{}", FontWeight::ExtraLight), "extralight");
1358        assert_eq!(format!("{}", FontWeight::Light), "light");
1359        assert_eq!(format!("{}", FontWeight::Normal), "normal");
1360        assert_eq!(format!("{}", FontWeight::Medium), "medium");
1361        assert_eq!(format!("{}", FontWeight::SemiBold), "semibold");
1362        assert_eq!(format!("{}", FontWeight::Bold), "bold");
1363        assert_eq!(format!("{}", FontWeight::ExtraBold), "extrabold");
1364        assert_eq!(format!("{}", FontWeight::Black), "black");
1365    }
1366
1367    #[test]
1368    fn test_text_align_display() {
1369        // Test that TextAlign displays correctly
1370        assert_eq!(format!("{}", TextAlign::Left), "left");
1371        assert_eq!(format!("{}", TextAlign::Center), "center");
1372        assert_eq!(format!("{}", TextAlign::Right), "right");
1373        assert_eq!(format!("{}", TextAlign::Justify), "justify");
1374        assert_eq!(format!("{}", TextAlign::Start), "start");
1375        assert_eq!(format!("{}", TextAlign::End), "end");
1376    }
1377
1378    #[test]
1379    fn test_line_height_display() {
1380        // Test that LineHeight displays correctly
1381        assert_eq!(format!("{}", LineHeight::None), "none");
1382        assert_eq!(format!("{}", LineHeight::Three), "3");
1383        assert_eq!(format!("{}", LineHeight::Four), "4");
1384        assert_eq!(format!("{}", LineHeight::Five), "5");
1385        assert_eq!(format!("{}", LineHeight::Six), "6");
1386        assert_eq!(format!("{}", LineHeight::Seven), "7");
1387        assert_eq!(format!("{}", LineHeight::Eight), "8");
1388        assert_eq!(format!("{}", LineHeight::Nine), "9");
1389        assert_eq!(format!("{}", LineHeight::Ten), "10");
1390        assert_eq!(format!("{}", LineHeight::Tight), "tight");
1391        assert_eq!(format!("{}", LineHeight::Snug), "snug");
1392        assert_eq!(format!("{}", LineHeight::Normal), "normal");
1393        assert_eq!(format!("{}", LineHeight::Relaxed), "relaxed");
1394        assert_eq!(format!("{}", LineHeight::Loose), "loose");
1395        assert_eq!(format!("{}", LineHeight::Custom(1.5)), "1.5");
1396    }
1397
1398    #[test]
1399    fn test_letter_spacing_display() {
1400        // Test that LetterSpacing displays correctly
1401        assert_eq!(format!("{}", LetterSpacing::Tighter), "tighter");
1402        assert_eq!(format!("{}", LetterSpacing::Tight), "tight");
1403        assert_eq!(format!("{}", LetterSpacing::Normal), "normal");
1404        assert_eq!(format!("{}", LetterSpacing::Wide), "wide");
1405        assert_eq!(format!("{}", LetterSpacing::Wider), "wider");
1406        assert_eq!(format!("{}", LetterSpacing::Widest), "widest");
1407        assert_eq!(format!("{}", LetterSpacing::Custom(0.1)), "0.1");
1408    }
1409
1410    #[test]
1411    fn test_text_decoration_display() {
1412        // Test that TextDecoration displays correctly
1413        assert_eq!(format!("{}", TextDecoration::None), "no-underline");
1414        assert_eq!(format!("{}", TextDecoration::Underline), "underline");
1415        assert_eq!(format!("{}", TextDecoration::Overline), "overline");
1416        assert_eq!(format!("{}", TextDecoration::LineThrough), "line-through");
1417    }
1418
1419    #[test]
1420    fn test_text_transform_display() {
1421        // Test that TextTransform displays correctly
1422        assert_eq!(format!("{}", TextTransform::None), "normal-case");
1423        assert_eq!(format!("{}", TextTransform::Uppercase), "uppercase");
1424        assert_eq!(format!("{}", TextTransform::Lowercase), "lowercase");
1425        assert_eq!(format!("{}", TextTransform::Capitalize), "capitalize");
1426    }
1427
1428    #[test]
1429    fn test_text_overflow_class_names() {
1430        // Test that TextOverflow generates correct class names
1431        assert_eq!(TextOverflow::Truncate.to_class_name(), "truncate");
1432        assert_eq!(TextOverflow::Ellipsis.to_class_name(), "text-ellipsis");
1433        assert_eq!(TextOverflow::Clip.to_class_name(), "text-clip");
1434    }
1435
1436    #[test]
1437    fn test_white_space_class_names() {
1438        // Test that WhiteSpace generates correct class names
1439        assert_eq!(WhiteSpace::Normal.to_class_name(), "whitespace-normal");
1440        assert_eq!(WhiteSpace::Nowrap.to_class_name(), "whitespace-nowrap");
1441        assert_eq!(WhiteSpace::Pre.to_class_name(), "whitespace-pre");
1442        assert_eq!(WhiteSpace::PreLine.to_class_name(), "whitespace-pre-line");
1443        assert_eq!(WhiteSpace::PreWrap.to_class_name(), "whitespace-pre-wrap");
1444        assert_eq!(WhiteSpace::BreakSpaces.to_class_name(), "whitespace-break-spaces");
1445    }
1446
1447    #[test]
1448    fn test_word_break_class_names() {
1449        // Test that WordBreak generates correct class names
1450        assert_eq!(WordBreak::Normal.to_class_name(), "break-normal");
1451        assert_eq!(WordBreak::BreakAll.to_class_name(), "break-all");
1452        assert_eq!(WordBreak::BreakWords.to_class_name(), "break-words");
1453        assert_eq!(WordBreak::KeepAll.to_class_name(), "break-keep");
1454    }
1455
1456    #[test]
1457    fn test_font_family_css_values() {
1458        // Test that FontFamily generates correct CSS values
1459        assert_eq!(FontFamily::Sans.to_css_value(), "ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"");
1460        assert_eq!(FontFamily::Serif.to_css_value(), "ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif");
1461        assert_eq!(FontFamily::Mono.to_css_value(), "ui-monospace, SFMono-Regular, \"SF Mono\", Consolas, \"Liberation Mono\", Menlo, monospace");
1462    }
1463
1464    #[test]
1465    fn test_font_size_css_values() {
1466        // Test that FontSize generates correct CSS values
1467        assert_eq!(FontSize::Xs.to_css_value(), "0.75rem");
1468        assert_eq!(FontSize::Sm.to_css_value(), "0.875rem");
1469        assert_eq!(FontSize::Base.to_css_value(), "1rem");
1470        assert_eq!(FontSize::Lg.to_css_value(), "1.125rem");
1471        assert_eq!(FontSize::Xl.to_css_value(), "1.25rem");
1472        assert_eq!(FontSize::Xl2.to_css_value(), "1.5rem");
1473        assert_eq!(FontSize::Xl3.to_css_value(), "1.875rem");
1474        assert_eq!(FontSize::Xl4.to_css_value(), "2.25rem");
1475        assert_eq!(FontSize::Xl5.to_css_value(), "3rem");
1476        assert_eq!(FontSize::Xl6.to_css_value(), "3.75rem");
1477        assert_eq!(FontSize::Xl7.to_css_value(), "4.5rem");
1478        assert_eq!(FontSize::Xl8.to_css_value(), "6rem");
1479        assert_eq!(FontSize::Xl9.to_css_value(), "8rem");
1480    }
1481
1482    #[test]
1483    fn test_font_weight_css_values() {
1484        // Test that FontWeight generates correct CSS values
1485        assert_eq!(FontWeight::Thin.to_css_value(), "100");
1486        assert_eq!(FontWeight::ExtraLight.to_css_value(), "200");
1487        assert_eq!(FontWeight::Light.to_css_value(), "300");
1488        assert_eq!(FontWeight::Normal.to_css_value(), "400");
1489        assert_eq!(FontWeight::Medium.to_css_value(), "500");
1490        assert_eq!(FontWeight::SemiBold.to_css_value(), "600");
1491        assert_eq!(FontWeight::Bold.to_css_value(), "700");
1492        assert_eq!(FontWeight::ExtraBold.to_css_value(), "800");
1493        assert_eq!(FontWeight::Black.to_css_value(), "900");
1494    }
1495
1496    #[test]
1497    fn test_text_align_css_values() {
1498        // Test that TextAlign generates correct CSS values
1499        assert_eq!(TextAlign::Left.to_css_value(), "left");
1500        assert_eq!(TextAlign::Center.to_css_value(), "center");
1501        assert_eq!(TextAlign::Right.to_css_value(), "right");
1502        assert_eq!(TextAlign::Justify.to_css_value(), "justify");
1503        assert_eq!(TextAlign::Start.to_css_value(), "start");
1504        assert_eq!(TextAlign::End.to_css_value(), "end");
1505    }
1506
1507    #[test]
1508    fn test_line_height_css_values() {
1509        // Test that LineHeight generates correct CSS values
1510        assert_eq!(LineHeight::None.to_css_value(), "1");
1511        assert_eq!(LineHeight::Three.to_css_value(), "0.75rem");
1512        assert_eq!(LineHeight::Four.to_css_value(), "1rem");
1513        assert_eq!(LineHeight::Five.to_css_value(), "1.25rem");
1514        assert_eq!(LineHeight::Six.to_css_value(), "1.5rem");
1515        assert_eq!(LineHeight::Seven.to_css_value(), "1.75rem");
1516        assert_eq!(LineHeight::Eight.to_css_value(), "2rem");
1517        assert_eq!(LineHeight::Nine.to_css_value(), "2.25rem");
1518        assert_eq!(LineHeight::Ten.to_css_value(), "2.5rem");
1519        assert_eq!(LineHeight::Tight.to_css_value(), "1.25");
1520        assert_eq!(LineHeight::Snug.to_css_value(), "1.375");
1521        assert_eq!(LineHeight::Normal.to_css_value(), "1.5");
1522        assert_eq!(LineHeight::Relaxed.to_css_value(), "1.625");
1523        assert_eq!(LineHeight::Loose.to_css_value(), "2");
1524        assert_eq!(LineHeight::Custom(1.5).to_css_value(), "1.5");
1525    }
1526
1527    #[test]
1528    fn test_letter_spacing_css_values() {
1529        // Test that LetterSpacing generates correct CSS values
1530        assert_eq!(LetterSpacing::Tighter.to_css_value(), "-0.05em");
1531        assert_eq!(LetterSpacing::Tight.to_css_value(), "-0.025em");
1532        assert_eq!(LetterSpacing::Normal.to_css_value(), "0em");
1533        assert_eq!(LetterSpacing::Wide.to_css_value(), "0.025em");
1534        assert_eq!(LetterSpacing::Wider.to_css_value(), "0.05em");
1535        assert_eq!(LetterSpacing::Widest.to_css_value(), "0.1em");
1536        assert_eq!(LetterSpacing::Custom(0.1).to_css_value(), "0.1em");
1537    }
1538
1539    #[test]
1540    fn test_typography_serialization() {
1541        // Test that typography enums can be serialized and deserialized
1542        let font_family = FontFamily::Sans;
1543        let serialized = serde_json::to_string(&font_family).unwrap();
1544        let deserialized: FontFamily = serde_json::from_str(&serialized).unwrap();
1545        assert_eq!(font_family, deserialized);
1546
1547        let font_size = FontSize::Lg;
1548        let serialized = serde_json::to_string(&font_size).unwrap();
1549        let deserialized: FontSize = serde_json::from_str(&serialized).unwrap();
1550        assert_eq!(font_size, deserialized);
1551
1552        let font_weight = FontWeight::Bold;
1553        let serialized = serde_json::to_string(&font_weight).unwrap();
1554        let deserialized: FontWeight = serde_json::from_str(&serialized).unwrap();
1555        assert_eq!(font_weight, deserialized);
1556
1557        let text_align = TextAlign::Center;
1558        let serialized = serde_json::to_string(&text_align).unwrap();
1559        let deserialized: TextAlign = serde_json::from_str(&serialized).unwrap();
1560        assert_eq!(text_align, deserialized);
1561
1562        let line_height = LineHeight::Relaxed;
1563        let serialized = serde_json::to_string(&line_height).unwrap();
1564        let deserialized: LineHeight = serde_json::from_str(&serialized).unwrap();
1565        assert_eq!(line_height, deserialized);
1566
1567        let letter_spacing = LetterSpacing::Wide;
1568        let serialized = serde_json::to_string(&letter_spacing).unwrap();
1569        let deserialized: LetterSpacing = serde_json::from_str(&serialized).unwrap();
1570        assert_eq!(letter_spacing, deserialized);
1571    }
1572
1573    #[test]
1574    fn test_typography_equality_and_hash() {
1575        // Test that typography enums can be compared for equality and hashed
1576        let font_family1 = FontFamily::Sans;
1577        let font_family2 = FontFamily::Sans;
1578        let font_family3 = FontFamily::Serif;
1579        
1580        assert_eq!(font_family1, font_family2);
1581        assert_ne!(font_family1, font_family3);
1582        
1583        // Test that equal enums have the same hash
1584        use std::collections::hash_map::DefaultHasher;
1585        use std::hash::{Hash, Hasher};
1586        
1587        let mut hasher1 = DefaultHasher::new();
1588        let mut hasher2 = DefaultHasher::new();
1589        font_family1.hash(&mut hasher1);
1590        font_family2.hash(&mut hasher2);
1591        assert_eq!(hasher1.finish(), hasher2.finish());
1592    }
1593
1594    #[test]
1595    fn test_comprehensive_typography_utilities() {
1596        // Test comprehensive usage of all typography utility methods
1597        let classes = ClassBuilder::new()
1598            // Font families
1599            .font_family(FontFamily::Sans)
1600            .font_family(FontFamily::Serif)
1601            .font_family(FontFamily::Mono)
1602            
1603            // Font sizes
1604            .font_size(FontSize::Xs)
1605            .font_size(FontSize::Sm)
1606            .font_size(FontSize::Base)
1607            .font_size(FontSize::Lg)
1608            .font_size(FontSize::Xl)
1609            .font_size(FontSize::Xl2)
1610            .font_size(FontSize::Xl3)
1611            .font_size(FontSize::Xl4)
1612            .font_size(FontSize::Xl5)
1613            .font_size(FontSize::Xl6)
1614            .font_size(FontSize::Xl7)
1615            .font_size(FontSize::Xl8)
1616            .font_size(FontSize::Xl9)
1617            
1618            // Font weights
1619            .font_weight(FontWeight::Thin)
1620            .font_weight(FontWeight::ExtraLight)
1621            .font_weight(FontWeight::Light)
1622            .font_weight(FontWeight::Normal)
1623            .font_weight(FontWeight::Medium)
1624            .font_weight(FontWeight::SemiBold)
1625            .font_weight(FontWeight::Bold)
1626            .font_weight(FontWeight::ExtraBold)
1627            .font_weight(FontWeight::Black)
1628            
1629            // Text alignment
1630            .text_align(TextAlign::Left)
1631            .text_align(TextAlign::Center)
1632            .text_align(TextAlign::Right)
1633            .text_align(TextAlign::Justify)
1634            .text_align(TextAlign::Start)
1635            .text_align(TextAlign::End)
1636            
1637            // Line heights
1638            .line_height(LineHeight::None)
1639            .line_height(LineHeight::Three)
1640            .line_height(LineHeight::Four)
1641            .line_height(LineHeight::Five)
1642            .line_height(LineHeight::Six)
1643            .line_height(LineHeight::Seven)
1644            .line_height(LineHeight::Eight)
1645            .line_height(LineHeight::Nine)
1646            .line_height(LineHeight::Ten)
1647            .line_height(LineHeight::Tight)
1648            .line_height(LineHeight::Snug)
1649            .line_height(LineHeight::Normal)
1650            .line_height(LineHeight::Relaxed)
1651            .line_height(LineHeight::Loose)
1652            .line_height(LineHeight::Custom(1.5))
1653            
1654            // Letter spacing
1655            .letter_spacing(LetterSpacing::Tighter)
1656            .letter_spacing(LetterSpacing::Tight)
1657            .letter_spacing(LetterSpacing::Normal)
1658            .letter_spacing(LetterSpacing::Wide)
1659            .letter_spacing(LetterSpacing::Wider)
1660            .letter_spacing(LetterSpacing::Widest)
1661            .letter_spacing(LetterSpacing::Custom(0.1))
1662            
1663            // Text decoration
1664            .text_decoration(TextDecoration::None)
1665            .text_decoration(TextDecoration::Underline)
1666            .text_decoration(TextDecoration::Overline)
1667            .text_decoration(TextDecoration::LineThrough)
1668            
1669            // Text transform
1670            .text_transform(TextTransform::None)
1671            .text_transform(TextTransform::Uppercase)
1672            .text_transform(TextTransform::Lowercase)
1673            .text_transform(TextTransform::Capitalize)
1674            
1675            // Text overflow
1676            .text_overflow(TextOverflow::Truncate)
1677            .text_overflow(TextOverflow::Ellipsis)
1678            .text_overflow(TextOverflow::Clip)
1679            
1680            // White space
1681            .white_space(WhiteSpace::Normal)
1682            .white_space(WhiteSpace::Nowrap)
1683            .white_space(WhiteSpace::Pre)
1684            .white_space(WhiteSpace::PreLine)
1685            .white_space(WhiteSpace::PreWrap)
1686            .white_space(WhiteSpace::BreakSpaces)
1687            
1688            // Word break
1689            .word_break(WordBreak::Normal)
1690            .word_break(WordBreak::BreakAll)
1691            .word_break(WordBreak::BreakWords)
1692            .word_break(WordBreak::KeepAll)
1693            
1694            // Text decoration style
1695            .text_decoration_style(TextDecorationStyle::Solid)
1696            .text_decoration_style(TextDecorationStyle::Double)
1697            .text_decoration_style(TextDecorationStyle::Dotted)
1698            .text_decoration_style(TextDecorationStyle::Dashed)
1699            .text_decoration_style(TextDecorationStyle::Wavy)
1700            
1701            // Text decoration thickness
1702            .text_decoration_thickness(TextDecorationThickness::Auto)
1703            .text_decoration_thickness(TextDecorationThickness::FromFont)
1704            .text_decoration_thickness(TextDecorationThickness::Zero)
1705            .text_decoration_thickness(TextDecorationThickness::One)
1706            .text_decoration_thickness(TextDecorationThickness::Two)
1707            .text_decoration_thickness(TextDecorationThickness::Four)
1708            .text_decoration_thickness(TextDecorationThickness::Eight)
1709            
1710            // Text underline offset
1711            .text_underline_offset(TextUnderlineOffset::Auto)
1712            .text_underline_offset(TextUnderlineOffset::Zero)
1713            .text_underline_offset(TextUnderlineOffset::One)
1714            .text_underline_offset(TextUnderlineOffset::Two)
1715            .text_underline_offset(TextUnderlineOffset::Four)
1716            .text_underline_offset(TextUnderlineOffset::Eight)
1717            .build();
1718        
1719        let css_classes = classes.to_css_classes();
1720        
1721        // Verify font families
1722        assert!(css_classes.contains("font-sans"));
1723        assert!(css_classes.contains("font-serif"));
1724        assert!(css_classes.contains("font-mono"));
1725        
1726        // Verify font sizes
1727        assert!(css_classes.contains("text-xs"));
1728        assert!(css_classes.contains("text-sm"));
1729        assert!(css_classes.contains("text-base"));
1730        assert!(css_classes.contains("text-lg"));
1731        assert!(css_classes.contains("text-xl"));
1732        assert!(css_classes.contains("text-2xl"));
1733        assert!(css_classes.contains("text-3xl"));
1734        assert!(css_classes.contains("text-4xl"));
1735        assert!(css_classes.contains("text-5xl"));
1736        assert!(css_classes.contains("text-6xl"));
1737        assert!(css_classes.contains("text-7xl"));
1738        assert!(css_classes.contains("text-8xl"));
1739        assert!(css_classes.contains("text-9xl"));
1740        
1741        // Verify font weights
1742        assert!(css_classes.contains("font-thin"));
1743        assert!(css_classes.contains("font-extralight"));
1744        assert!(css_classes.contains("font-light"));
1745        assert!(css_classes.contains("font-normal"));
1746        assert!(css_classes.contains("font-medium"));
1747        assert!(css_classes.contains("font-semibold"));
1748        assert!(css_classes.contains("font-bold"));
1749        assert!(css_classes.contains("font-extrabold"));
1750        assert!(css_classes.contains("font-black"));
1751        
1752        // Verify text alignment
1753        assert!(css_classes.contains("text-left"));
1754        assert!(css_classes.contains("text-center"));
1755        assert!(css_classes.contains("text-right"));
1756        assert!(css_classes.contains("text-justify"));
1757        assert!(css_classes.contains("text-start"));
1758        assert!(css_classes.contains("text-end"));
1759        
1760        // Verify line heights
1761        assert!(css_classes.contains("leading-none"));
1762        assert!(css_classes.contains("leading-3"));
1763        assert!(css_classes.contains("leading-4"));
1764        assert!(css_classes.contains("leading-5"));
1765        assert!(css_classes.contains("leading-6"));
1766        assert!(css_classes.contains("leading-7"));
1767        assert!(css_classes.contains("leading-8"));
1768        assert!(css_classes.contains("leading-9"));
1769        assert!(css_classes.contains("leading-10"));
1770        assert!(css_classes.contains("leading-tight"));
1771        assert!(css_classes.contains("leading-snug"));
1772        assert!(css_classes.contains("leading-normal"));
1773        assert!(css_classes.contains("leading-relaxed"));
1774        assert!(css_classes.contains("leading-loose"));
1775        assert!(css_classes.contains("leading-1.5"));
1776        
1777        // Verify letter spacing
1778        assert!(css_classes.contains("tracking-tighter"));
1779        assert!(css_classes.contains("tracking-tight"));
1780        assert!(css_classes.contains("tracking-normal"));
1781        assert!(css_classes.contains("tracking-wide"));
1782        assert!(css_classes.contains("tracking-wider"));
1783        assert!(css_classes.contains("tracking-widest"));
1784        assert!(css_classes.contains("tracking-0.1"));
1785        
1786        // Verify text decoration
1787        assert!(css_classes.contains("no-underline"));
1788        assert!(css_classes.contains("underline"));
1789        assert!(css_classes.contains("overline"));
1790        assert!(css_classes.contains("line-through"));
1791        
1792        // Verify text transform
1793        assert!(css_classes.contains("normal-case"));
1794        assert!(css_classes.contains("uppercase"));
1795        assert!(css_classes.contains("lowercase"));
1796        assert!(css_classes.contains("capitalize"));
1797        
1798        // Verify text overflow
1799        assert!(css_classes.contains("truncate"));
1800        assert!(css_classes.contains("text-ellipsis"));
1801        assert!(css_classes.contains("text-clip"));
1802        
1803        // Verify white space
1804        assert!(css_classes.contains("whitespace-normal"));
1805        assert!(css_classes.contains("whitespace-nowrap"));
1806        assert!(css_classes.contains("whitespace-pre"));
1807        assert!(css_classes.contains("whitespace-pre-line"));
1808        assert!(css_classes.contains("whitespace-pre-wrap"));
1809        assert!(css_classes.contains("whitespace-break-spaces"));
1810        
1811        // Verify word break
1812        assert!(css_classes.contains("break-normal"));
1813        assert!(css_classes.contains("break-all"));
1814        assert!(css_classes.contains("break-words"));
1815        assert!(css_classes.contains("break-keep"));
1816        
1817        // Verify text decoration style
1818        assert!(css_classes.contains("decoration-solid"));
1819        assert!(css_classes.contains("decoration-double"));
1820        assert!(css_classes.contains("decoration-dotted"));
1821        assert!(css_classes.contains("decoration-dashed"));
1822        assert!(css_classes.contains("decoration-wavy"));
1823        
1824        // Verify text decoration thickness
1825        assert!(css_classes.contains("decoration-auto"));
1826        assert!(css_classes.contains("decoration-from-font"));
1827        assert!(css_classes.contains("decoration-0"));
1828        assert!(css_classes.contains("decoration-1"));
1829        assert!(css_classes.contains("decoration-2"));
1830        assert!(css_classes.contains("decoration-4"));
1831        assert!(css_classes.contains("decoration-8"));
1832        
1833        // Verify text underline offset
1834        assert!(css_classes.contains("underline-offset-auto"));
1835        assert!(css_classes.contains("underline-offset-0"));
1836        assert!(css_classes.contains("underline-offset-1"));
1837        assert!(css_classes.contains("underline-offset-2"));
1838        assert!(css_classes.contains("underline-offset-4"));
1839        assert!(css_classes.contains("underline-offset-8"));
1840    }
1841}