diff --git a/src/util/applyImportantSelector.js b/src/util/applyImportantSelector.js index ff9ec4f4b343..07302f94d5f6 100644 --- a/src/util/applyImportantSelector.js +++ b/src/util/applyImportantSelector.js @@ -5,13 +5,12 @@ export function applyImportantSelector(selector, important) { let sel = parser().astSync(selector) sel.each((sel) => { - // Wrap with :is if it's not already wrapped - let isWrapped = - sel.nodes[0].type === 'pseudo' && - sel.nodes[0].value === ':is' && - sel.nodes.every((node) => node.type !== 'combinator') + // For nesting, we only need to wrap a selector with :is() if it has a top-level combinator, + // e.g. `.dark .text-white`, to be independent of DOM order. Any other selector, including + // combinators inside of pseudos like `:where()`, are ok to nest. + let shouldWrap = sel.nodes.some((node) => node.type === 'combinator') - if (!isWrapped) { + if (shouldWrap) { sel.nodes = [ parser.pseudo({ value: ':is', diff --git a/tests/util/apply-important-selector.test.js b/tests/util/apply-important-selector.test.js index f5d3697cf88c..cd971b92c732 100644 --- a/tests/util/apply-important-selector.test.js +++ b/tests/util/apply-important-selector.test.js @@ -2,24 +2,23 @@ import { applyImportantSelector } from '../../src/util/applyImportantSelector' it.each` before | after - ${'.foo'} | ${'#app :is(.foo)'} + ${'.foo'} | ${'#app .foo'} ${'.foo .bar'} | ${'#app :is(.foo .bar)'} - ${'.foo:hover'} | ${'#app :is(.foo:hover)'} + ${'.foo:hover'} | ${'#app .foo:hover'} ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} - ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} - ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} + ${'.foo::before'} | ${'#app .foo::before'} + ${'.foo::file-selector-button'} | ${'#app .foo::file-selector-button'} + ${'.foo::-webkit-progress-bar'} | ${'#app .foo::-webkit-progress-bar'} + ${'.foo:hover::before'} | ${'#app .foo:hover::before'} ${':is(:where(.dark) :is(:where([dir="rtl"]) .foo::before))'} | ${'#app :is(:where(.dark) :is(:where([dir="rtl"]) .foo))::before'} ${':is(:where(.dark) .foo) .bar'} | ${'#app :is(:is(:where(.dark) .foo) .bar)'} ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} - ${'.foo:before'} | ${'#app :is(.foo):before'} - ${'.foo::some-uknown-pseudo'} | ${'#app :is(.foo)::some-uknown-pseudo'} - ${'.foo::some-uknown-pseudo:hover'} | ${'#app :is(.foo)::some-uknown-pseudo:hover'} - ${'.foo:focus::some-uknown-pseudo:hover'} | ${'#app :is(.foo:focus)::some-uknown-pseudo:hover'} - ${'.foo:hover::some-uknown-pseudo:focus'} | ${'#app :is(.foo:hover)::some-uknown-pseudo:focus'} + ${'.foo:before'} | ${'#app .foo:before'} + ${'.foo::some-uknown-pseudo'} | ${'#app .foo::some-uknown-pseudo'} + ${'.foo::some-uknown-pseudo:hover'} | ${'#app .foo::some-uknown-pseudo:hover'} + ${'.foo:focus::some-uknown-pseudo:hover'} | ${'#app .foo:focus::some-uknown-pseudo:hover'} + ${'.foo:hover::some-uknown-pseudo:focus'} | ${'#app .foo:hover::some-uknown-pseudo:focus'} `('should generate "$after" from "$before"', ({ before, after }) => { expect(applyImportantSelector(before, '#app')).toEqual(after) })