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 Highlight(HighlightPseudoElement),
14 Part(PartPseudoElement<'a>),
16 Picker(PickerPseudoElement),
18 Slotted(SlottedPseudoElement<'a>),
20 ViewTransitionGroup(ViewTransitionGroupPseudoFunction<'a>),
23 ViewTransitionImagePair(ViewTransitionImagePairPseudoFunction<'a>),
25 ViewTransitionNew(ViewTransitionNewPseudoFunction<'a>),
27 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}