diff --git a/src/lib.rs b/src/lib.rs index 8b9535f0..02bf9fcf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6925,6 +6925,21 @@ mod tests { "@keyframes test{to{background:#00f}}", ); + // named animation range percentages + minify_test( + r#" + @keyframes test { + entry 0% { + background: blue + } + exit 100% { + background: green + } + } + "#, + "@keyframes test{entry 0%{background:#00f}exit 100%{background:green}}", + ); + // CSS-wide keywords and `none` cannot remove quotes. minify_test( r#" @@ -6948,6 +6963,18 @@ mod tests { "@keyframes \"none\"{0%{background:green}}", ); + // named animation ranges cannot be used with to or from + minify_test( + r#" + @keyframes test { + entry to { + background: blue + } + } + "#, + "@keyframes test{}", + ); + // CSS-wide keywords without quotes throws an error. error_test( r#" diff --git a/src/rules/keyframes.rs b/src/rules/keyframes.rs index adf2fb5b..9d1e758d 100644 --- a/src/rules/keyframes.rs +++ b/src/rules/keyframes.rs @@ -8,6 +8,7 @@ use crate::declaration::DeclarationBlock; use crate::error::{ParserError, PrinterError}; use crate::parser::ParserOptions; use crate::printer::Printer; +use crate::properties::animation::TimelineRangeName; use crate::properties::custom::{CustomProperty, UnparsedProperty}; use crate::properties::Property; use crate::targets::Targets; @@ -265,6 +266,34 @@ impl<'i> ToCss for KeyframesRule<'i> { } } +/// A percentage of a given timeline range +#[derive(Debug, PartialEq, Clone)] +#[cfg_attr(feature = "visitor", derive(Visit))] +#[cfg_attr( + feature = "serde", + derive(serde::Serialize, serde::Deserialize), + serde(tag = "type", rename_all = "camelCase") +)] +#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))] +#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))] +pub struct TimelineRangePercentage { + /// A named timeline range + timeline_range_name: TimelineRangeName, + /// The percentage progress between the start and end of the rage + percentage: Percentage +} + +impl<'i> Parse<'i> for TimelineRangePercentage { + fn parse<'t>(input: &mut Parser<'i, 't>) -> Result>> { + let timeline_range_name = TimelineRangeName::parse(input)?; + let percentage = Percentage::parse(input)?; + Ok(TimelineRangePercentage { + timeline_range_name, + percentage + }) + } +} + /// A [keyframe selector](https://drafts.csswg.org/css-animations/#typedef-keyframe-selector) /// within an `@keyframes` rule. #[derive(Debug, PartialEq, Clone, Parse)] @@ -283,6 +312,8 @@ pub enum KeyframeSelector { From, /// The `to` keyword. Equivalent to 100%. To, + /// A [named timeline range selector](https://drafts.csswg.org/scroll-animations-1/#named-range-keyframes) + TimelineRangePercentage(TimelineRangePercentage) } impl ToCss for KeyframeSelector { @@ -306,6 +337,14 @@ impl ToCss for KeyframeSelector { } } KeyframeSelector::To => dest.write_str("to"), + KeyframeSelector::TimelineRangePercentage(TimelineRangePercentage { + timeline_range_name, + percentage + }) => { + timeline_range_name.to_css(dest)?; + dest.write_char(' ')?; + percentage.to_css(dest) + } } } }