1mod animation;
7mod aspect_ratio;
8mod background;
9mod background_image;
10mod background_position;
11mod background_repeat;
12mod background_size;
13mod background_size_resolve;
14mod blend_mode;
15mod border;
16mod box_alignment;
17mod box_shadow;
18mod clip_path;
19mod color;
20mod conic_gradient;
21mod content;
22mod filter;
23mod flex;
24mod flex_grow;
25mod font_family;
26mod font_feature_settings;
27mod font_size;
28mod font_stretch;
29mod font_style;
30mod font_synthesis;
31mod font_variation_settings;
32mod font_weight;
33mod gradient_utils;
34mod grid;
35mod length;
36mod line_clamp;
37mod line_height;
38mod linear_gradient;
39mod order;
40mod overflow;
41mod overflow_wrap;
42mod percentage_number;
43mod radial_gradient;
44mod sides;
45mod space_pair;
46mod text_decoration;
47mod text_fit;
48mod text_indent;
49mod text_overflow;
50mod text_shadow;
51mod text_stroke;
52mod text_wrap;
53mod traits;
54mod transform;
55mod vertical_align;
56mod white_space;
57mod word_break;
58mod z_index;
59
60pub use animation::*;
61pub use aspect_ratio::*;
62pub use background::*;
63pub use background_image::*;
64pub use background_position::*;
65pub use background_repeat::*;
66pub use background_size::*;
67pub use background_size_resolve::*;
68pub use blend_mode::*;
69pub use border::*;
70pub use box_alignment::*;
71pub use box_shadow::*;
72pub use clip_path::*;
73pub use color::*;
74pub use conic_gradient::*;
75pub use content::*;
76pub use filter::*;
77pub use flex::*;
78pub use flex_grow::*;
79pub use font_family::*;
80pub use font_feature_settings::*;
81pub use font_size::*;
82pub use font_stretch::*;
83pub use font_style::*;
84pub use font_synthesis::*;
85pub use font_variation_settings::*;
86pub use font_weight::*;
87pub use gradient_utils::{GradientOverlayTile, overlay_gradient_tile_fast_normal_unconstrained};
88pub use grid::*;
89pub use length::*;
90pub use line_clamp::*;
91pub use line_height::*;
92pub use linear_gradient::*;
93pub use order::*;
94pub use overflow::*;
95pub use overflow_wrap::*;
96pub use percentage_number::*;
97pub use radial_gradient::*;
98use serde::Deserialize;
99pub use sides::*;
100pub use space_pair::*;
101pub use text_decoration::*;
102pub use text_fit::*;
103pub use text_indent::*;
104pub use text_overflow::*;
105pub use text_shadow::*;
106pub use text_stroke::*;
107pub use text_wrap::*;
108pub use traits::*;
109pub(crate) use traits::{
110 declare_box_alignment_enum_impl, declare_enum_from_css_impl, impl_from_taffy_enum,
111};
112pub use transform::*;
113pub use vertical_align::*;
114pub use white_space::*;
115pub use word_break::*;
116pub use z_index::*;
117
118use cssparser::{Parser, match_ignore_ascii_case};
119use image::imageops::FilterType;
120use parley::Alignment;
121use std::fmt;
122
123use crate::style::{SizingContext, tw::TailwindPropertyParser};
124
125pub(crate) fn next_is_comma<'i>(input: &mut Parser<'i, '_>) -> bool {
126 let state = input.state();
127 let is_comma = input.expect_comma().is_ok();
128 input.reset(&state);
129 is_comma
130}
131
132impl<T: Animatable + Copy> Animatable for SpacePair<T> {
133 fn interpolate(
134 &mut self,
135 from: &Self,
136 to: &Self,
137 progress: f32,
138 sizing: &SizingContext,
139 current_color: Color,
140 ) {
141 self
142 .x
143 .interpolate(&from.x, &to.x, progress, sizing, current_color);
144 self
145 .y
146 .interpolate(&from.y, &to.y, progress, sizing, current_color);
147 }
148}
149
150impl<T: Animatable + Copy> Animatable for Sides<T> {
151 fn interpolate(
152 &mut self,
153 from: &Self,
154 to: &Self,
155 progress: f32,
156 sizing: &SizingContext,
157 current_color: Color,
158 ) {
159 for (index, value) in self.0.iter_mut().enumerate() {
160 value.interpolate(
161 &from.0[index],
162 &to.0[index],
163 progress,
164 sizing,
165 current_color,
166 );
167 }
168 }
169}
170
171macro_rules! unexpected_token {
172 (@build $type:ty, $location:expr, $token:expr $(,)?) => {{
173 let location = $location;
174 let token = $token;
175 let token = cssparser::ToCss::to_css_string(token);
176 let message = <$type as $crate::style::FromCss>::EXPECT_MESSAGE
177 .build_message(&token, $crate::style::merge_enum_values(<$type as $crate::style::FromCss>::VALID_TOKENS));
178
179 cssparser::ParseError {
180 location,
181 kind: cssparser::ParseErrorKind::Custom(std::borrow::Cow::Owned(message)),
182 }
183 }};
184 ($type:ty, $location:expr, $token:expr $(,)?) => {
185 $crate::style::unexpected_token!(@build $type, $location, $token)
186 };
187 ($location:expr, $token:expr $(,)?) => {
188 $crate::style::unexpected_token!(@build Self, $location, $token)
189 };
190}
191
192pub(crate) use unexpected_token;
193
194pub(crate) fn merge_enum_values(values: &[CssToken]) -> String {
199 match values.len() {
200 0 => String::new(),
201 1 => values[0].to_string(),
202 2 => format!("{} or {}", values[0], values[1]),
203 _ => {
204 let all_but_last = values[..values.len() - 1]
205 .iter()
206 .map(ToString::to_string)
207 .collect::<Vec<_>>()
208 .join(", ");
209 format!("{} or {}", all_but_last, values[values.len() - 1])
210 }
211 }
212}
213
214pub(crate) fn write_css_string<W: fmt::Write>(dest: &mut W, s: &str) -> fmt::Result {
216 dest.write_char('"')?;
217 for ch in s.chars() {
218 match ch {
219 '\\' => dest.write_str("\\\\")?,
220 '"' => dest.write_str("\\\"")?,
221 c => dest.write_char(c)?,
222 }
223 }
224 dest.write_char('"')
225}
226
227#[derive(Debug, Clone, Copy, PartialEq, Default)]
231pub enum ObjectFit {
232 #[default]
234 Fill,
235 Contain,
237 Cover,
239 ScaleDown,
241 None,
243}
244
245declare_enum_from_css_impl!(
246 ObjectFit,
247 "fill" => ObjectFit::Fill,
248 "contain" => ObjectFit::Contain,
249 "cover" => ObjectFit::Cover,
250 "scale-down" => ObjectFit::ScaleDown,
251 "none" => ObjectFit::None
252);
253
254impl TailwindPropertyParser for ObjectFit {
255 fn parse_tw(token: &str) -> Option<Self> {
256 Self::from_str(token).ok()
257 }
258}
259
260#[derive(Debug, Clone, Copy, PartialEq, Default)]
262#[non_exhaustive]
263pub enum BackgroundClip {
264 #[default]
266 BorderBox,
267 PaddingBox,
269 ContentBox,
271 Text,
273 BorderArea,
275}
276
277declare_enum_from_css_impl!(
278 BackgroundClip,
279 "border-box" => BackgroundClip::BorderBox,
280 "padding-box" => BackgroundClip::PaddingBox,
281 "content-box" => BackgroundClip::ContentBox,
282 "text" => BackgroundClip::Text,
283 "border-area" => BackgroundClip::BorderArea
284);
285
286impl TailwindPropertyParser for BackgroundClip {
287 fn parse_tw(token: &str) -> Option<Self> {
288 match_ignore_ascii_case! {token,
289 "border" => Some(BackgroundClip::BorderBox),
290 "padding" => Some(BackgroundClip::PaddingBox),
291 "content" => Some(BackgroundClip::ContentBox),
292 "text" => Some(BackgroundClip::Text),
293 _ => None,
294 }
295 }
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Default)]
302pub struct BorderRadius(pub Sides<SpacePair<LengthDefaultsToZero>>);
303
304impl From<f32> for BorderRadius {
305 fn from(value: f32) -> Self {
306 Self(Sides(
307 [SpacePair::from_pair(Length::Px(value), Length::Px(value)); 4],
308 ))
309 }
310}
311
312impl MakeComputed for BorderRadius {
313 fn make_computed(&mut self, sizing: &SizingContext) {
314 self.0.make_computed(sizing);
315 }
316}
317
318impl Animatable for BorderRadius {
319 fn interpolate(
320 &mut self,
321 from: &Self,
322 to: &Self,
323 progress: f32,
324 sizing: &SizingContext,
325 current_color: Color,
326 ) {
327 self
328 .0
329 .interpolate(&from.0, &to.0, progress, sizing, current_color);
330 }
331}
332
333impl<'i> FromCss<'i> for BorderRadius {
334 fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
335 let widths: Sides<LengthDefaultsToZero> = Sides::from_css(input)?;
336
337 let heights = if input.try_parse(|input| input.expect_delim('/')).is_ok() {
338 Sides::from_css(input)?
339 } else {
340 widths
341 };
342
343 Ok(BorderRadius(Sides([
344 SpacePair::from_pair(widths.0[0], heights.0[0]),
345 SpacePair::from_pair(widths.0[1], heights.0[1]),
346 SpacePair::from_pair(widths.0[2], heights.0[2]),
347 SpacePair::from_pair(widths.0[3], heights.0[3]),
348 ])))
349 }
350
351 const EXPECT_MESSAGE: CssExpectedMessage = CssExpectedMessage::BorderRadius;
352
353 const VALID_TOKENS: &'static [CssToken] = &[CssToken::Syntax(CssSyntaxKind::Length)];
354}
355
356#[derive(Default, Debug, Clone, Copy, PartialEq)]
360#[non_exhaustive]
361pub enum BoxSizing {
362 ContentBox,
364 #[default]
366 BorderBox,
367}
368
369declare_enum_from_css_impl!(
370 BoxSizing,
371 "content-box" => BoxSizing::ContentBox,
372 "border-box" => BoxSizing::BorderBox
373);
374
375impl_from_taffy_enum!(BoxSizing, taffy::BoxSizing, ContentBox, BorderBox);
376
377#[derive(Default, Debug, Clone, Copy, PartialEq)]
381#[non_exhaustive]
382pub enum TextAlign {
383 Left,
385 Right,
387 Center,
389 Justify,
391 #[default]
393 Start,
394 End,
396}
397
398declare_enum_from_css_impl!(
399 TextAlign,
400 "left" => TextAlign::Left,
401 "right" => TextAlign::Right,
402 "center" => TextAlign::Center,
403 "justify" => TextAlign::Justify,
404 "start" => TextAlign::Start,
405 "end" => TextAlign::End
406);
407
408impl TailwindPropertyParser for TextAlign {
409 fn parse_tw(token: &str) -> Option<Self> {
410 Self::from_str(token).ok()
411 }
412}
413
414impl_from_taffy_enum!(
415 TextAlign, Alignment, Left, Right, Center, Justify, Start, End
416);
417
418#[derive(Debug, Clone, Copy, PartialEq, Default)]
420#[non_exhaustive]
421pub enum Isolation {
422 Isolate,
424 #[default]
426 Auto,
427}
428
429declare_enum_from_css_impl!(
430 Isolation,
431 "isolate" => Isolation::Isolate,
432 "auto" => Isolation::Auto
433);
434
435#[derive(Debug, Clone, Copy, PartialEq, Default)]
440#[non_exhaustive]
441pub enum Visibility {
442 #[default]
444 Visible,
445 Hidden,
447}
448
449declare_enum_from_css_impl!(
450 Visibility,
451 "visible" => Visibility::Visible,
452 "hidden" => Visibility::Hidden
453);
454
455#[derive(Default, Debug, Clone, Copy, PartialEq)]
457pub enum LineJoin {
458 #[default]
460 Miter,
461 Round,
463 Bevel,
465}
466
467declare_enum_from_css_impl!(
468 LineJoin,
469 "miter" => LineJoin::Miter,
470 "round" => LineJoin::Round,
471 "bevel" => LineJoin::Bevel
472);
473
474impl TailwindPropertyParser for LineJoin {
475 fn parse_tw(token: &str) -> Option<Self> {
476 Self::from_str(token).ok()
477 }
478}
479
480#[derive(Default, Debug, Clone, Copy, PartialEq)]
484pub enum Position {
485 #[default]
488 Relative,
489 Absolute,
492 Static,
495 Fixed,
497}
498
499declare_enum_from_css_impl!(
500 Position,
501 "relative" => Position::Relative,
502 "absolute" => Position::Absolute,
503 "static" => Position::Static,
504 "fixed" => Position::Fixed
505);
506
507impl From<Position> for taffy::Position {
508 fn from(value: Position) -> Self {
509 match value {
510 Position::Relative | Position::Static => Self::Relative,
511 Position::Absolute | Position::Fixed => Self::Absolute,
512 }
513 }
514}
515
516impl Position {
517 pub const fn is_positioned(self) -> bool {
520 matches!(self, Self::Relative | Self::Absolute | Self::Fixed)
521 }
522
523 pub const fn is_out_of_flow(self) -> bool {
525 matches!(self, Self::Absolute | Self::Fixed)
526 }
527}
528
529#[derive(Default, Debug, Clone, Copy, PartialEq, Deserialize)]
531#[serde(rename_all = "kebab-case")]
532pub enum Direction {
533 #[default]
535 Ltr,
536 Rtl,
538}
539
540declare_enum_from_css_impl!(
541 Direction,
542 "ltr" => Direction::Ltr,
543 "rtl" => Direction::Rtl
544);
545
546impl_from_taffy_enum!(Direction, taffy::Direction, Ltr, Rtl);
547
548#[derive(Default, Debug, Clone, Copy, PartialEq)]
550#[non_exhaustive]
551pub enum Float {
552 #[default]
554 None,
555 Left,
557 Right,
559 InlineStart,
561 InlineEnd,
563}
564
565declare_enum_from_css_impl!(
566 Float,
567 "none" => Float::None,
568 "left" => Float::Left,
569 "right" => Float::Right,
570 "inline-start" => Float::InlineStart,
571 "inline-end" => Float::InlineEnd,
572);
573
574impl Float {
575 pub fn resolve(self, direction: Direction) -> taffy::Float {
577 match self {
578 Self::None => taffy::Float::None,
579 Self::Left => taffy::Float::Left,
580 Self::Right => taffy::Float::Right,
581 Self::InlineStart => {
582 if direction == Direction::Rtl {
583 taffy::Float::Right
584 } else {
585 taffy::Float::Left
586 }
587 }
588 Self::InlineEnd => {
589 if direction == Direction::Rtl {
590 taffy::Float::Left
591 } else {
592 taffy::Float::Right
593 }
594 }
595 }
596 }
597}
598
599#[derive(Default, Debug, Clone, Copy, PartialEq)]
601#[non_exhaustive]
602pub enum Clear {
603 #[default]
605 None,
606 Left,
608 Right,
610 Both,
612 InlineStart,
614 InlineEnd,
616}
617
618declare_enum_from_css_impl!(
619 Clear,
620 "none" => Clear::None,
621 "left" => Clear::Left,
622 "right" => Clear::Right,
623 "both" => Clear::Both,
624 "inline-start" => Clear::InlineStart,
625 "inline-end" => Clear::InlineEnd,
626);
627
628impl Clear {
629 pub fn resolve(self, direction: Direction) -> taffy::Clear {
631 match self {
632 Self::None => taffy::Clear::None,
633 Self::Left => taffy::Clear::Left,
634 Self::Right => taffy::Clear::Right,
635 Self::Both => taffy::Clear::Both,
636 Self::InlineStart => {
637 if direction == Direction::Rtl {
638 taffy::Clear::Right
639 } else {
640 taffy::Clear::Left
641 }
642 }
643 Self::InlineEnd => {
644 if direction == Direction::Rtl {
645 taffy::Clear::Left
646 } else {
647 taffy::Clear::Right
648 }
649 }
650 }
651 }
652}
653
654#[derive(Debug, Clone, Copy, PartialEq, Default)]
658#[non_exhaustive]
659pub enum FlexDirection {
660 #[default]
662 Row,
663 Column,
665 RowReverse,
667 ColumnReverse,
669}
670
671declare_enum_from_css_impl!(
672 FlexDirection,
673 "row" => FlexDirection::Row,
674 "column" => FlexDirection::Column,
675 "row-reverse" => FlexDirection::RowReverse,
676 "column-reverse" => FlexDirection::ColumnReverse
677);
678
679impl_from_taffy_enum!(
680 FlexDirection,
681 taffy::FlexDirection,
682 Row,
683 Column,
684 RowReverse,
685 ColumnReverse
686);
687
688#[derive(Debug, Clone, Copy, PartialEq, Default)]
693#[non_exhaustive]
694pub enum JustifyContent {
695 #[default]
697 Normal,
698 Start,
700 End,
702 FlexStart,
706 FlexEnd,
710 Center,
712 Stretch,
714 SpaceBetween,
717 SpaceEvenly,
719 SpaceAround,
723 SafeStart,
725 SafeEnd,
727 SafeFlexStart,
729 SafeFlexEnd,
731 SafeCenter,
733}
734
735declare_box_alignment_enum_impl!(
736 JustifyContent,
737 safe {
738 "start" => Start / SafeStart,
739 "end" => End / SafeEnd,
740 "flex-start" => FlexStart / SafeFlexStart,
741 "flex-end" => FlexEnd / SafeFlexEnd,
742 "center" => Center / SafeCenter,
743 },
744 plain {
745 "normal" => Normal,
746 "stretch" => Stretch,
747 "space-between" => SpaceBetween,
748 "space-around" => SpaceAround,
749 "space-evenly" => SpaceEvenly,
750 }
751);
752
753impl TailwindPropertyParser for JustifyContent {
754 fn parse_tw(token: &str) -> Option<Self> {
755 match token {
756 "between" => Some(JustifyContent::SpaceBetween),
757 "around" => Some(JustifyContent::SpaceAround),
758 "evenly" => Some(JustifyContent::SpaceEvenly),
759 _ => Self::from_str(token).ok(),
760 }
761 }
762}
763
764impl From<JustifyContent> for Option<taffy::JustifyContent> {
765 fn from(value: JustifyContent) -> Self {
766 match value {
767 JustifyContent::Normal => None,
768 JustifyContent::Start => Some(taffy::JustifyContent::START),
769 JustifyContent::End => Some(taffy::JustifyContent::END),
770 JustifyContent::FlexStart => Some(taffy::JustifyContent::FLEX_START),
771 JustifyContent::FlexEnd => Some(taffy::JustifyContent::FLEX_END),
772 JustifyContent::Center => Some(taffy::JustifyContent::CENTER),
773 JustifyContent::Stretch => Some(taffy::JustifyContent::STRETCH),
774 JustifyContent::SpaceBetween => Some(taffy::JustifyContent::SPACE_BETWEEN),
775 JustifyContent::SpaceAround => Some(taffy::JustifyContent::SPACE_AROUND),
776 JustifyContent::SpaceEvenly => Some(taffy::JustifyContent::SPACE_EVENLY),
777 JustifyContent::SafeStart => Some(taffy::JustifyContent::SAFE_START),
778 JustifyContent::SafeEnd => Some(taffy::JustifyContent::SAFE_END),
779 JustifyContent::SafeFlexStart => Some(taffy::JustifyContent::SAFE_FLEX_START),
780 JustifyContent::SafeFlexEnd => Some(taffy::JustifyContent::SAFE_FLEX_END),
781 JustifyContent::SafeCenter => Some(taffy::JustifyContent::SAFE_CENTER),
782 }
783 }
784}
785
786#[derive(Debug, Clone, Copy, PartialEq, Default)]
788#[non_exhaustive]
789pub enum Display {
790 None,
792 Flex,
794 InlineFlex,
796 Grid,
798 InlineGrid,
800 #[default]
802 Inline,
803 Block,
805 InlineBlock,
807}
808
809declare_enum_from_css_impl!(
810 Display,
811 "none" => Display::None,
812 "flex" => Display::Flex,
813 "inline-flex" => Display::InlineFlex,
814 "grid" => Display::Grid,
815 "inline-grid" => Display::InlineGrid,
816 "inline" => Display::Inline,
817 "block" => Display::Block,
818 "inline-block" => Display::InlineBlock
819);
820
821impl Display {
822 pub fn is_inline(&self) -> bool {
824 *self == Display::Inline
825 }
826
827 pub fn is_inline_level(&self) -> bool {
829 matches!(
830 self,
831 Display::Inline | Display::InlineBlock | Display::InlineFlex | Display::InlineGrid
832 )
833 }
834
835 pub fn should_blockify_children(&self) -> bool {
837 matches!(
838 self,
839 Display::Flex | Display::InlineFlex | Display::Grid | Display::InlineGrid
840 )
841 }
842
843 pub fn as_blockified(self) -> Self {
845 match self {
846 Display::Inline => Display::Block,
847 Display::InlineBlock => Display::Block,
848 Display::InlineFlex => Display::Flex,
849 Display::InlineGrid => Display::Grid,
850 _ => self,
851 }
852 }
853
854 pub fn blockify(&mut self) {
856 *self = self.as_blockified();
857 }
858}
859
860impl From<Display> for taffy::Display {
861 fn from(value: Display) -> Self {
862 match value {
863 Display::Flex | Display::InlineFlex => taffy::Display::Flex,
864 Display::Grid | Display::InlineGrid => taffy::Display::Grid,
865 Display::Block | Display::InlineBlock | Display::Inline => taffy::Display::Block,
866 Display::None => taffy::Display::None,
867 }
868 }
869}
870
871#[derive(Debug, Clone, Copy, PartialEq, Default)]
876#[non_exhaustive]
877pub enum AlignItems {
878 #[default]
880 Normal,
881 Start,
883 End,
885 FlexStart,
887 FlexEnd,
889 Center,
891 Baseline,
893 Stretch,
895 SafeStart,
897 SafeEnd,
899 SafeFlexStart,
901 SafeFlexEnd,
903 SafeCenter,
905}
906
907declare_box_alignment_enum_impl!(
908 AlignItems,
909 safe {
910 "start" => Start / SafeStart,
911 "end" => End / SafeEnd,
912 "flex-start" => FlexStart / SafeFlexStart,
913 "flex-end" => FlexEnd / SafeFlexEnd,
914 "center" => Center / SafeCenter,
915 },
916 plain {
917 "normal" => Normal,
918 "baseline" => Baseline,
919 "stretch" => Stretch,
920 }
921);
922
923impl TailwindPropertyParser for AlignItems {
924 fn parse_tw(token: &str) -> Option<Self> {
925 Self::from_str(token).ok()
926 }
927}
928
929impl From<AlignItems> for Option<taffy::AlignItems> {
930 fn from(value: AlignItems) -> Self {
931 match value {
932 AlignItems::Normal => None,
933 AlignItems::Start => Some(taffy::AlignItems::START),
934 AlignItems::End => Some(taffy::AlignItems::END),
935 AlignItems::FlexStart => Some(taffy::AlignItems::FLEX_START),
936 AlignItems::FlexEnd => Some(taffy::AlignItems::FLEX_END),
937 AlignItems::Center => Some(taffy::AlignItems::CENTER),
938 AlignItems::Baseline => Some(taffy::AlignItems::BASELINE),
939 AlignItems::Stretch => Some(taffy::AlignItems::STRETCH),
940 AlignItems::SafeStart => Some(taffy::AlignItems::SAFE_START),
941 AlignItems::SafeEnd => Some(taffy::AlignItems::SAFE_END),
942 AlignItems::SafeFlexStart => Some(taffy::AlignItems::SAFE_FLEX_START),
943 AlignItems::SafeFlexEnd => Some(taffy::AlignItems::SAFE_FLEX_END),
944 AlignItems::SafeCenter => Some(taffy::AlignItems::SAFE_CENTER),
945 }
946 }
947}
948
949#[derive(Debug, Clone, Copy, PartialEq, Default)]
953#[non_exhaustive]
954pub enum FlexWrap {
955 #[default]
957 NoWrap,
958 Wrap,
960 WrapReverse,
962}
963
964declare_enum_from_css_impl!(
965 FlexWrap,
966 "nowrap" => FlexWrap::NoWrap,
967 "wrap" => FlexWrap::Wrap,
968 "wrap-reverse" => FlexWrap::WrapReverse
969);
970
971impl_from_taffy_enum!(FlexWrap, taffy::FlexWrap, NoWrap, Wrap, WrapReverse);
972
973#[derive(Debug, Clone, Copy, PartialEq, Default)]
975pub enum TextTransform {
976 #[default]
978 None,
979 Uppercase,
981 Lowercase,
983 Capitalize,
985}
986
987declare_enum_from_css_impl!(
988 TextTransform,
989 "none" => TextTransform::None,
990 "uppercase" => TextTransform::Uppercase,
991 "lowercase" => TextTransform::Lowercase,
992 "capitalize" => TextTransform::Capitalize
993);
994
995#[derive(Debug, Clone, Copy, PartialEq, Default)]
997#[non_exhaustive]
998pub enum TextDecorationSkipInk {
999 #[default]
1001 Auto,
1002 None,
1004}
1005
1006declare_enum_from_css_impl!(
1007 TextDecorationSkipInk,
1008 "auto" => TextDecorationSkipInk::Auto,
1009 "none" => TextDecorationSkipInk::None
1010);
1011
1012#[derive(Debug, Clone, Copy, PartialEq, Default)]
1014pub enum WhiteSpaceCollapse {
1015 Preserve,
1017 #[default]
1019 Collapse,
1020 PreserveSpaces,
1022 PreserveBreaks,
1024}
1025
1026declare_enum_from_css_impl!(
1027 WhiteSpaceCollapse,
1028 "preserve" => WhiteSpaceCollapse::Preserve,
1029 "collapse" => WhiteSpaceCollapse::Collapse,
1030 "preserve-spaces" => WhiteSpaceCollapse::PreserveSpaces,
1031 "preserve-breaks" => WhiteSpaceCollapse::PreserveBreaks,
1032);
1033
1034#[derive(Debug, Clone, Copy, PartialEq, Default)]
1036pub enum ImageScalingAlgorithm {
1037 #[default]
1040 Auto,
1041 Smooth,
1044 Pixelated,
1047}
1048
1049declare_enum_from_css_impl!(
1050 ImageScalingAlgorithm,
1051 "auto" => ImageScalingAlgorithm::Auto,
1052 "smooth" => ImageScalingAlgorithm::Smooth,
1053 "pixelated" => ImageScalingAlgorithm::Pixelated
1054);
1055
1056#[derive(Debug, Default, Clone, Copy, PartialEq)]
1058pub enum BorderStyle {
1059 #[default]
1061 None,
1062 Hidden,
1064 Dotted,
1066 Dashed,
1068 Solid,
1070 Double,
1072 Groove,
1074 Ridge,
1076 Inset,
1078 Outset,
1080}
1081
1082impl BorderStyle {
1083 pub const fn is_rendered(self) -> bool {
1085 !matches!(self, Self::None | Self::Hidden)
1086 }
1087}
1088
1089declare_enum_from_css_impl!(
1090 BorderStyle,
1091 "none" => BorderStyle::None,
1092 "hidden" => BorderStyle::Hidden,
1093 "dotted" => BorderStyle::Dotted,
1094 "dashed" => BorderStyle::Dashed,
1095 "solid" => BorderStyle::Solid,
1096 "double" => BorderStyle::Double,
1097 "groove" => BorderStyle::Groove,
1098 "ridge" => BorderStyle::Ridge,
1099 "inset" => BorderStyle::Inset,
1100 "outset" => BorderStyle::Outset,
1101);
1102
1103impl TailwindPropertyParser for BorderStyle {
1104 fn parse_tw(token: &str) -> Option<Self> {
1105 Self::from_str(token).ok()
1106 }
1107}
1108
1109impl From<ImageScalingAlgorithm> for FilterType {
1110 fn from(algorithm: ImageScalingAlgorithm) -> Self {
1111 match algorithm {
1112 ImageScalingAlgorithm::Auto => FilterType::CatmullRom,
1113 ImageScalingAlgorithm::Smooth => FilterType::Lanczos3,
1114 ImageScalingAlgorithm::Pixelated => FilterType::Nearest,
1115 }
1116 }
1117}