Skip to main content

css_ast/types/
single_transition.rs

1use super::prelude::*;
2use crate::{CalcableValue, EasingFunction, NoneOr, SingleTransitionProperty, Time, TransitionBehaviorValue};
3use css_parse::parse_optionals;
4
5/// <https://drafts.csswg.org/css-transitions-2/#single-transition>
6///
7/// ```text,ignore
8/// <single-transition> = [ none | <single-transition-property> ] || <time> || <easing-function> || <time> || <transition-behavior-value>
9/// ```
10#[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		// Substitution/math in the <time> slots.
92		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}