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