css_ast/selector/
functional_pseudo_element.rs

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