Skip to content

Commit

Permalink
fix: do not prune selectors like :global(.foo):has(.scoped) (#15140)
Browse files Browse the repository at this point in the history
Fixes #14910

The issue occurs only when :has() targets at a component's root element and because include_self is false.
I came to the conclusion that this is the same case as :root:has(.scoped).
  • Loading branch information
7nik authored Jan 30, 2025
1 parent 8e83127 commit 5225575
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/famous-bulldogs-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: do not prune selectors like `:global(.foo):has(.scoped)`
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,18 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element)
let sibling_elements; // do them lazy because it's rarely used and expensive to calculate

// If this is a :has inside a global selector, we gotta include the element itself, too,
// because the global selector might be for an element that's outside the component (e.g. :root).
// because the global selector might be for an element that's outside the component,
// e.g. :root:has(.scoped), :global(.foo):has(.scoped), or :root { &:has(.scoped) {} }
const rules = get_parent_rules(rule);
const include_self =
rules.some((r) => r.prelude.children.some((c) => c.children.some((s) => is_global(s, r)))) ||
rules[rules.length - 1].prelude.children.some((c) =>
c.children.some((r) =>
r.selectors.some((s) => s.type === 'PseudoClassSelector' && s.name === 'root')
r.selectors.some(
(s) =>
s.type === 'PseudoClassSelector' &&
(s.name === 'root' || (s.name === 'global' && s.args))
)
)
);
if (include_self) {
Expand Down
14 changes: 14 additions & 0 deletions packages/svelte/tests/css/samples/has/_config.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,20 @@ export default test({
column: 16,
character: 1614
}
},
{
code: 'css_unused_selector',
message: 'Unused CSS selector ":global(.foo):has(.unused)"',
start: {
line: 155,
column: 1,
character: 1684
},
end: {
line: 155,
column: 27,
character: 1710
}
}
]
});
7 changes: 7 additions & 0 deletions packages/svelte/tests/css/samples/has/expected.css
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,10 @@
color: red;
}*/
}

.foo:has(x.svelte-xyz) {
color: green;
}
/* (unused) :global(.foo):has(.unused) {
color: red;
}*/
7 changes: 7 additions & 0 deletions packages/svelte/tests/css/samples/has/input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,11 @@
color: red;
}
}
:global(.foo):has(x) {
color: green;
}
:global(.foo):has(.unused) {
color: red;
}
</style>

0 comments on commit 5225575

Please sign in to comment.