style: Support multiple parts in ::part() selectors.

Differential Revision: https://phabricator.services.mozilla.com/D48753
This commit is contained in:
Emilio Cobos Álvarez 2019-10-17 00:51:54 +00:00
parent f701192e38
commit 7965ddefa6
3 changed files with 30 additions and 15 deletions

View file

@ -667,7 +667,7 @@ where
match *selector {
Component::Combinator(_) => unreachable!(),
Component::Part(ref part) => element.is_part(part),
Component::Part(ref parts) => parts.iter().all(|part| element.is_part(part)),
Component::Slotted(ref selector) => {
// <slots> are never flattened tree slottables.
!element.is_html_slot_element() &&

View file

@ -607,7 +607,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
}
#[inline]
pub fn part(&self) -> Option<&Impl::PartName> {
pub fn parts(&self) -> Option<&[Impl::PartName]> {
if !self.is_part() {
return None;
}
@ -1013,7 +1013,7 @@ pub enum Component<Impl: SelectorImpl> {
Slotted(Selector<Impl>),
/// The `::part` pseudo-element.
/// https://drafts.csswg.org/css-shadow-parts/#part
Part(#[shmem(field_bound)] Impl::PartName),
Part(#[shmem(field_bound)] Box<[Impl::PartName]>),
/// The `:host` pseudo-class:
///
/// https://drafts.csswg.org/css-scoping/#host-selector
@ -1302,9 +1302,14 @@ impl<Impl: SelectorImpl> ToCss for Component<Impl> {
selector.to_css(dest)?;
dest.write_char(')')
},
Part(ref part_name) => {
Part(ref part_names) => {
dest.write_str("::part(")?;
display_to_css_identifier(part_name, dest)?;
for (i, name) in part_names.iter().enumerate() {
if i != 0 {
dest.write_char(' ')?;
}
display_to_css_identifier(name, dest)?;
}
dest.write_char(')')
},
PseudoElement(ref p) => p.to_css(dest),
@ -1626,7 +1631,7 @@ enum SimpleSelectorParseResult<Impl: SelectorImpl> {
SimpleSelector(Component<Impl>),
PseudoElement(Impl::PseudoElement),
SlottedPseudo(Selector<Impl>),
PartPseudo(Impl::PartName),
PartPseudo(Box<[Impl::PartName]>),
}
#[derive(Debug)]
@ -2029,10 +2034,10 @@ where
SimpleSelectorParseResult::SimpleSelector(s) => {
builder.push_simple_selector(s);
},
SimpleSelectorParseResult::PartPseudo(part_name) => {
SimpleSelectorParseResult::PartPseudo(part_names) => {
state.insert(SelectorParsingState::AFTER_PART);
builder.push_combinator(Combinator::Part);
builder.push_simple_selector(Component::Part(part_name));
builder.push_simple_selector(Component::Part(part_names));
},
SimpleSelectorParseResult::SlottedPseudo(selector) => {
state.insert(SelectorParsingState::AFTER_SLOTTED);
@ -2193,10 +2198,15 @@ where
input.new_custom_error(SelectorParseErrorKind::InvalidState)
);
}
let name = input.parse_nested_block(|input| {
Ok(input.expect_ident()?.as_ref().into())
let names = input.parse_nested_block(|input| {
let mut result = Vec::with_capacity(1);
result.push(input.expect_ident()?.as_ref().into());
while !input.is_exhausted() {
result.push(input.expect_ident()?.as_ref().into());
}
Ok(result.into_boxed_slice())
})?;
return Ok(Some(SimpleSelectorParseResult::PartPseudo(name)));
return Ok(Some(SimpleSelectorParseResult::PartPseudo(names)));
}
if P::parse_slotted(parser) && name.eq_ignore_ascii_case("slotted") {
if !state.allows_slotted() {
@ -3051,8 +3061,7 @@ pub mod tests {
assert!(parse("::part()").is_err());
assert!(parse("::part(42)").is_err());
// Though note https://github.com/w3c/csswg-drafts/issues/3502
assert!(parse("::part(foo bar)").is_err());
assert!(parse("::part(foo bar)").is_ok());
assert!(parse("::part(foo):hover").is_ok());
assert!(parse("::part(foo) + bar").is_err());

View file

@ -2032,11 +2032,17 @@ impl CascadeData {
// Part is special, since given it doesn't have any
// selectors inside, it's not worth using a whole
// SelectorMap for it.
if let Some(part) = selector.part() {
if let Some(parts) = selector.parts() {
// ::part() has all semantics, so we just need to
// put any of them in the selector map.
//
// We choose the last one quite arbitrarily,
// expecting it's slightly more likely to be more
// specific.
self.part_rules
.get_or_insert_with(|| Box::new(Default::default()))
.for_insertion(pseudo_element)
.try_entry(part.clone())?
.try_entry(parts.last().unwrap().clone())?
.or_insert_with(SmallVec::new)
.try_push(rule)?;
} else {