rustyle_css/css/
layout.rs

1//! CSS layout utilities
2//!
3//! Provides type-safe layout definitions including flexbox, grid, and container queries.
4
5use super::units::Length;
6
7/// Flex direction
8#[derive(Clone, Debug)]
9pub enum FlexDirection {
10    Row,
11    RowReverse,
12    Column,
13    ColumnReverse,
14}
15
16impl FlexDirection {
17    /// Convert to CSS string
18    pub fn to_css(&self) -> String {
19        match self {
20            FlexDirection::Row => "row",
21            FlexDirection::RowReverse => "row-reverse",
22            FlexDirection::Column => "column",
23            FlexDirection::ColumnReverse => "column-reverse",
24        }
25        .to_string()
26    }
27}
28
29/// Justify content
30#[derive(Clone, Debug)]
31pub enum JustifyContent {
32    FlexStart,
33    FlexEnd,
34    Center,
35    SpaceBetween,
36    SpaceAround,
37    SpaceEvenly,
38}
39
40impl JustifyContent {
41    /// Convert to CSS string
42    pub fn to_css(&self) -> String {
43        match self {
44            JustifyContent::FlexStart => "flex-start",
45            JustifyContent::FlexEnd => "flex-end",
46            JustifyContent::Center => "center",
47            JustifyContent::SpaceBetween => "space-between",
48            JustifyContent::SpaceAround => "space-around",
49            JustifyContent::SpaceEvenly => "space-evenly",
50        }
51        .to_string()
52    }
53}
54
55/// Align items
56#[derive(Clone, Debug)]
57pub enum AlignItems {
58    FlexStart,
59    FlexEnd,
60    Center,
61    Baseline,
62    Stretch,
63}
64
65impl AlignItems {
66    /// Convert to CSS string
67    pub fn to_css(&self) -> String {
68        match self {
69            AlignItems::FlexStart => "flex-start",
70            AlignItems::FlexEnd => "flex-end",
71            AlignItems::Center => "center",
72            AlignItems::Baseline => "baseline",
73            AlignItems::Stretch => "stretch",
74        }
75        .to_string()
76    }
77}
78
79/// Display property
80#[derive(Clone, Debug)]
81pub enum Display {
82    Block,
83    Inline,
84    InlineBlock,
85    Flex,
86    Grid,
87    None,
88}
89
90impl Display {
91    /// Convert to CSS string
92    pub fn to_css(&self) -> String {
93        match self {
94            Display::Block => "block",
95            Display::Inline => "inline",
96            Display::InlineBlock => "inline-block",
97            Display::Flex => "flex",
98            Display::Grid => "grid",
99            Display::None => "none",
100        }
101        .to_string()
102    }
103}
104
105/// Flex gap for consistent spacing in flex containers
106#[derive(Clone, Debug)]
107pub struct FlexGap {
108    pub row: Length,
109    pub column: Length,
110}
111
112impl FlexGap {
113    /// Create a flex gap with the same value for row and column
114    pub fn uniform(value: Length) -> Self {
115        Self {
116            row: value.clone(),
117            column: value,
118        }
119    }
120
121    /// Create a flex gap with different row and column values
122    pub fn new(row: Length, column: Length) -> Self {
123        Self { row, column }
124    }
125
126    /// Convert to CSS string
127    pub fn to_css(&self) -> String {
128        if self.row.to_css() == self.column.to_css() {
129            format!("gap: {};", self.row.to_css())
130        } else {
131            format!("gap: {} {};", self.row.to_css(), self.column.to_css())
132        }
133    }
134}
135
136/// Container query condition
137#[derive(Clone, Debug)]
138pub enum ContainerQueryCondition {
139    /// Min width
140    MinWidth(Length),
141    /// Max width
142    MaxWidth(Length),
143    /// Min height
144    MinHeight(Length),
145    /// Max height
146    MaxHeight(Length),
147    /// Aspect ratio
148    AspectRatio(f32, f32),
149    /// Container name
150    Named(String),
151}
152
153/// Container query type
154#[derive(Clone, Debug)]
155pub struct ContainerQuery {
156    pub name: Option<String>,
157    pub conditions: Vec<ContainerQueryCondition>,
158}
159
160impl ContainerQuery {
161    /// Create a new container query
162    pub fn new() -> Self {
163        Self {
164            name: None,
165            conditions: Vec::new(),
166        }
167    }
168
169    /// Set container name
170    pub fn name(mut self, name: &str) -> Self {
171        self.name = Some(name.to_string());
172        self
173    }
174
175    /// Add a condition
176    pub fn condition(mut self, condition: ContainerQueryCondition) -> Self {
177        self.conditions.push(condition);
178        self
179    }
180
181    /// Add min-width condition
182    pub fn min_width(mut self, width: Length) -> Self {
183        self.conditions
184            .push(ContainerQueryCondition::MinWidth(width));
185        self
186    }
187
188    /// Add max-width condition
189    pub fn max_width(mut self, width: Length) -> Self {
190        self.conditions
191            .push(ContainerQueryCondition::MaxWidth(width));
192        self
193    }
194
195    /// Convert to CSS string
196    pub fn to_css(&self) -> String {
197        let mut parts = Vec::new();
198
199        if let Some(ref name) = self.name {
200            parts.push(name.clone());
201        }
202
203        for condition in &self.conditions {
204            let cond_str = match condition {
205                ContainerQueryCondition::MinWidth(w) => format!("(min-width: {})", w.to_css()),
206                ContainerQueryCondition::MaxWidth(w) => format!("(max-width: {})", w.to_css()),
207                ContainerQueryCondition::MinHeight(h) => format!("(min-height: {})", h.to_css()),
208                ContainerQueryCondition::MaxHeight(h) => format!("(max-height: {})", h.to_css()),
209                ContainerQueryCondition::AspectRatio(w, h) => {
210                    format!("(aspect-ratio: {} / {})", w, h)
211                }
212                ContainerQueryCondition::Named(n) => n.clone(),
213            };
214            parts.push(cond_str);
215        }
216
217        format!("@container {} {{", parts.join(" and "))
218    }
219}
220
221impl Default for ContainerQuery {
222    fn default() -> Self {
223        Self::new()
224    }
225}