Skip to main content

takumi_css/style/properties/grid/
grid_repeat_track.rs

1use cssparser::Parser;
2
3use super::{parse_line_names, write_space_separated};
4use crate::style::{
5  CssSyntaxKind, CssToken, FromCss, GridTrackSize, MakeComputed, ParseResult, SizingContext, ToCss,
6};
7
8/// Represents a grid repeat track
9#[derive(Debug, Clone, PartialEq)]
10#[non_exhaustive]
11pub struct GridRepeatTrack {
12  /// The size of the grid track
13  pub size: GridTrackSize,
14  /// The names for the line preceding this track within the repeat() clause
15  pub names: Vec<String>,
16  /// The names for the final line after the last track within the repeat() clause
17  /// Only set on the last track of the repeat fragment. For other tracks this is None.
18  pub end_names: Option<Vec<String>>,
19}
20
21impl MakeComputed for GridRepeatTrack {
22  fn make_computed(&mut self, sizing: &SizingContext) {
23    self.size.make_computed(sizing);
24  }
25}
26
27impl<'i> FromCss<'i> for GridRepeatTrack {
28  fn from_css(input: &mut Parser<'i, '_>) -> ParseResult<'i, Self> {
29    // Collect any leading line name blocks: [name1 name2]
30    let mut names: Vec<String> = Vec::new();
31
32    while input.try_parse(Parser::expect_square_bracket_block).is_ok() {
33      names.extend(parse_line_names(input)?);
34    }
35
36    // Parse the track size
37    let size = GridTrackSize::from_css(input)?;
38
39    // Collect any trailing line name blocks
40    while input.try_parse(Parser::expect_square_bracket_block).is_ok() {
41      names.extend(parse_line_names(input)?);
42    }
43
44    Ok(GridRepeatTrack {
45      size,
46      names,
47      end_names: None,
48    })
49  }
50
51  const VALID_TOKENS: &'static [CssToken] = &[
52    CssToken::Syntax(CssSyntaxKind::LineNames),
53    CssToken::Syntax(CssSyntaxKind::TrackSize),
54  ];
55}
56
57impl ToCss for GridRepeatTrack {
58  fn to_css<W: std::fmt::Write>(&self, dest: &mut W) -> std::fmt::Result {
59    if !self.names.is_empty() {
60      dest.write_str("[")?;
61      write_space_separated(dest, &self.names)?;
62      dest.write_str("] ")?;
63    }
64    self.size.to_css(dest)?;
65    if let Some(end_names) = &self.end_names
66      && !end_names.is_empty()
67    {
68      dest.write_str(" [")?;
69      write_space_separated(dest, end_names)?;
70      dest.write_str("]")?;
71    }
72    Ok(())
73  }
74}
75
76#[cfg(test)]
77mod tests {
78  use crate::style::GridLength;
79
80  use super::*;
81  use cssparser::{Parser, ParserInput};
82
83  #[test]
84  fn test_parse_repeat_track_with_names() {
85    let mut parser_input = ParserInput::new("[a b] 1fr [c]");
86    let mut parser = Parser::new(&mut parser_input);
87    let track = GridRepeatTrack::from_css(&mut parser);
88
89    assert_eq!(
90      track,
91      Ok(GridRepeatTrack {
92        size: GridTrackSize::Fixed(GridLength::Fr(1.0)),
93        names: vec!["a".to_string(), "b".to_string(), "c".to_string()],
94        end_names: None,
95      })
96    );
97  }
98}