lightningcss/rules/
view_transition.rs1use super::Location;
4use crate::error::{ParserError, PrinterError};
5use crate::printer::Printer;
6use crate::properties::custom::CustomProperty;
7use crate::stylesheet::ParserOptions;
8use crate::traits::{Parse, ToCss};
9use crate::values::ident::NoneOrCustomIdentList;
10#[cfg(feature = "visitor")]
11use crate::visitor::Visit;
12use cssparser::*;
13
14#[derive(Debug, PartialEq, Clone)]
16#[cfg_attr(feature = "visitor", derive(Visit))]
17#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
20pub struct ViewTransitionRule<'i> {
21 #[cfg_attr(feature = "serde", serde(borrow))]
23 pub properties: Vec<ViewTransitionProperty<'i>>,
24 #[cfg_attr(feature = "visitor", skip_visit)]
26 pub loc: Location,
27}
28
29#[derive(Debug, Clone, PartialEq)]
33#[cfg_attr(feature = "visitor", derive(Visit))]
34#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
35#[cfg_attr(
36 feature = "serde",
37 derive(serde::Serialize, serde::Deserialize),
38 serde(tag = "property", content = "value", rename_all = "kebab-case")
39)]
40#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
41pub enum ViewTransitionProperty<'i> {
42 Navigation(Navigation),
44 #[cfg_attr(feature = "serde", serde(borrow))]
46 Types(NoneOrCustomIdentList<'i>),
47 Custom(CustomProperty<'i>),
49}
50
51#[derive(Debug, Clone, PartialEq, Default, Parse, ToCss)]
54#[cfg_attr(feature = "visitor", derive(Visit))]
55#[cfg_attr(feature = "into_owned", derive(static_self::IntoOwned))]
56#[cfg_attr(
57 feature = "serde",
58 derive(serde::Serialize, serde::Deserialize),
59 serde(rename_all = "kebab-case")
60)]
61#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
62pub enum Navigation {
63 #[default]
65 None,
66 Auto,
68}
69
70pub(crate) struct ViewTransitionDeclarationParser;
71
72impl<'i> cssparser::DeclarationParser<'i> for ViewTransitionDeclarationParser {
73 type Declaration = ViewTransitionProperty<'i>;
74 type Error = ParserError<'i>;
75
76 fn parse_value<'t>(
77 &mut self,
78 name: CowRcStr<'i>,
79 input: &mut Parser<'i, 't>,
80 _declaration_start: &ParserState,
81 ) -> Result<Self::Declaration, ParseError<'i, Self::Error>> {
82 let state = input.state();
83 match_ignore_ascii_case! { &name,
84 "navigation" => {
85 if let Ok(navigation) = Navigation::parse(input) {
87 return Ok(ViewTransitionProperty::Navigation(navigation));
88 }
89 },
90 "types" => {
91 if let Ok(types) = NoneOrCustomIdentList::parse(input) {
93 return Ok(ViewTransitionProperty::Types(types));
94 }
95 },
96 _ => return Err(input.new_custom_error(ParserError::InvalidDeclaration))
97 }
98
99 input.reset(&state);
100 return Ok(ViewTransitionProperty::Custom(CustomProperty::parse(
101 name.into(),
102 input,
103 &ParserOptions::default(),
104 )?));
105 }
106}
107
108impl<'i> AtRuleParser<'i> for ViewTransitionDeclarationParser {
110 type Prelude = ();
111 type AtRule = ViewTransitionProperty<'i>;
112 type Error = ParserError<'i>;
113}
114
115impl<'i> QualifiedRuleParser<'i> for ViewTransitionDeclarationParser {
116 type Prelude = ();
117 type QualifiedRule = ViewTransitionProperty<'i>;
118 type Error = ParserError<'i>;
119}
120
121impl<'i> RuleBodyItemParser<'i, ViewTransitionProperty<'i>, ParserError<'i>> for ViewTransitionDeclarationParser {
122 fn parse_qualified(&self) -> bool {
123 false
124 }
125
126 fn parse_declarations(&self) -> bool {
127 true
128 }
129}
130
131impl<'i> ViewTransitionRule<'i> {
132 pub(crate) fn parse<'t>(
133 input: &mut Parser<'i, 't>,
134 loc: Location,
135 ) -> Result<Self, ParseError<'i, ParserError<'i>>> {
136 let mut decl_parser = ViewTransitionDeclarationParser;
137 let mut parser = RuleBodyParser::new(input, &mut decl_parser);
138 let mut properties = vec![];
139 while let Some(decl) = parser.next() {
140 if let Ok(decl) = decl {
141 properties.push(decl);
142 }
143 }
144
145 Ok(ViewTransitionRule { properties, loc })
146 }
147}
148
149impl<'i> ToCss for ViewTransitionRule<'i> {
150 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
151 where
152 W: std::fmt::Write,
153 {
154 #[cfg(feature = "sourcemap")]
155 dest.add_mapping(self.loc);
156 dest.write_str("@view-transition")?;
157 dest.whitespace()?;
158 dest.write_char('{')?;
159 dest.indent();
160 let len = self.properties.len();
161 for (i, prop) in self.properties.iter().enumerate() {
162 dest.newline()?;
163 prop.to_css(dest)?;
164 if i != len - 1 || !dest.minify {
165 dest.write_char(';')?;
166 }
167 }
168 dest.dedent();
169 dest.newline()?;
170 dest.write_char('}')
171 }
172}
173
174impl<'i> ToCss for ViewTransitionProperty<'i> {
175 fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
176 where
177 W: std::fmt::Write,
178 {
179 macro_rules! property {
180 ($prop: literal, $value: expr) => {{
181 dest.write_str($prop)?;
182 dest.delim(':', false)?;
183 $value.to_css(dest)
184 }};
185 }
186
187 match self {
188 ViewTransitionProperty::Navigation(f) => property!("navigation", f),
189 ViewTransitionProperty::Types(t) => property!("types", t),
190 ViewTransitionProperty::Custom(custom) => {
191 dest.write_str(custom.name.as_ref())?;
192 dest.delim(':', false)?;
193 custom.value.to_css(dest, true)
194 }
195 }
196 }
197}