rustyle_css/css/
grid.rs

1//! CSS Grid utilities
2//!
3//! Provides type-safe CSS Grid definitions including templates, areas, and subgrid support.
4
5use super::units::Length;
6
7/// Grid template definition
8#[derive(Clone, Debug)]
9pub struct GridTemplate {
10    columns: Vec<GridTrack>,
11    rows: Vec<GridTrack>,
12    areas: Option<Vec<Vec<String>>>,
13}
14
15/// Grid track (column or row) definition
16#[derive(Clone, Debug)]
17pub enum GridTrack {
18    /// Fixed size (e.g., "200px")
19    Fixed(Length),
20    /// Flexible size (e.g., "1fr")
21    Flexible(f32),
22    /// Minmax function
23    MinMax(Length, Length),
24    /// Repeat function
25    Repeat(u32, Vec<GridTrack>),
26    /// Auto
27    Auto,
28    /// Named line
29    Named(String),
30}
31
32impl GridTrack {
33    /// Convert to CSS string
34    pub fn to_css(&self) -> String {
35        match self {
36            GridTrack::Fixed(len) => len.to_css(),
37            GridTrack::Flexible(fr) => format!("{}fr", fr),
38            GridTrack::MinMax(min, max) => format!("minmax({}, {})", min.to_css(), max.to_css()),
39            GridTrack::Repeat(count, tracks) => {
40                let tracks_str = tracks
41                    .iter()
42                    .map(|t| t.to_css())
43                    .collect::<Vec<_>>()
44                    .join(" ");
45                format!("repeat({}, {})", count, tracks_str)
46            }
47            GridTrack::Auto => "auto".to_string(),
48            GridTrack::Named(name) => format!("[{}]", name),
49        }
50    }
51}
52
53impl GridTemplate {
54    /// Create a new grid template
55    pub fn new() -> Self {
56        Self {
57            columns: Vec::new(),
58            rows: Vec::new(),
59            areas: None,
60        }
61    }
62
63    /// Add columns
64    pub fn columns(mut self, cols: Vec<GridTrack>) -> Self {
65        self.columns = cols;
66        self
67    }
68
69    /// Add rows
70    pub fn rows(mut self, rows: Vec<GridTrack>) -> Self {
71        self.rows = rows;
72        self
73    }
74
75    /// Set grid areas
76    pub fn areas(mut self, areas: Vec<Vec<String>>) -> Self {
77        self.areas = Some(areas);
78        self
79    }
80
81    /// Convert to CSS string
82    pub fn to_css(&self) -> String {
83        let mut css = String::new();
84
85        if !self.columns.is_empty() {
86            let cols_str = self
87                .columns
88                .iter()
89                .map(|t| t.to_css())
90                .collect::<Vec<_>>()
91                .join(" ");
92            css.push_str(&format!("grid-template-columns: {}; ", cols_str));
93        }
94
95        if !self.rows.is_empty() {
96            let rows_str = self
97                .rows
98                .iter()
99                .map(|t| t.to_css())
100                .collect::<Vec<_>>()
101                .join(" ");
102            css.push_str(&format!("grid-template-rows: {}; ", rows_str));
103        }
104
105        if let Some(ref areas) = self.areas {
106            let areas_str = areas
107                .iter()
108                .map(|row| format!("\"{}\"", row.join(" ")))
109                .collect::<Vec<_>>()
110                .join(" ");
111            css.push_str(&format!("grid-template-areas: {}; ", areas_str));
112        }
113
114        css
115    }
116}
117
118impl Default for GridTemplate {
119    fn default() -> Self {
120        Self::new()
121    }
122}
123
124/// Grid area definition
125#[derive(Clone, Debug)]
126pub struct GridArea {
127    pub name: String,
128    pub row_start: Option<String>,
129    pub column_start: Option<String>,
130    pub row_end: Option<String>,
131    pub column_end: Option<String>,
132}
133
134impl GridArea {
135    /// Create a new grid area
136    pub fn new(name: &str) -> Self {
137        Self {
138            name: name.to_string(),
139            row_start: None,
140            column_start: None,
141            row_end: None,
142            column_end: None,
143        }
144    }
145
146    /// Set row start
147    pub fn row_start(mut self, start: &str) -> Self {
148        self.row_start = Some(start.to_string());
149        self
150    }
151
152    /// Set column start
153    pub fn column_start(mut self, start: &str) -> Self {
154        self.column_start = Some(start.to_string());
155        self
156    }
157
158    /// Set row end
159    pub fn row_end(mut self, end: &str) -> Self {
160        self.row_end = Some(end.to_string());
161        self
162    }
163
164    /// Set column end
165    pub fn column_end(mut self, end: &str) -> Self {
166        self.column_end = Some(end.to_string());
167        self
168    }
169
170    /// Convert to CSS string
171    pub fn to_css(&self) -> String {
172        let mut props = Vec::new();
173
174        props.push(format!("grid-area: {};", self.name));
175
176        if let Some(ref start) = self.row_start {
177            props.push(format!("grid-row-start: {};", start));
178        }
179
180        if let Some(ref start) = self.column_start {
181            props.push(format!("grid-column-start: {};", start));
182        }
183
184        if let Some(ref end) = self.row_end {
185            props.push(format!("grid-row-end: {};", end));
186        }
187
188        if let Some(ref end) = self.column_end {
189            props.push(format!("grid-column-end: {};", end));
190        }
191
192        props.join(" ")
193    }
194}
195
196/// Subgrid support
197#[derive(Clone, Debug)]
198pub struct Subgrid {
199    pub columns: bool,
200    pub rows: bool,
201}
202
203impl Subgrid {
204    /// Create subgrid for both columns and rows
205    pub fn both() -> Self {
206        Self {
207            columns: true,
208            rows: true,
209        }
210    }
211
212    /// Create subgrid for columns only
213    pub fn columns() -> Self {
214        Self {
215            columns: true,
216            rows: false,
217        }
218    }
219
220    /// Create subgrid for rows only
221    pub fn rows() -> Self {
222        Self {
223            columns: false,
224            rows: true,
225        }
226    }
227
228    /// Convert to CSS string
229    pub fn to_css(&self) -> String {
230        match (self.columns, self.rows) {
231            (true, true) => "subgrid".to_string(),
232            (true, false) => "subgrid / none".to_string(),
233            (false, true) => "none / subgrid".to_string(),
234            (false, false) => "none".to_string(),
235        }
236    }
237}