css_ast/selector/
functional_pseudo_element.rs

1use bumpalo::collections::Vec;
2use css_parse::{Parse, Parser, Result as ParserResult, T, function_set};
3use csskit_derives::{Parse, ToCursors, ToSpan, Visitable};
4
5use super::CompoundSelector;
6
7#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize), serde(tag = "type", rename_all = "kebab-case"))]
9#[cfg_attr(feature = "css_feature_data", derive(::csskit_derives::ToCSSFeature), css_feature("css.selectors"))]
10#[visit]
11pub enum FunctionalPseudoElement<'a> {
12	// https://drafts.csswg.org/css-highlight-api/#custom-highlight-pseudo
13	Highlight(HighlightPseudoElement),
14	// https://drafts.csswg.org/css-shadow-parts/#part
15	Part(PartPseudoElement<'a>),
16	// https://drafts.csswg.org/css-forms-1/#picker-pseudo
17	Picker(PickerPseudoElement),
18	// https://drafts.csswg.org/css-scoping/#slotted-pseudo
19	Slotted(SlottedPseudoElement<'a>),
20	// https://drafts.csswg.org/css-view-transitions-2/#view-transition-pseudo
21	// https://drafts.csswg.org/css-view-transitions-2/#::view-transition-group
22	ViewTransitionGroup(ViewTransitionGroupPseudoFunction<'a>),
23	// https://drafts.csswg.org/css-view-transitions-2/#::view-transition-image-pair
24	ViewTransitionImagePair(ViewTransitionImagePairPseudoFunction<'a>),
25	// https://drafts.csswg.org/css-view-transitions-2/#::view-transition-new
26	ViewTransitionNew(ViewTransitionNewPseudoFunction<'a>),
27	// https://drafts.csswg.org/css-view-transitions-2/#::view-transition-old
28	ViewTransitionOld(ViewTransitionOldPseudoFunction<'a>),
29}
30
31function_set!(
32	enum FunctionKeywords {
33		Highlight: "highlight",
34		Part: "part",
35		Slotted: "slotted",
36		Picker: "picker",
37		ViewTransitionGroup: "view-transition-group",
38		ViewTransitionImagePair: "view-transition-image-pair",
39		ViewTransitionNew: "view-transition-new",
40		ViewTransitionOld: "view-transition-old",
41	}
42);
43
44impl<'a> Parse<'a> for FunctionalPseudoElement<'a> {
45	fn parse(p: &mut Parser<'a>) -> ParserResult<Self> {
46		let colons = p.parse::<T![::]>()?;
47		let kw = p.parse::<FunctionKeywords>()?;
48		match kw {
49			FunctionKeywords::Highlight(function) => {
50				let value = p.parse::<T![Ident]>()?;
51				let close = p.parse_if_peek::<T![')']>()?;
52				Ok(Self::Highlight(HighlightPseudoElement { colons, function, value, close }))
53			}
54			FunctionKeywords::Part(function) => {
55				let mut value = Vec::new_in(p.bump());
56				loop {
57					if p.peek::<T![')']>() {
58						break;
59					}
60					value.push(p.parse::<T![Ident]>()?);
61				}
62				let close = p.parse_if_peek::<T![')']>()?;
63				Ok(Self::Part(PartPseudoElement { colons, function, value, close }))
64			}
65			FunctionKeywords::Picker(function) => {
66				let value = p.parse::<T![Ident]>()?;
67				let close = p.parse_if_peek::<T![')']>()?;
68				Ok(Self::Picker(PickerPseudoElement { colons, function, value, close }))
69			}
70			FunctionKeywords::Slotted(function) => {
71				let value = p.parse::<CompoundSelector>()?;
72				let close = p.parse_if_peek::<T![')']>()?;
73				Ok(Self::Slotted(SlottedPseudoElement { colons, function, value, close }))
74			}
75			FunctionKeywords::ViewTransitionGroup(function) => {
76				let value = p.parse::<PtNameAndClassSelector>()?;
77				let close = p.parse_if_peek::<T![')']>()?;
78				Ok(Self::ViewTransitionGroup(ViewTransitionGroupPseudoFunction { colons, function, value, close }))
79			}
80			FunctionKeywords::ViewTransitionImagePair(function) => {
81				let value = p.parse::<PtNameAndClassSelector>()?;
82				let close = p.parse_if_peek::<T![')']>()?;
83				Ok(Self::ViewTransitionImagePair(ViewTransitionImagePairPseudoFunction {
84					colons,
85					function,
86					value,
87					close,
88				}))
89			}
90			FunctionKeywords::ViewTransitionNew(function) => {
91				let value = p.parse::<PtNameAndClassSelector>()?;
92				let close = p.parse_if_peek::<T![')']>()?;
93				Ok(Self::ViewTransitionNew(ViewTransitionNewPseudoFunction { colons, function, value, close }))
94			}
95			FunctionKeywords::ViewTransitionOld(function) => {
96				let value = p.parse::<PtNameAndClassSelector>()?;
97				let close = p.parse_if_peek::<T![')']>()?;
98				Ok(Self::ViewTransitionOld(ViewTransitionOldPseudoFunction { colons, function, value, close }))
99			}
100		}
101	}
102}
103
104#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
106#[visit(self)]
107pub struct HighlightPseudoElement {
108	pub colons: T![::],
109	pub function: T![Function],
110	pub value: T![Ident],
111	pub close: Option<T![')']>,
112}
113
114#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
115#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
116#[visit]
117pub struct SlottedPseudoElement<'a> {
118	#[visit(skip)]
119	pub colons: T![::],
120	#[visit(skip)]
121	pub function: T![Function],
122	pub value: CompoundSelector<'a>,
123	#[visit(skip)]
124	pub close: Option<T![')']>,
125}
126
127#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
129#[visit(self)]
130pub struct PartPseudoElement<'a> {
131	pub colons: T![::],
132	pub function: T![Function],
133	pub value: Vec<'a, T![Ident]>,
134	pub close: Option<T![')']>,
135}
136
137#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
139#[visit(self)]
140pub struct PickerPseudoElement {
141	pub colons: T![::],
142	pub function: T![Function],
143	pub value: T![Ident],
144	pub close: Option<T![')']>,
145}
146
147#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
148#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
149#[visit(self)]
150pub struct ViewTransitionGroupPseudoFunction<'a> {
151	pub colons: T![::],
152	pub function: T![Function],
153	pub value: PtNameAndClassSelector<'a>,
154	pub close: Option<T![')']>,
155}
156
157#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
158#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
159#[visit(self)]
160pub struct ViewTransitionImagePairPseudoFunction<'a> {
161	pub colons: T![::],
162	pub function: T![Function],
163	pub value: PtNameAndClassSelector<'a>,
164	pub close: Option<T![')']>,
165}
166
167#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
168#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
169#[visit(self)]
170pub struct ViewTransitionNewPseudoFunction<'a> {
171	pub colons: T![::],
172	pub function: T![Function],
173	pub value: PtNameAndClassSelector<'a>,
174	pub close: Option<T![')']>,
175}
176
177#[derive(ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
178#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
179#[visit(self)]
180pub struct ViewTransitionOldPseudoFunction<'a> {
181	pub colons: T![::],
182	pub function: T![Function],
183	pub value: PtNameAndClassSelector<'a>,
184	pub close: Option<T![')']>,
185}
186
187#[derive(Parse, ToSpan, ToCursors, Visitable, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
188#[cfg_attr(feature = "serde", derive(serde::Serialize), serde())]
189#[visit(self)]
190pub enum PtNameAndClassSelector<'a> {
191	Wildcard(T![*]),
192	Named(T![Ident], Vec<'a, (T![.], T![Ident])>),
193	Classes(Vec<'a, (T![.], T![Ident])>),
194}