tailwind_rs_core/utilities/
transitions.rs1use crate::classes::ClassBuilder;
7use serde::{Deserialize, Serialize};
8use std::fmt;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12pub enum TransitionDuration {
13 Duration75,
15 Duration100,
17 Duration150,
19 Duration200,
21 Duration300,
23 Duration500,
25 Duration700,
27 Duration1000,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
33pub enum TransitionTimingFunction {
34 Linear,
36 In,
38 Out,
40 InOut,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
46pub enum TransitionDelay {
47 Delay75,
49 Delay100,
51 Delay150,
53 Delay200,
55 Delay300,
57 Delay500,
59 Delay700,
61 Delay1000,
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
67pub enum TransitionProperty {
68 All,
70 None,
72 Default,
74 Colors,
76 Opacity,
78 Shadow,
80 Transform,
82}
83
84impl TransitionDuration {
85 pub fn to_class_name(&self) -> String {
86 match self {
87 TransitionDuration::Duration75 => "75".to_string(),
88 TransitionDuration::Duration100 => "100".to_string(),
89 TransitionDuration::Duration150 => "150".to_string(),
90 TransitionDuration::Duration200 => "200".to_string(),
91 TransitionDuration::Duration300 => "300".to_string(),
92 TransitionDuration::Duration500 => "500".to_string(),
93 TransitionDuration::Duration700 => "700".to_string(),
94 TransitionDuration::Duration1000 => "1000".to_string(),
95 }
96 }
97
98 pub fn to_css_value(&self) -> String {
99 match self {
100 TransitionDuration::Duration75 => "75ms".to_string(),
101 TransitionDuration::Duration100 => "100ms".to_string(),
102 TransitionDuration::Duration150 => "150ms".to_string(),
103 TransitionDuration::Duration200 => "200ms".to_string(),
104 TransitionDuration::Duration300 => "300ms".to_string(),
105 TransitionDuration::Duration500 => "500ms".to_string(),
106 TransitionDuration::Duration700 => "700ms".to_string(),
107 TransitionDuration::Duration1000 => "1000ms".to_string(),
108 }
109 }
110}
111
112impl TransitionTimingFunction {
113 pub fn to_class_name(&self) -> String {
114 match self {
115 TransitionTimingFunction::Linear => "linear".to_string(),
116 TransitionTimingFunction::In => "in".to_string(),
117 TransitionTimingFunction::Out => "out".to_string(),
118 TransitionTimingFunction::InOut => "in-out".to_string(),
119 }
120 }
121
122 pub fn to_css_value(&self) -> String {
123 match self {
124 TransitionTimingFunction::Linear => "linear".to_string(),
125 TransitionTimingFunction::In => "cubic-bezier(0.4, 0, 1, 1)".to_string(),
126 TransitionTimingFunction::Out => "cubic-bezier(0, 0, 0.2, 1)".to_string(),
127 TransitionTimingFunction::InOut => "cubic-bezier(0.4, 0, 0.2, 1)".to_string(),
128 }
129 }
130}
131
132impl TransitionDelay {
133 pub fn to_class_name(&self) -> String {
134 match self {
135 TransitionDelay::Delay75 => "75".to_string(),
136 TransitionDelay::Delay100 => "100".to_string(),
137 TransitionDelay::Delay150 => "150".to_string(),
138 TransitionDelay::Delay200 => "200".to_string(),
139 TransitionDelay::Delay300 => "300".to_string(),
140 TransitionDelay::Delay500 => "500".to_string(),
141 TransitionDelay::Delay700 => "700".to_string(),
142 TransitionDelay::Delay1000 => "1000".to_string(),
143 }
144 }
145
146 pub fn to_css_value(&self) -> String {
147 match self {
148 TransitionDelay::Delay75 => "75ms".to_string(),
149 TransitionDelay::Delay100 => "100ms".to_string(),
150 TransitionDelay::Delay150 => "150ms".to_string(),
151 TransitionDelay::Delay200 => "200ms".to_string(),
152 TransitionDelay::Delay300 => "300ms".to_string(),
153 TransitionDelay::Delay500 => "500ms".to_string(),
154 TransitionDelay::Delay700 => "700ms".to_string(),
155 TransitionDelay::Delay1000 => "1000ms".to_string(),
156 }
157 }
158}
159
160impl TransitionProperty {
161 pub fn to_class_name(&self) -> String {
162 match self {
163 TransitionProperty::All => "all".to_string(),
164 TransitionProperty::None => "none".to_string(),
165 TransitionProperty::Default => "default".to_string(),
166 TransitionProperty::Colors => "colors".to_string(),
167 TransitionProperty::Opacity => "opacity".to_string(),
168 TransitionProperty::Shadow => "shadow".to_string(),
169 TransitionProperty::Transform => "transform".to_string(),
170 }
171 }
172
173 pub fn to_css_value(&self) -> String {
174 match self {
175 TransitionProperty::All => "all".to_string(),
176 TransitionProperty::None => "none".to_string(),
177 TransitionProperty::Default => "background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter".to_string(),
178 TransitionProperty::Colors => "background-color, border-color, color, fill, stroke".to_string(),
179 TransitionProperty::Opacity => "opacity".to_string(),
180 TransitionProperty::Shadow => "box-shadow".to_string(),
181 TransitionProperty::Transform => "transform".to_string(),
182 }
183 }
184}
185
186impl fmt::Display for TransitionDuration {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 write!(f, "{}", self.to_class_name())
189 }
190}
191
192impl fmt::Display for TransitionTimingFunction {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 write!(f, "{}", self.to_class_name())
195 }
196}
197
198impl fmt::Display for TransitionDelay {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 write!(f, "{}", self.to_class_name())
201 }
202}
203
204impl fmt::Display for TransitionProperty {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 write!(f, "{}", self.to_class_name())
207 }
208}
209
210pub trait TransitionDurationUtilities {
212 fn transition_duration(self, duration: TransitionDuration) -> Self;
213}
214
215impl TransitionDurationUtilities for ClassBuilder {
216 fn transition_duration(self, duration: TransitionDuration) -> Self {
217 self.class(format!("duration-{}", duration.to_class_name()))
218 }
219}
220
221pub trait TransitionTimingFunctionUtilities {
223 fn transition_timing_function(self, timing: TransitionTimingFunction) -> Self;
224}
225
226impl TransitionTimingFunctionUtilities for ClassBuilder {
227 fn transition_timing_function(self, timing: TransitionTimingFunction) -> Self {
228 self.class(format!("ease-{}", timing.to_class_name()))
229 }
230}
231
232pub trait TransitionDelayUtilities {
234 fn transition_delay(self, delay: TransitionDelay) -> Self;
235}
236
237impl TransitionDelayUtilities for ClassBuilder {
238 fn transition_delay(self, delay: TransitionDelay) -> Self {
239 self.class(format!("delay-{}", delay.to_class_name()))
240 }
241}
242
243pub trait TransitionPropertyUtilities {
245 fn transition_property(self, property: TransitionProperty) -> Self;
246}
247
248impl TransitionPropertyUtilities for ClassBuilder {
249 fn transition_property(self, property: TransitionProperty) -> Self {
250 self.class(format!("transition-{}", property.to_class_name()))
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn test_transition_duration_utilities() {
260 let classes = ClassBuilder::new()
261 .transition_duration(TransitionDuration::Duration75)
262 .transition_duration(TransitionDuration::Duration100)
263 .transition_duration(TransitionDuration::Duration150)
264 .transition_duration(TransitionDuration::Duration200)
265 .transition_duration(TransitionDuration::Duration300)
266 .transition_duration(TransitionDuration::Duration500)
267 .transition_duration(TransitionDuration::Duration700)
268 .transition_duration(TransitionDuration::Duration1000)
269 .build();
270
271 let css_classes = classes.to_css_classes();
272 assert!(css_classes.contains("duration-75"));
273 assert!(css_classes.contains("duration-100"));
274 assert!(css_classes.contains("duration-150"));
275 assert!(css_classes.contains("duration-200"));
276 assert!(css_classes.contains("duration-300"));
277 assert!(css_classes.contains("duration-500"));
278 assert!(css_classes.contains("duration-700"));
279 assert!(css_classes.contains("duration-1000"));
280 }
281
282 #[test]
283 fn test_transition_timing_function_utilities() {
284 let classes = ClassBuilder::new()
285 .transition_timing_function(TransitionTimingFunction::Linear)
286 .transition_timing_function(TransitionTimingFunction::In)
287 .transition_timing_function(TransitionTimingFunction::Out)
288 .transition_timing_function(TransitionTimingFunction::InOut)
289 .build();
290
291 let css_classes = classes.to_css_classes();
292 assert!(css_classes.contains("ease-linear"));
293 assert!(css_classes.contains("ease-in"));
294 assert!(css_classes.contains("ease-out"));
295 assert!(css_classes.contains("ease-in-out"));
296 }
297
298 #[test]
299 fn test_transition_delay_utilities() {
300 let classes = ClassBuilder::new()
301 .transition_delay(TransitionDelay::Delay75)
302 .transition_delay(TransitionDelay::Delay100)
303 .transition_delay(TransitionDelay::Delay150)
304 .transition_delay(TransitionDelay::Delay200)
305 .transition_delay(TransitionDelay::Delay300)
306 .transition_delay(TransitionDelay::Delay500)
307 .transition_delay(TransitionDelay::Delay700)
308 .transition_delay(TransitionDelay::Delay1000)
309 .build();
310
311 let css_classes = classes.to_css_classes();
312 assert!(css_classes.contains("delay-75"));
313 assert!(css_classes.contains("delay-100"));
314 assert!(css_classes.contains("delay-150"));
315 assert!(css_classes.contains("delay-200"));
316 assert!(css_classes.contains("delay-300"));
317 assert!(css_classes.contains("delay-500"));
318 assert!(css_classes.contains("delay-700"));
319 assert!(css_classes.contains("delay-1000"));
320 }
321
322 #[test]
323 fn test_transition_property_utilities() {
324 let classes = ClassBuilder::new()
325 .transition_property(TransitionProperty::All)
326 .transition_property(TransitionProperty::None)
327 .transition_property(TransitionProperty::Default)
328 .transition_property(TransitionProperty::Colors)
329 .transition_property(TransitionProperty::Opacity)
330 .transition_property(TransitionProperty::Shadow)
331 .transition_property(TransitionProperty::Transform)
332 .build();
333
334 let css_classes = classes.to_css_classes();
335 assert!(css_classes.contains("transition-all"));
336 assert!(css_classes.contains("transition-none"));
337 assert!(css_classes.contains("transition-default"));
338 assert!(css_classes.contains("transition-colors"));
339 assert!(css_classes.contains("transition-opacity"));
340 assert!(css_classes.contains("transition-shadow"));
341 assert!(css_classes.contains("transition-transform"));
342 }
343
344 #[test]
345 fn test_complex_transitions_combination() {
346 let classes = ClassBuilder::new()
347 .transition_duration(TransitionDuration::Duration300)
348 .transition_timing_function(TransitionTimingFunction::InOut)
349 .transition_delay(TransitionDelay::Delay100)
350 .transition_property(TransitionProperty::Colors)
351 .build();
352
353 let css_classes = classes.to_css_classes();
354 assert!(css_classes.contains("duration-300"));
355 assert!(css_classes.contains("ease-in-out"));
356 assert!(css_classes.contains("delay-100"));
357 assert!(css_classes.contains("transition-colors"));
358 }
359
360 #[test]
362 fn test_week12_transition_utilities() {
363 let classes = ClassBuilder::new()
365 .transition_property(TransitionProperty::None)
367 .transition_property(TransitionProperty::All)
368 .transition_property(TransitionProperty::Default)
369 .transition_property(TransitionProperty::Colors)
370 .transition_property(TransitionProperty::Opacity)
371 .transition_property(TransitionProperty::Shadow)
372 .transition_property(TransitionProperty::Transform)
373 .transition_duration(TransitionDuration::Duration75)
375 .transition_duration(TransitionDuration::Duration100)
376 .transition_duration(TransitionDuration::Duration150)
377 .transition_duration(TransitionDuration::Duration200)
378 .transition_duration(TransitionDuration::Duration300)
379 .transition_duration(TransitionDuration::Duration500)
380 .transition_duration(TransitionDuration::Duration700)
381 .transition_duration(TransitionDuration::Duration1000)
382 .transition_timing_function(TransitionTimingFunction::Linear)
384 .transition_timing_function(TransitionTimingFunction::In)
385 .transition_timing_function(TransitionTimingFunction::Out)
386 .transition_timing_function(TransitionTimingFunction::InOut)
387 .transition_delay(TransitionDelay::Delay75)
389 .transition_delay(TransitionDelay::Delay100)
390 .transition_delay(TransitionDelay::Delay150)
391 .transition_delay(TransitionDelay::Delay200)
392 .transition_delay(TransitionDelay::Delay300)
393 .transition_delay(TransitionDelay::Delay500)
394 .transition_delay(TransitionDelay::Delay700)
395 .transition_delay(TransitionDelay::Delay1000)
396 .build();
397
398 let css_classes = classes.to_css_classes();
399
400 assert!(css_classes.contains("transition-none"));
402 assert!(css_classes.contains("transition-all"));
403 assert!(css_classes.contains("transition"));
404 assert!(css_classes.contains("transition-colors"));
405 assert!(css_classes.contains("transition-opacity"));
406 assert!(css_classes.contains("transition-shadow"));
407 assert!(css_classes.contains("transition-transform"));
408
409 assert!(css_classes.contains("duration-75"));
411 assert!(css_classes.contains("duration-100"));
412 assert!(css_classes.contains("duration-150"));
413 assert!(css_classes.contains("duration-200"));
414 assert!(css_classes.contains("duration-300"));
415 assert!(css_classes.contains("duration-500"));
416 assert!(css_classes.contains("duration-700"));
417 assert!(css_classes.contains("duration-1000"));
418
419 assert!(css_classes.contains("ease-linear"));
421 assert!(css_classes.contains("ease-in"));
422 assert!(css_classes.contains("ease-out"));
423 assert!(css_classes.contains("ease-in-out"));
424
425 assert!(css_classes.contains("delay-75"));
427 assert!(css_classes.contains("delay-100"));
428 assert!(css_classes.contains("delay-150"));
429 assert!(css_classes.contains("delay-200"));
430 assert!(css_classes.contains("delay-300"));
431 assert!(css_classes.contains("delay-500"));
432 assert!(css_classes.contains("delay-700"));
433 assert!(css_classes.contains("delay-1000"));
434 }
435}