tailwind_rs_core/utilities/
device_variants.rs1use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum PointerVariant {
13 Coarse,
15 Fine,
17 AnyCoarse,
19 AnyFine,
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
25pub enum MotionVariant {
26 Reduced,
28 NoPreference,
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
34pub enum ColorSchemeVariant {
35 Light,
37 Dark,
39}
40
41impl PointerVariant {
42 pub fn to_class_name(&self) -> String {
43 match self {
44 PointerVariant::Coarse => "pointer-coarse".to_string(),
45 PointerVariant::Fine => "pointer-fine".to_string(),
46 PointerVariant::AnyCoarse => "any-pointer-coarse".to_string(),
47 PointerVariant::AnyFine => "any-pointer-fine".to_string(),
48 }
49 }
50
51 pub fn to_media_query(&self) -> String {
52 match self {
53 PointerVariant::Coarse => "@media (pointer: coarse)".to_string(),
54 PointerVariant::Fine => "@media (pointer: fine)".to_string(),
55 PointerVariant::AnyCoarse => "@media (any-pointer: coarse)".to_string(),
56 PointerVariant::AnyFine => "@media (any-pointer: fine)".to_string(),
57 }
58 }
59}
60
61impl MotionVariant {
62 pub fn to_class_name(&self) -> String {
63 match self {
64 MotionVariant::Reduced => "motion-reduce".to_string(),
65 MotionVariant::NoPreference => "motion-safe".to_string(),
66 }
67 }
68
69 pub fn to_media_query(&self) -> String {
70 match self {
71 MotionVariant::Reduced => "@media (prefers-reduced-motion: reduce)".to_string(),
72 MotionVariant::NoPreference => {
73 "@media (prefers-reduced-motion: no-preference)".to_string()
74 }
75 }
76 }
77}
78
79impl ColorSchemeVariant {
80 pub fn to_class_name(&self) -> String {
81 match self {
82 ColorSchemeVariant::Light => "light".to_string(),
83 ColorSchemeVariant::Dark => "dark".to_string(),
84 }
85 }
86
87 pub fn to_media_query(&self) -> String {
88 match self {
89 ColorSchemeVariant::Light => "@media (prefers-color-scheme: light)".to_string(),
90 ColorSchemeVariant::Dark => "@media (prefers-color-scheme: dark)".to_string(),
91 }
92 }
93}
94
95impl fmt::Display for PointerVariant {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 write!(f, "{}", self.to_class_name())
98 }
99}
100
101impl fmt::Display for MotionVariant {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "{}", self.to_class_name())
104 }
105}
106
107impl fmt::Display for ColorSchemeVariant {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "{}", self.to_class_name())
110 }
111}
112
113pub trait PointerVariantUtilities {
115 fn pointer_coarse(self) -> Self;
117 fn pointer_fine(self) -> Self;
119 fn any_pointer_coarse(self) -> Self;
121 fn any_pointer_fine(self) -> Self;
123}
124
125impl PointerVariantUtilities for ClassBuilder {
126 fn pointer_coarse(self) -> Self {
127 self.class("pointer-coarse")
128 }
129
130 fn pointer_fine(self) -> Self {
131 self.class("pointer-fine")
132 }
133
134 fn any_pointer_coarse(self) -> Self {
135 self.class("any-pointer-coarse")
136 }
137
138 fn any_pointer_fine(self) -> Self {
139 self.class("any-pointer-fine")
140 }
141}
142
143pub trait MotionVariantUtilities {
145 fn motion_reduce(self) -> Self;
147 fn motion_safe(self) -> Self;
149}
150
151impl MotionVariantUtilities for ClassBuilder {
152 fn motion_reduce(self) -> Self {
153 self.class("motion-reduce")
154 }
155
156 fn motion_safe(self) -> Self {
157 self.class("motion-safe")
158 }
159}
160
161pub trait ColorSchemeVariantUtilities {
163 fn light(self) -> Self;
165 fn dark(self) -> Self;
167}
168
169impl ColorSchemeVariantUtilities for ClassBuilder {
170 fn light(self) -> Self {
171 self.class("light")
172 }
173
174 fn dark(self) -> Self {
175 self.class("dark")
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn test_pointer_variant_class_names() {
185 assert_eq!(PointerVariant::Coarse.to_class_name(), "pointer-coarse");
186 assert_eq!(PointerVariant::Fine.to_class_name(), "pointer-fine");
187 assert_eq!(
188 PointerVariant::AnyCoarse.to_class_name(),
189 "any-pointer-coarse"
190 );
191 assert_eq!(PointerVariant::AnyFine.to_class_name(), "any-pointer-fine");
192 }
193
194 #[test]
195 fn test_pointer_variant_media_queries() {
196 assert_eq!(
197 PointerVariant::Coarse.to_media_query(),
198 "@media (pointer: coarse)"
199 );
200 assert_eq!(
201 PointerVariant::Fine.to_media_query(),
202 "@media (pointer: fine)"
203 );
204 assert_eq!(
205 PointerVariant::AnyCoarse.to_media_query(),
206 "@media (any-pointer: coarse)"
207 );
208 assert_eq!(
209 PointerVariant::AnyFine.to_media_query(),
210 "@media (any-pointer: fine)"
211 );
212 }
213
214 #[test]
215 fn test_motion_variant_class_names() {
216 assert_eq!(MotionVariant::Reduced.to_class_name(), "motion-reduce");
217 assert_eq!(MotionVariant::NoPreference.to_class_name(), "motion-safe");
218 }
219
220 #[test]
221 fn test_motion_variant_media_queries() {
222 assert_eq!(
223 MotionVariant::Reduced.to_media_query(),
224 "@media (prefers-reduced-motion: reduce)"
225 );
226 assert_eq!(
227 MotionVariant::NoPreference.to_media_query(),
228 "@media (prefers-reduced-motion: no-preference)"
229 );
230 }
231
232 #[test]
233 fn test_color_scheme_variant_class_names() {
234 assert_eq!(ColorSchemeVariant::Light.to_class_name(), "light");
235 assert_eq!(ColorSchemeVariant::Dark.to_class_name(), "dark");
236 }
237
238 #[test]
239 fn test_color_scheme_variant_media_queries() {
240 assert_eq!(
241 ColorSchemeVariant::Light.to_media_query(),
242 "@media (prefers-color-scheme: light)"
243 );
244 assert_eq!(
245 ColorSchemeVariant::Dark.to_media_query(),
246 "@media (prefers-color-scheme: dark)"
247 );
248 }
249
250 #[test]
251 fn test_pointer_variant_utilities() {
252 let classes = ClassBuilder::new()
253 .pointer_coarse()
254 .pointer_fine()
255 .any_pointer_coarse()
256 .any_pointer_fine()
257 .build();
258
259 assert!(classes.classes.contains("pointer-coarse"));
260 assert!(classes.classes.contains("pointer-fine"));
261 assert!(classes.classes.contains("any-pointer-coarse"));
262 assert!(classes.classes.contains("any-pointer-fine"));
263 }
264
265 #[test]
266 fn test_motion_variant_utilities() {
267 let classes = ClassBuilder::new().motion_reduce().motion_safe().build();
268
269 assert!(classes.classes.contains("motion-reduce"));
270 assert!(classes.classes.contains("motion-safe"));
271 }
272
273 #[test]
274 fn test_color_scheme_variant_utilities() {
275 let classes = ClassBuilder::new().light().dark().build();
276
277 println!("Generated classes: {:?}", classes.classes);
278 assert!(classes.classes.contains("light"));
279 assert!(classes.classes.contains("dark"));
280 }
281
282 #[test]
283 fn test_device_variants_comprehensive() {
284 let classes = ClassBuilder::new()
285 .pointer_coarse()
286 .pointer_fine()
287 .motion_reduce()
288 .motion_safe()
289 .light()
290 .dark()
291 .build();
292
293 assert!(classes.classes.contains("pointer-coarse"));
294 assert!(classes.classes.contains("pointer-fine"));
295 assert!(classes.classes.contains("motion-reduce"));
296 assert!(classes.classes.contains("motion-safe"));
297 println!("Generated classes: {:?}", classes.classes);
298 assert!(classes.classes.contains("light"));
299 assert!(classes.classes.contains("dark"));
300 }
301}