whisker_css/prop/
box_model.rs1use crate::css::Css;
7use crate::data_type::LengthPercentage;
8use crate::keyword::BoxSizing;
9use crate::shorthand::padding_margin::MarginValue;
10use crate::value::Size;
11
12impl Css {
13 pub fn width(self, v: impl Into<Size>) -> Self {
18 self.push("width", v.into())
19 }
20
21 pub fn height(self, v: impl Into<Size>) -> Self {
24 self.push("height", v.into())
25 }
26
27 pub fn min_width(self, v: impl Into<Size>) -> Self {
30 self.push("min-width", v.into())
31 }
32
33 pub fn min_height(self, v: impl Into<Size>) -> Self {
36 self.push("min-height", v.into())
37 }
38
39 pub fn max_width(self, v: impl Into<Size>) -> Self {
42 self.push("max-width", v.into())
43 }
44
45 pub fn max_height(self, v: impl Into<Size>) -> Self {
48 self.push("max-height", v.into())
49 }
50
51 pub fn box_sizing(self, v: BoxSizing) -> Self {
56 self.push("box-sizing", v)
57 }
58
59 pub fn aspect_ratio(self, width: f32, height: f32) -> Self {
62 self.push_raw("aspect-ratio", format!("{width} / {height}"))
63 }
64
65 pub fn padding_top(self, v: impl Into<LengthPercentage>) -> Self {
70 self.push("padding-top", v.into())
71 }
72
73 pub fn padding_right(self, v: impl Into<LengthPercentage>) -> Self {
76 self.push("padding-right", v.into())
77 }
78
79 pub fn padding_bottom(self, v: impl Into<LengthPercentage>) -> Self {
82 self.push("padding-bottom", v.into())
83 }
84
85 pub fn padding_left(self, v: impl Into<LengthPercentage>) -> Self {
88 self.push("padding-left", v.into())
89 }
90
91 pub fn margin_top(self, v: impl Into<MarginValue>) -> Self {
96 self.push("margin-top", v.into())
97 }
98
99 pub fn margin_right(self, v: impl Into<MarginValue>) -> Self {
102 self.push("margin-right", v.into())
103 }
104
105 pub fn margin_bottom(self, v: impl Into<MarginValue>) -> Self {
108 self.push("margin-bottom", v.into())
109 }
110
111 pub fn margin_left(self, v: impl Into<MarginValue>) -> Self {
114 self.push("margin-left", v.into())
115 }
116
117 pub fn gap(self, v: impl Into<LengthPercentage>) -> Self {
122 let v = v.into();
123 self.push("row-gap", v.clone()).push("column-gap", v)
124 }
125
126 pub fn row_gap(self, v: impl Into<LengthPercentage>) -> Self {
129 self.push("row-gap", v.into())
130 }
131
132 pub fn column_gap(self, v: impl Into<LengthPercentage>) -> Self {
135 self.push("column-gap", v.into())
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::data_type::{FitContent, MaxContent};
142 use crate::ext::*;
143 use crate::keyword::BoxSizing;
144 use crate::value::Size;
145 use crate::Css;
146
147 #[test]
148 fn width_height_basic() {
149 let s = Css::new().width(px(100)).height(50.percent());
150 assert_eq!(s.to_string(), "width: 100px; height: 50%;");
151 }
152
153 #[test]
154 fn min_max_dimensions() {
155 let s = Css::new()
156 .min_width(px(50))
157 .min_height(px(50))
158 .max_width(percent(80))
159 .max_height(Size::None);
160 assert_eq!(
161 s.to_string(),
162 "min-width: 50px; min-height: 50px; max-width: 80%; max-height: none;"
163 );
164 }
165
166 #[test]
167 fn intrinsic_sizing_keywords() {
168 let s = Css::new()
169 .width(Size::Auto)
170 .height(MaxContent)
171 .min_width(Size::MinContent)
172 .max_width(FitContent::keyword());
173 assert_eq!(
174 s.to_string(),
175 "width: auto; height: max-content; min-width: min-content; max-width: fit-content;"
176 );
177 }
178
179 #[test]
180 fn box_sizing_keyword() {
181 let s = Css::new().box_sizing(BoxSizing::BorderBox);
182 assert_eq!(s.to_string(), "box-sizing: border-box;");
183 }
184
185 #[test]
186 fn aspect_ratio_pair() {
187 let s = Css::new().aspect_ratio(16.0, 9.0);
188 assert_eq!(s.to_string(), "aspect-ratio: 16 / 9;");
189 }
190
191 #[test]
192 fn padding_longhands() {
193 let s = Css::new()
194 .padding_top(px(2))
195 .padding_right(px(4))
196 .padding_bottom(px(6))
197 .padding_left(px(8));
198 assert_eq!(
199 s.to_string(),
200 "padding-top: 2px; padding-right: 4px; padding-bottom: 6px; padding-left: 8px;"
201 );
202 }
203
204 #[test]
205 fn margin_longhands_allow_negatives() {
206 let s = Css::new()
207 .margin_top(px(-4))
208 .margin_right(0.percent())
209 .margin_bottom(px(8))
210 .margin_left(percent(-50.0));
211 assert_eq!(
212 s.to_string(),
213 "margin-top: -4px; margin-right: 0%; margin-bottom: 8px; margin-left: -50%;"
214 );
215 }
216
217 #[test]
218 fn gap_expands_to_row_and_column() {
219 let s = Css::new().gap(px(8));
220 assert_eq!(s.to_string(), "row-gap: 8px; column-gap: 8px;");
221 }
222
223 #[test]
224 fn row_and_column_gap_individual() {
225 let s = Css::new().row_gap(px(4)).column_gap(px(12));
226 assert_eq!(s.to_string(), "row-gap: 4px; column-gap: 12px;");
227 }
228
229 #[test]
230 fn padding_top_override_via_last_write_wins() {
231 let s = Css::new().padding_top(px(8)).padding_top(px(0));
232 assert_eq!(s.to_string(), "padding-top: 0px;");
233 }
234}