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