Skip to main content

takumi_css/style/properties/grid/
grid_track_size.rs

1use 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
11/// A list of `GridTrackSize`
12pub 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/// Represents a grid track size
28#[derive(Debug, Clone, Copy, PartialEq)]
29#[non_exhaustive]
30pub enum GridTrackSize {
31  /// A minmax() track size
32  MinMax(GridMinMaxSize),
33  /// A fixed track size
34  Fixed(GridLength),
35}
36
37impl GridTrackSize {
38  /// Converts the grid track size to a non-repeated track sizing function.
39  pub fn to_min_max(self, sizing: &SizingContext) -> TrackSizingFunction {
40    match self {
41      // SAFETY: The compact length is a valid track sizing function.
42      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}