diff --git a/.changeset/five-zoos-brush.md b/.changeset/five-zoos-brush.md new file mode 100644 index 0000000000..ff28e81ae2 --- /dev/null +++ b/.changeset/five-zoos-brush.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: mark `:has` selectors with multiple preceding selectors as used diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js index 64cbf28891..f65d1c281d 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js @@ -202,12 +202,17 @@ function apply_selector(relative_selectors, rule, element, stylesheet, check_has const possible_match = relative_selector_might_apply_to_node( relative_selector, + parent_selectors, rule, element, stylesheet, check_has ); + if (possible_match === 'definite_match') { + return true; + } + if (!possible_match) { return false; } @@ -388,14 +393,16 @@ const regex_backslash_and_following_character = /\\(.)/g; * Ensure that `element` satisfies each simple selector in `relative_selector` * * @param {Compiler.Css.RelativeSelector} relative_selector + * @param {Compiler.Css.RelativeSelector[]} parent_selectors * @param {Compiler.Css.Rule} rule * @param {Compiler.AST.RegularElement | Compiler.AST.SvelteElement} element * @param {Compiler.Css.StyleSheet} stylesheet * @param {boolean} check_has Whether or not to check the `:has(...)` selectors - * @returns {boolean} + * @returns {boolean | 'definite_match'} */ function relative_selector_might_apply_to_node( relative_selector, + parent_selectors, rule, element, stylesheet, @@ -446,7 +453,7 @@ function relative_selector_might_apply_to_node( apply_combinator( left_most_combinator, selectors[0] ?? [], - [relative_selector], + [...parent_selectors, relative_selector], rule, element, stylesheet, @@ -478,7 +485,8 @@ function relative_selector_might_apply_to_node( } } - return true; + // We return this to signal the parent "don't bother checking the rest of the selectors, I already did that" + return 'definite_match'; } for (const selector of other_selectors) { diff --git a/packages/svelte/tests/css/samples/has/expected.css b/packages/svelte/tests/css/samples/has/expected.css index a543916631..8b01b2a749 100644 --- a/packages/svelte/tests/css/samples/has/expected.css +++ b/packages/svelte/tests/css/samples/has/expected.css @@ -85,3 +85,6 @@ /* (unused) x:has(> z) { color: red; }*/ + x.svelte-xyz > y:where(.svelte-xyz):has(z:where(.svelte-xyz)) { + color: green; + } diff --git a/packages/svelte/tests/css/samples/has/input.svelte b/packages/svelte/tests/css/samples/has/input.svelte index 0a9644d2ae..2cbd06b95a 100644 --- a/packages/svelte/tests/css/samples/has/input.svelte +++ b/packages/svelte/tests/css/samples/has/input.svelte @@ -91,4 +91,7 @@ x:has(> z) { color: red; } + x > y:has(z) { + color: green; + }