tailwind_rs_core/utilities/
container_queries.rs1use serde::{Deserialize, Serialize};
7use std::fmt;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum ContainerQuery {
12 InlineSize(ContainerSize),
14 BlockSize(ContainerSize),
16 Width(ContainerSize),
18 Height(ContainerSize),
20 AspectRatio(ContainerAspectRatio),
22 Orientation(ContainerOrientation),
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28pub enum ContainerSize {
29 Xs,
31 Sm,
33 Md,
35 Lg,
37 Xl,
39 Xl2,
41 Custom(String),
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
47pub enum ContainerAspectRatio {
48 Square,
50 Video,
52 Widescreen,
54 Ultrawide,
56 Custom(String),
58}
59
60#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
62pub enum ContainerOrientation {
63 Landscape,
65 Portrait,
67}
68
69impl ContainerQuery {
70 pub fn inline_size(size: ContainerSize) -> Self {
72 Self::InlineSize(size)
73 }
74
75 pub fn block_size(size: ContainerSize) -> Self {
77 Self::BlockSize(size)
78 }
79
80 pub fn width(size: ContainerSize) -> Self {
82 Self::Width(size)
83 }
84
85 pub fn height(size: ContainerSize) -> Self {
87 Self::Height(size)
88 }
89
90 pub fn aspect_ratio(ratio: ContainerAspectRatio) -> Self {
92 Self::AspectRatio(ratio)
93 }
94
95 pub fn orientation(orientation: ContainerOrientation) -> Self {
97 Self::Orientation(orientation)
98 }
99
100 pub fn to_css_query(&self) -> String {
102 match self {
103 ContainerQuery::InlineSize(size) => {
104 format!("@container (inline-size > {})", size.to_css_value())
105 }
106 ContainerQuery::BlockSize(size) => {
107 format!("@container (block-size > {})", size.to_css_value())
108 }
109 ContainerQuery::Width(size) => {
110 format!("@container (width > {})", size.to_css_value())
111 }
112 ContainerQuery::Height(size) => {
113 format!("@container (height > {})", size.to_css_value())
114 }
115 ContainerQuery::AspectRatio(ratio) => {
116 format!("@container (aspect-ratio > {})", ratio.to_css_value())
117 }
118 ContainerQuery::Orientation(orientation) => {
119 format!("@container (orientation: {})", orientation.to_css_value())
120 }
121 }
122 }
123
124 pub fn to_class_name(&self) -> String {
126 match self {
127 ContainerQuery::InlineSize(size) => {
128 format!("@container/inline-size:{}", size.to_class_name())
129 }
130 ContainerQuery::BlockSize(size) => {
131 format!("@container/block-size:{}", size.to_class_name())
132 }
133 ContainerQuery::Width(size) => {
134 format!("@container/width:{}", size.to_class_name())
135 }
136 ContainerQuery::Height(size) => {
137 format!("@container/height:{}", size.to_class_name())
138 }
139 ContainerQuery::AspectRatio(ratio) => {
140 format!("@container/aspect-ratio:{}", ratio.to_class_name())
141 }
142 ContainerQuery::Orientation(orientation) => {
143 format!("@container/orientation:{}", orientation.to_class_name())
144 }
145 }
146 }
147}
148
149impl ContainerSize {
150 pub fn to_css_value(&self) -> String {
152 match self {
153 ContainerSize::Xs => "320px".to_string(),
154 ContainerSize::Sm => "640px".to_string(),
155 ContainerSize::Md => "768px".to_string(),
156 ContainerSize::Lg => "1024px".to_string(),
157 ContainerSize::Xl => "1280px".to_string(),
158 ContainerSize::Xl2 => "1536px".to_string(),
159 ContainerSize::Custom(size) => size.clone(),
160 }
161 }
162
163 pub fn to_class_name(&self) -> String {
165 match self {
166 ContainerSize::Xs => "xs".to_string(),
167 ContainerSize::Sm => "sm".to_string(),
168 ContainerSize::Md => "md".to_string(),
169 ContainerSize::Lg => "lg".to_string(),
170 ContainerSize::Xl => "xl".to_string(),
171 ContainerSize::Xl2 => "2xl".to_string(),
172 ContainerSize::Custom(size) => size.clone(),
173 }
174 }
175}
176
177impl ContainerAspectRatio {
178 pub fn to_css_value(&self) -> String {
180 match self {
181 ContainerAspectRatio::Square => "1/1".to_string(),
182 ContainerAspectRatio::Video => "4/3".to_string(),
183 ContainerAspectRatio::Widescreen => "16/9".to_string(),
184 ContainerAspectRatio::Ultrawide => "21/9".to_string(),
185 ContainerAspectRatio::Custom(ratio) => ratio.clone(),
186 }
187 }
188
189 pub fn to_class_name(&self) -> String {
191 match self {
192 ContainerAspectRatio::Square => "square".to_string(),
193 ContainerAspectRatio::Video => "video".to_string(),
194 ContainerAspectRatio::Widescreen => "widescreen".to_string(),
195 ContainerAspectRatio::Ultrawide => "ultrawide".to_string(),
196 ContainerAspectRatio::Custom(ratio) => ratio.clone(),
197 }
198 }
199}
200
201impl ContainerOrientation {
202 pub fn to_css_value(&self) -> String {
204 match self {
205 ContainerOrientation::Landscape => "landscape".to_string(),
206 ContainerOrientation::Portrait => "portrait".to_string(),
207 }
208 }
209
210 pub fn to_class_name(&self) -> String {
212 match self {
213 ContainerOrientation::Landscape => "landscape".to_string(),
214 ContainerOrientation::Portrait => "portrait".to_string(),
215 }
216 }
217}
218
219impl fmt::Display for ContainerQuery {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 write!(f, "{}", self.to_css_query())
222 }
223}
224
225impl fmt::Display for ContainerSize {
226 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
227 write!(f, "{}", self.to_css_value())
228 }
229}
230
231impl fmt::Display for ContainerAspectRatio {
232 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 write!(f, "{}", self.to_css_value())
234 }
235}
236
237impl fmt::Display for ContainerOrientation {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(f, "{}", self.to_css_value())
240 }
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_inline_size_container_query() {
249 let query = ContainerQuery::inline_size(ContainerSize::Md);
250 assert_eq!(query.to_css_query(), "@container (inline-size > 768px)");
251 assert_eq!(query.to_class_name(), "@container/inline-size:md");
252 }
253
254 #[test]
255 fn test_block_size_container_query() {
256 let query = ContainerQuery::block_size(ContainerSize::Lg);
257 assert_eq!(query.to_css_query(), "@container (block-size > 1024px)");
258 assert_eq!(query.to_class_name(), "@container/block-size:lg");
259 }
260
261 #[test]
262 fn test_width_container_query() {
263 let query = ContainerQuery::width(ContainerSize::Sm);
264 assert_eq!(query.to_css_query(), "@container (width > 640px)");
265 assert_eq!(query.to_class_name(), "@container/width:sm");
266 }
267
268 #[test]
269 fn test_height_container_query() {
270 let query = ContainerQuery::height(ContainerSize::Xl);
271 assert_eq!(query.to_css_query(), "@container (height > 1280px)");
272 assert_eq!(query.to_class_name(), "@container/height:xl");
273 }
274
275 #[test]
276 fn test_aspect_ratio_container_query() {
277 let query = ContainerQuery::aspect_ratio(ContainerAspectRatio::Widescreen);
278 assert_eq!(query.to_css_query(), "@container (aspect-ratio > 16/9)");
279 assert_eq!(query.to_class_name(), "@container/aspect-ratio:widescreen");
280 }
281
282 #[test]
283 fn test_orientation_container_query() {
284 let query = ContainerQuery::orientation(ContainerOrientation::Landscape);
285 assert_eq!(query.to_css_query(), "@container (orientation: landscape)");
286 assert_eq!(query.to_class_name(), "@container/orientation:landscape");
287 }
288
289 #[test]
290 fn test_custom_container_size() {
291 let size = ContainerSize::Custom("500px".to_string());
292 assert_eq!(size.to_css_value(), "500px");
293 assert_eq!(size.to_class_name(), "500px");
294 }
295
296 #[test]
297 fn test_custom_aspect_ratio() {
298 let ratio = ContainerAspectRatio::Custom("3/2".to_string());
299 assert_eq!(ratio.to_css_value(), "3/2");
300 assert_eq!(ratio.to_class_name(), "3/2");
301 }
302
303 #[test]
304 fn test_container_size_values() {
305 assert_eq!(ContainerSize::Xs.to_css_value(), "320px");
306 assert_eq!(ContainerSize::Sm.to_css_value(), "640px");
307 assert_eq!(ContainerSize::Md.to_css_value(), "768px");
308 assert_eq!(ContainerSize::Lg.to_css_value(), "1024px");
309 assert_eq!(ContainerSize::Xl.to_css_value(), "1280px");
310 assert_eq!(ContainerSize::Xl2.to_css_value(), "1536px");
311 }
312
313 #[test]
314 fn test_container_size_class_names() {
315 assert_eq!(ContainerSize::Xs.to_class_name(), "xs");
316 assert_eq!(ContainerSize::Sm.to_class_name(), "sm");
317 assert_eq!(ContainerSize::Md.to_class_name(), "md");
318 assert_eq!(ContainerSize::Lg.to_class_name(), "lg");
319 assert_eq!(ContainerSize::Xl.to_class_name(), "xl");
320 assert_eq!(ContainerSize::Xl2.to_class_name(), "2xl");
321 }
322
323 #[test]
324 fn test_aspect_ratio_values() {
325 assert_eq!(ContainerAspectRatio::Square.to_css_value(), "1/1");
326 assert_eq!(ContainerAspectRatio::Video.to_css_value(), "4/3");
327 assert_eq!(ContainerAspectRatio::Widescreen.to_css_value(), "16/9");
328 assert_eq!(ContainerAspectRatio::Ultrawide.to_css_value(), "21/9");
329 }
330
331 #[test]
332 fn test_aspect_ratio_class_names() {
333 assert_eq!(ContainerAspectRatio::Square.to_class_name(), "square");
334 assert_eq!(ContainerAspectRatio::Video.to_class_name(), "video");
335 assert_eq!(ContainerAspectRatio::Widescreen.to_class_name(), "widescreen");
336 assert_eq!(ContainerAspectRatio::Ultrawide.to_class_name(), "ultrawide");
337 }
338
339 #[test]
340 fn test_orientation_values() {
341 assert_eq!(ContainerOrientation::Landscape.to_css_value(), "landscape");
342 assert_eq!(ContainerOrientation::Portrait.to_css_value(), "portrait");
343 }
344
345 #[test]
346 fn test_orientation_class_names() {
347 assert_eq!(ContainerOrientation::Landscape.to_class_name(), "landscape");
348 assert_eq!(ContainerOrientation::Portrait.to_class_name(), "portrait");
349 }
350
351 #[test]
352 fn test_container_query_display() {
353 let query = ContainerQuery::inline_size(ContainerSize::Md);
354 assert_eq!(format!("{}", query), "@container (inline-size > 768px)");
355 }
356
357 #[test]
358 fn test_container_size_display() {
359 let size = ContainerSize::Lg;
360 assert_eq!(format!("{}", size), "1024px");
361 }
362
363 #[test]
364 fn test_aspect_ratio_display() {
365 let ratio = ContainerAspectRatio::Widescreen;
366 assert_eq!(format!("{}", ratio), "16/9");
367 }
368
369 #[test]
370 fn test_orientation_display() {
371 let orientation = ContainerOrientation::Landscape;
372 assert_eq!(format!("{}", orientation), "landscape");
373 }
374
375 #[test]
376 fn test_container_query_serialization() {
377 let query = ContainerQuery::inline_size(ContainerSize::Md);
378 let serialized = serde_json::to_string(&query).unwrap();
379 let deserialized: ContainerQuery = serde_json::from_str(&serialized).unwrap();
380 assert_eq!(query, deserialized);
381 }
382
383 #[test]
384 fn test_container_size_serialization() {
385 let size = ContainerSize::Lg;
386 let serialized = serde_json::to_string(&size).unwrap();
387 let deserialized: ContainerSize = serde_json::from_str(&serialized).unwrap();
388 assert_eq!(size, deserialized);
389 }
390
391 #[test]
392 fn test_aspect_ratio_serialization() {
393 let ratio = ContainerAspectRatio::Widescreen;
394 let serialized = serde_json::to_string(&ratio).unwrap();
395 let deserialized: ContainerAspectRatio = serde_json::from_str(&serialized).unwrap();
396 assert_eq!(ratio, deserialized);
397 }
398
399 #[test]
400 fn test_orientation_serialization() {
401 let orientation = ContainerOrientation::Landscape;
402 let serialized = serde_json::to_string(&orientation).unwrap();
403 let deserialized: ContainerOrientation = serde_json::from_str(&serialized).unwrap();
404 assert_eq!(orientation, deserialized);
405 }
406}