dom: match unfocused focus-within selectors

This commit is contained in:
SGavrl committed 2026-07-26 22:39:00 +00:00
1 parent f7fec080ad
commit aff0172987
1 file changed
+33 -2
+33 -2
View File
@@ -102,6 +102,8 @@ pub enum PseudoClass {
Hover, Hover,
Active, Active,
Focus, Focus,
FocusVisible,
FocusWithin,
Enabled, Enabled,
Disabled, Disabled,
Checked, Checked,
@@ -126,7 +128,11 @@ impl parser::NonTSPseudoClass for PseudoClass {
fn is_user_action_state(&self) -> bool { fn is_user_action_state(&self) -> bool {
matches!( matches!(
self, self,
PseudoClass::Hover | PseudoClass::Active | PseudoClass::Focus PseudoClass::Hover
| PseudoClass::Active
| PseudoClass::Focus
| PseudoClass::FocusVisible
| PseudoClass::FocusWithin
) )
} }
@@ -144,6 +150,8 @@ impl ToCss for PseudoClass {
PseudoClass::Hover => dest.write_str(":hover"), PseudoClass::Hover => dest.write_str(":hover"),
PseudoClass::Active => dest.write_str(":active"), PseudoClass::Active => dest.write_str(":active"),
PseudoClass::Focus => dest.write_str(":focus"), PseudoClass::Focus => dest.write_str(":focus"),
PseudoClass::FocusVisible => dest.write_str(":focus-visible"),
PseudoClass::FocusWithin => dest.write_str(":focus-within"),
PseudoClass::Enabled => dest.write_str(":enabled"), PseudoClass::Enabled => dest.write_str(":enabled"),
PseudoClass::Disabled => dest.write_str(":disabled"), PseudoClass::Disabled => dest.write_str(":disabled"),
PseudoClass::Checked => dest.write_str(":checked"), PseudoClass::Checked => dest.write_str(":checked"),
@@ -207,6 +215,8 @@ impl<'i> parser::Parser<'i> for ObscuraSelectorParser {
"hover" => Ok(PseudoClass::Hover), "hover" => Ok(PseudoClass::Hover),
"active" => Ok(PseudoClass::Active), "active" => Ok(PseudoClass::Active),
"focus" => Ok(PseudoClass::Focus), "focus" => Ok(PseudoClass::Focus),
"focus-visible" => Ok(PseudoClass::FocusVisible),
"focus-within" => Ok(PseudoClass::FocusWithin),
"enabled" => Ok(PseudoClass::Enabled), "enabled" => Ok(PseudoClass::Enabled),
"disabled" => Ok(PseudoClass::Disabled), "disabled" => Ok(PseudoClass::Disabled),
"checked" => Ok(PseudoClass::Checked), "checked" => Ok(PseudoClass::Checked),
@@ -462,7 +472,11 @@ impl<'a> Element for DomElement<'a> {
PseudoClass::Checked => self.has_boolean_attr("checked") || self.has_boolean_attr("selected"), PseudoClass::Checked => self.has_boolean_attr("checked") || self.has_boolean_attr("selected"),
// Dynamic user-interaction pseudo-classes have no meaning against // Dynamic user-interaction pseudo-classes have no meaning against
// a static DOM snapshot with no live user input. // a static DOM snapshot with no live user input.
PseudoClass::Hover | PseudoClass::Active | PseudoClass::Focus => false, PseudoClass::Hover
| PseudoClass::Active
| PseudoClass::Focus
| PseudoClass::FocusVisible
| PseudoClass::FocusWithin => false,
} }
} }
@@ -990,6 +1004,23 @@ mod tests {
assert_eq!(tree.query_selector_all("input:checked").unwrap().len(), 1); assert_eq!(tree.query_selector_all("input:checked").unwrap().len(), 1);
} }
#[test]
fn unfocused_snapshot_matches_focus_negation_selectors() {
let tree = parse_html(
r#"<div class="visually-hidden-focusable">Skip</div>"#,
);
let hidden = tree
.query_selector_all(
".visually-hidden-focusable:not(:focus):not(:focus-within)",
)
.unwrap();
assert_eq!(hidden.len(), 1);
assert_eq!(
tree.query_selector_all(":focus-visible").unwrap().len(),
0
);
}
#[test] #[test]
fn test_query_selector_descendant() { fn test_query_selector_descendant() {
let tree = let tree =