takumi_css/style/properties/grid/
grid_track_size.rs1use std::fmt::Write;
2
3use cssparser::{Parser, match_ignore_ascii_case};
4use taffy::{MaxTrackSizingFunction, MinTrackSizingFunction, TrackSizingFunction};
5
6use crate::style::{
7 CssDescriptorKind, CssSyntaxKind, CssToken, FromCss, GridLength, GridMinMaxSize, Length,
8 MakeComputed, ParseResult, SizingContext, ToCss, tw::TailwindPropertyParser,
9};
10
11pub type GridTrackSizes = Vec<GridTrackSize>;
13
14impl<'i> FromCss<'i> for GridTrackSizes {
15 fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
16 let mut components: Vec<GridTrackSize> = Vec::new();
17 while let Ok(size) = GridTrackSize::from_css(input) {
18 components.push(size);
19 }
20
21 Ok(components)
22 }
23
24 const VALID_TOKENS: &'static [CssToken] = GridTrackSize::VALID_TOKENS;
25}
26
27#[derive(Debug, Clone, Copy, PartialEq)]
29#[non_exhaustive]
30pub enum GridTrackSize {
31 MinMax(GridMinMaxSize),
33 Fixed(GridLength),
35}
36
37impl GridTrackSize {
38 pub fn to_min_max(self, sizing: &SizingContext) -> TrackSizingFunction {
40 match self {
41 Self::Fixed(size) => unsafe {
43 TrackSizingFunction {
44 min: MinTrackSizingFunction::from_raw(size.to_compact_length(sizing)),
45 max: MaxTrackSizingFunction::from_raw(size.to_compact_length(sizing)),
46 }
47 },
48 Self::MinMax(min_max) => unsafe {
49 TrackSizingFunction {
50 min: MinTrackSizingFunction::from_raw(min_max.min.to_compact_length(sizing)),
51 max: MaxTrackSizingFunction::from_raw(min_max.max.to_compact_length(sizing)),
52 }
53 },
54 }
55 }
56}
57
58impl TailwindPropertyParser for GridTrackSize {
59 fn parse_tw(token: &str) -> Option<Self> {
60 let track_size = match_ignore_ascii_case! {token,
61 "auto" => GridTrackSize::Fixed(GridLength::Unit(Length::Auto)),
62 "fr" => GridTrackSize::Fixed(GridLength::Fr(1.0)),
63 _ => return None,
64 };
65 Some(track_size)
66 }
67}
68
69impl<'i> FromCss<'i> for GridTrackSize {
70 fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
71 if input
72 .try_parse(|input| input.expect_function_matching("minmax"))
73 .is_ok()
74 {
75 return input.parse_nested_block(|input| {
76 let min = GridLength::from_css(input)?;
77 input.expect_comma()?;
78 let max = GridLength::from_css(input)?;
79 Ok(GridTrackSize::MinMax(GridMinMaxSize { min, max }))
80 });
81 }
82
83 let length = GridLength::from_css(input)?;
84 Ok(GridTrackSize::Fixed(length))
85 }
86
87 const VALID_TOKENS: &'static [CssToken] = &[
88 CssToken::Descriptor(CssDescriptorKind::MinmaxFn),
89 CssToken::Syntax(CssSyntaxKind::Length),
90 ];
91}
92
93impl MakeComputed for GridTrackSize {
94 fn make_computed(&mut self, sizing: &SizingContext) {
95 match self {
96 GridTrackSize::MinMax(min_max) => min_max.make_computed(sizing),
97 GridTrackSize::Fixed(length) => length.make_computed(sizing),
98 }
99 }
100}
101
102impl ToCss for GridTrackSize {
103 fn to_css<W: Write>(&self, dest: &mut W) -> std::fmt::Result {
104 match self {
105 Self::MinMax(mm) => mm.to_css(dest),
106 Self::Fixed(gl) => gl.to_css(dest),
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use crate::style::Length;
114
115 use super::*;
116
117 #[test]
118 fn test_parse_minmax_and_track_size() {
119 assert_eq!(
120 GridTrackSize::from_str("minmax(10px, 1fr)"),
121 Ok(GridTrackSize::MinMax(GridMinMaxSize {
122 min: GridLength::Unit(Length::Px(10.0)),
123 max: GridLength::Fr(1.0)
124 }))
125 );
126
127 assert_eq!(
128 GridTrackSize::from_str("2fr"),
129 Ok(GridTrackSize::Fixed(GridLength::Fr(2.0)))
130 );
131 }
132}