1use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum FontFamily {
13 Sans,
15 Serif,
17 Mono,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum FontSize {
24 Xs,
26 Sm,
28 Base,
30 Lg,
32 Xl,
34 Xl2,
36 Xl3,
38 Xl4,
40 Xl5,
42 Xl6,
44 Xl7,
46 Xl8,
48 Xl9,
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
54pub enum FontWeight {
55 Thin,
57 ExtraLight,
59 Light,
61 Normal,
63 Medium,
65 SemiBold,
67 Bold,
69 ExtraBold,
71 Black,
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
77pub enum TextAlign {
78 Left,
80 Center,
82 Right,
84 Justify,
86 Start,
88 End,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
94pub enum LineHeight {
95 None,
97 Three,
99 Four,
101 Five,
103 Six,
105 Seven,
107 Eight,
109 Nine,
111 Ten,
113 Tight,
115 Snug,
117 Normal,
119 Relaxed,
121 Loose,
123 Custom(f32),
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
129pub enum LetterSpacing {
130 Tighter,
132 Tight,
134 Normal,
136 Wide,
138 Wider,
140 Widest,
142 Custom(f32),
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
148pub enum TextDecoration {
149 None,
151 Underline,
153 Overline,
155 LineThrough,
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
161pub enum TextDecorationStyle {
162 Solid,
164 Double,
166 Dotted,
168 Dashed,
170 Wavy,
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
176pub enum TextDecorationThickness {
177 Auto,
179 FromFont,
181 Zero,
183 One,
185 Two,
187 Four,
189 Eight,
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
195pub enum TextUnderlineOffset {
196 Auto,
198 Zero,
200 One,
202 Two,
204 Four,
206 Eight,
208}
209
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
212pub enum TextTransform {
213 None,
215 Uppercase,
217 Lowercase,
219 Capitalize,
221}
222
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
225pub enum TextOverflow {
226 Truncate,
228 Ellipsis,
230 Clip,
232}
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
236pub enum WhiteSpace {
237 Normal,
239 Nowrap,
241 Pre,
243 PreLine,
245 PreWrap,
247 BreakSpaces,
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
253pub enum WordBreak {
254 Normal,
256 BreakAll,
258 BreakWords,
260 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 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
747pub trait FontFamilyUtilities {
749 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
759pub trait FontSizeUtilities {
761 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
771pub trait FontWeightUtilities {
773 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
783pub trait TextAlignUtilities {
785 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
795pub trait LineHeightUtilities {
797 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
807pub trait LetterSpacingUtilities {
809 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
819pub trait TextDecorationUtilities {
821 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
831pub trait TextTransformUtilities {
833 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
843pub trait TextOverflowUtilities {
845 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
855pub trait WhiteSpaceUtilities {
857 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
867pub trait WordBreakUtilities {
869 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
879pub trait TextDecorationStyleUtilities {
881 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
891pub trait TextDecorationThicknessUtilities {
893 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
903pub trait TextUnderlineOffsetUtilities {
905 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]
1113 fn test_all_tailwind_font_sizes() {
1114 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]
1142 fn test_week4_typography_utilities() {
1143 let classes = ClassBuilder::new()
1145 .font_size(FontSize::Xs)
1147 .font_size(FontSize::Xl9)
1148 .font_weight(FontWeight::Thin)
1150 .font_weight(FontWeight::Black)
1151 .line_height(LineHeight::Tight)
1153 .line_height(LineHeight::Relaxed)
1154 .letter_spacing(LetterSpacing::Tighter)
1156 .letter_spacing(LetterSpacing::Widest)
1157 .text_decoration(TextDecoration::Underline)
1159 .text_decoration(TextDecoration::None)
1160 .text_decoration(TextDecoration::LineThrough)
1161 .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 assert!(css_classes.contains("text-xs"));
1171 assert!(css_classes.contains("text-9xl"));
1172
1173 assert!(css_classes.contains("font-thin"));
1175 assert!(css_classes.contains("font-black"));
1176
1177 assert!(css_classes.contains("leading-tight"));
1179 assert!(css_classes.contains("leading-relaxed"));
1180
1181 assert!(css_classes.contains("tracking-tighter"));
1183 assert!(css_classes.contains("tracking-widest"));
1184
1185 assert!(css_classes.contains("underline"));
1187 assert!(css_classes.contains("no-underline"));
1188 assert!(css_classes.contains("line-through"));
1189
1190 assert!(css_classes.contains("uppercase"));
1192 assert!(css_classes.contains("lowercase"));
1193 assert!(css_classes.contains("capitalize"));
1194 }
1195
1196 #[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]
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 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 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 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]
1268 fn test_comprehensive_extended_typography() {
1269 let classes = ClassBuilder::new()
1270 .line_height(LineHeight::Three)
1272 .line_height(LineHeight::Ten)
1273 .text_decoration(TextDecoration::Underline)
1275 .text_decoration_style(TextDecorationStyle::Wavy)
1276 .text_decoration_thickness(TextDecorationThickness::Two)
1277 .text_underline_offset(TextUnderlineOffset::Four)
1278 .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 assert!(css_classes.contains("leading-3"));
1289 assert!(css_classes.contains("leading-10"));
1290
1291 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 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]
1306 fn test_line_height_all_values() {
1307 let all_values = LineHeight::all_values();
1308 assert_eq!(all_values.len(), 14); 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 let classes = ClassBuilder::new()
1598 .font_family(FontFamily::Sans)
1600 .font_family(FontFamily::Serif)
1601 .font_family(FontFamily::Mono)
1602
1603 .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_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_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_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(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(TextDecoration::None)
1665 .text_decoration(TextDecoration::Underline)
1666 .text_decoration(TextDecoration::Overline)
1667 .text_decoration(TextDecoration::LineThrough)
1668
1669 .text_transform(TextTransform::None)
1671 .text_transform(TextTransform::Uppercase)
1672 .text_transform(TextTransform::Lowercase)
1673 .text_transform(TextTransform::Capitalize)
1674
1675 .text_overflow(TextOverflow::Truncate)
1677 .text_overflow(TextOverflow::Ellipsis)
1678 .text_overflow(TextOverflow::Clip)
1679
1680 .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(WordBreak::Normal)
1690 .word_break(WordBreak::BreakAll)
1691 .word_break(WordBreak::BreakWords)
1692 .word_break(WordBreak::KeepAll)
1693
1694 .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(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(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 assert!(css_classes.contains("font-sans"));
1723 assert!(css_classes.contains("font-serif"));
1724 assert!(css_classes.contains("font-mono"));
1725
1726 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 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 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 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 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 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 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 assert!(css_classes.contains("truncate"));
1800 assert!(css_classes.contains("text-ellipsis"));
1801 assert!(css_classes.contains("text-clip"));
1802
1803 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 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 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 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 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}