whisker_css/shorthand/
transition.rs1use core::fmt;
5
6use crate::css::Css;
7use crate::data_type::Time;
8use crate::data_type_ext::EasingFunction;
9use crate::keyword::TransitionPropertyKind;
10use crate::to_css::ToCss;
11
12#[derive(Clone, Debug, PartialEq)]
14pub struct Transition {
15 pub property: TransitionPropertyKind,
17 pub duration: Option<Time>,
19 pub timing: Option<EasingFunction>,
21 pub delay: Option<Time>,
23}
24
25impl Transition {
26 pub fn new(property: TransitionPropertyKind) -> Self {
28 Self {
29 property,
30 duration: None,
31 timing: None,
32 delay: None,
33 }
34 }
35
36 pub fn duration(mut self, d: Time) -> Self {
38 self.duration = Some(d);
39 self
40 }
41
42 pub fn timing(mut self, t: EasingFunction) -> Self {
44 self.timing = Some(t);
45 self
46 }
47
48 pub fn delay(mut self, d: Time) -> Self {
50 self.delay = Some(d);
51 self
52 }
53}
54
55impl ToCss for Transition {
56 fn to_css(&self, dest: &mut dyn fmt::Write) -> fmt::Result {
57 self.property.to_css(dest)?;
58 if let Some(d) = &self.duration {
59 dest.write_char(' ')?;
60 d.to_css(dest)?;
61 }
62 if let Some(t) = &self.timing {
63 dest.write_char(' ')?;
64 t.to_css(dest)?;
65 }
66 if let Some(d) = &self.delay {
67 dest.write_char(' ')?;
68 d.to_css(dest)?;
69 }
70 Ok(())
71 }
72}
73
74impl Css {
75 pub fn transition(self, t: Transition) -> Self {
78 self.push("transition", t)
79 }
80
81 pub fn transitions(self, ts: impl IntoIterator<Item = Transition>) -> Self {
84 let mut s = String::new();
85 for (i, t) in ts.into_iter().enumerate() {
86 if i > 0 {
87 s.push_str(", ");
88 }
89 let _ = t.to_css(&mut s);
90 }
91 self.push_raw("transition", s)
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use crate::data_type_ext::EasingFunction;
98 use crate::ext::*;
99 use crate::keyword::TransitionPropertyKind;
100 use crate::Css;
101
102 use super::*;
103
104 #[test]
105 fn transition_property_only() {
106 let s = Css::new().transition(Transition::new(TransitionPropertyKind::All));
107 assert_eq!(s.to_string(), "transition: all;");
108 }
109
110 #[test]
111 fn transition_property_duration_timing_delay() {
112 let s = Css::new().transition(
113 Transition::new(TransitionPropertyKind::name("opacity"))
114 .duration(300.ms())
115 .timing(EasingFunction::EaseInOut)
116 .delay(100.ms()),
117 );
118 assert_eq!(
119 s.to_string(),
120 "transition: opacity 300ms ease-in-out 100ms;"
121 );
122 }
123
124 #[test]
125 fn transitions_multiple_layers() {
126 let s = Css::new().transitions([
127 Transition::new(TransitionPropertyKind::name("opacity")).duration(300.ms()),
128 Transition::new(TransitionPropertyKind::name("transform"))
129 .duration(500.ms())
130 .delay(100.ms()),
131 ]);
132 assert_eq!(
133 s.to_string(),
134 "transition: opacity 300ms, transform 500ms 100ms;"
135 );
136 }
137}