1use super::prelude::*;
2use crate::{CalcableValue, EasingFunction, NoneOr, SingleTransitionProperty, Time, TransitionBehaviorValue};
3use css_parse::parse_optionals;
4
5#[node]
11#[derive(ToCursors, ToSpan, SemanticEq, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
13#[cfg_attr(feature = "visitable", derive(csskit_derives::Visitable), visit)]
14#[derive(csskit_derives::NodeWithMetadata)]
15pub struct SingleTransition<'a> {
16 #[cfg_attr(feature = "visitable", visit(skip))]
17 pub property: Option<NoneOr<SingleTransitionProperty>>,
18 pub duration: Option<CalcableValue<'a, Time>>,
19 pub easing: Option<EasingFunction<'a>>,
20 pub delay: Option<CalcableValue<'a, Time>>,
21 #[cfg_attr(feature = "visitable", visit(skip))]
22 pub behavior: Option<TransitionBehaviorValue>,
23}
24
25impl<'a> Peek<'a> for SingleTransition<'a> {
26 const PEEK_KINDSET: KindSet = <NoneOr<SingleTransitionProperty>>::PEEK_KINDSET
27 .combine(EasingFunction::PEEK_KINDSET)
28 .combine(<CalcableValue<'a, Time>>::PEEK_KINDSET);
29
30 #[inline(always)]
31 fn peek<I>(p: &Parser<'a, I>, c: Cursor) -> bool
32 where
33 I: Iterator<Item = Cursor> + Clone,
34 {
35 <NoneOr<SingleTransitionProperty>>::peek(p, c)
36 || EasingFunction::peek(p, c)
37 || <CalcableValue<'a, Time>>::peek(p, c)
38 }
39}
40
41impl<'a> Parse<'a> for SingleTransition<'a> {
42 fn parse<I>(p: &mut Parser<'a, I>) -> ParserResult<Self>
43 where
44 I: Iterator<Item = Cursor> + Clone,
45 {
46 let (easing, property, duration, delay, behavior) = parse_optionals!(p, easing: EasingFunction, property: NoneOr<SingleTransitionProperty>, duration: CalcableValue<Time>, delay: CalcableValue<Time>, behavior: TransitionBehaviorValue);
47 Ok(Self { easing, property, duration, delay, behavior })
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::CssAtomSet;
55 use css_parse::{assert_parse, assert_parse_error, assert_peek_false};
56
57 type NoneOrSingleTransitionProperty = NoneOr<SingleTransitionProperty>;
58
59 #[test]
60 fn test_writes() {
61 assert_parse!(
62 CssAtomSet::ATOMS,
63 NoneOrSingleTransitionProperty,
64 "none",
65 NoneOrSingleTransitionProperty::None(_)
66 );
67 assert_parse!(
68 CssAtomSet::ATOMS,
69 NoneOrSingleTransitionProperty,
70 "all",
71 NoneOrSingleTransitionProperty::Some(_)
72 );
73
74 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none");
75 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity");
76 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s");
77 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s ease-in");
78 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity 1s ease-in 2s");
79 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "2s ease-in");
80 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s opacity");
81 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in 1s opacity");
82 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s 2s ease-in opacity");
83 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in opacity 1s 2s");
84 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "ease-in");
85 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s");
86 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s 2s");
87 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "all 1s ease-in 2s");
88 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none 1s");
89 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "none 1s normal");
90 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "1s opacity allow-discrete");
91 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity calc(1s + 200ms)");
93 assert_parse!(CssAtomSet::ATOMS, SingleTransition, "opacity var(--dur) ease-in var(--delay)");
94 }
95
96 #[test]
97 fn test_errors() {
98 assert_peek_false!(CssAtomSet::ATOMS, SingleTransition, "1deg");
99 assert_parse_error!(CssAtomSet::ATOMS, SingleTransition, "none none");
100 }
101
102 #[test]
103 #[cfg(feature = "visitable")]
104 fn test_visits() {
105 use crate::assert_visits;
106 assert_visits!("1s", SingleTransition, Time);
107 assert_visits!("ease-in", SingleTransition, EasingFunction);
108 assert_visits!("1s 2s", SingleTransition, Time, Time);
109 assert_visits!("1s ease-in 2s", SingleTransition, Time, EasingFunction, Time);
110 }
111}