Skip to content

Commit

Permalink
Make :not work for shadowDOM
Browse files Browse the repository at this point in the history
  • Loading branch information
m-akinc committed Apr 8, 2024
1 parent f2e76e2 commit 721e16f
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 22 deletions.
27 changes: 9 additions & 18 deletions src/preview/rewriteStyleSheet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,29 +243,20 @@ describe("rewriteStyleSheet", () => {

it('supports "::slotted"', () => {
const sheet = new Sheet("::slotted(:hover) { color: red }")
rewriteStyleSheet(sheet as any)
rewriteStyleSheet(sheet as any, true)
const selectors = sheet.cssRules[0].getSelectors()
expect(selectors).toContain("::slotted(:hover)")
expect(selectors).toContain("::slotted(.pseudo-hover)")
expect(selectors).toContain(":host(.pseudo-hover-all) ::slotted(*)")
})

it('supports "::slotted" with classes', () => {
const sheet = new Sheet("::slotted(.a:hover, .b) .c { color: red }")
rewriteStyleSheet(sheet as any)
const selectors = sheet.cssRules[0].getSelectors()
expect(selectors).toContain("::slotted(.a:hover, .b) .c")
expect(selectors).toContain("::slotted(.a.pseudo-hover, .b) .c")
expect(selectors).toContain(":host(.pseudo-hover-all) ::slotted(.a, .b) .c")
})

it('supports "::slotted" with state selectors in descendant selector', () => {
const sheet = new Sheet("::slotted(.a) .b:hover { color: red }")
rewriteStyleSheet(sheet as any)
const sheet = new Sheet(".a > slot::slotted(.b:hover) { color: red }")
rewriteStyleSheet(sheet as any, true)
const selectors = sheet.cssRules[0].getSelectors()
expect(selectors).toContain("::slotted(.a) .b:hover")
expect(selectors).toContain("::slotted(.a) .b.pseudo-hover")
expect(selectors).toContain(":host(.pseudo-hover-all) ::slotted(.a) .b")
expect(selectors).toContain(".a > slot::slotted(.b:hover)")
expect(selectors).toContain(".a > slot::slotted(.b.pseudo-hover)")
expect(selectors).toContain(":host(.pseudo-hover-all) .a > slot::slotted(.b)")
})

it('supports ":not"', () => {
Expand All @@ -276,8 +267,8 @@ describe("rewriteStyleSheet", () => {

it('supports ":not" in shadow DOM', () => {
const sheet = new Sheet(":not(:hover) { color: red }")
rewriteStyleSheet(sheet as any)
expect(sheet.cssRules[0].selectorText).toEqual(":not(:hover), :not(.pseudo-hover), :host(:not(.pseudo-hover-all)) *")
rewriteStyleSheet(sheet as any, true)
expect(sheet.cssRules[0].selectorText).toEqual(":not(:hover), :not(.pseudo-hover), :not(:host(.pseudo-hover-all) *)")
})

it('supports complex use of ":not"', () => {
Expand All @@ -295,7 +286,7 @@ describe("rewriteStyleSheet", () => {
const selectors = sheet.cssRules[0].getSelectors()
expect(selectors).toContain("foo:focus:not(:hover, .bar:active) .baz")
expect(selectors).toContain("foo.pseudo-focus:not(.pseudo-hover, .bar.pseudo-active) .baz")
expect(selectors).toContain(":host(.pseudo-focus-all:not(.pseudo-hover-all, .pseudo-active-all)) foo:not(.bar) .baz")
expect(selectors).toContain(":host(.pseudo-focus-all) foo:not(:host(.pseudo-hover-all) *, :host(.pseudo-active-all) .bar) .baz")
})

it('supports ":has"', () => {
Expand Down
6 changes: 2 additions & 4 deletions src/preview/rewriteStyleSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ const rewriteRule = ({ cssText, selectorText }: CSSStyleRule, forShadowDOM: bool
} else {
ancestorSelector = states.reduce((acc, state) => acc.replace(replacementRegExp(state), `.pseudo-${state}-all`), selector)
}
} else if (selector.startsWith("::slotted(") || forShadowDOM) {
ancestorSelector = replacePseudoStatesWithDescendantSelector(selector, true)
} else {
ancestorSelector = selector
const matches = [...selector.matchAll(/:not\(([^)]+)\)/g)]
Expand All @@ -81,13 +79,13 @@ const rewriteRule = ({ cssText, selectorText }: CSSStyleRule, forShadowDOM: bool
// For each negated selector
for (const negatedSelector of selectorList.split(/,\s*/)) {
// :not cannot be nested and cannot contain pseudo-elements, so no need to worry about that.
rewrittenSelectors.push(replacePseudoStatesWithDescendantSelector(negatedSelector))
rewrittenSelectors.push(replacePseudoStatesWithDescendantSelector(negatedSelector, forShadowDOM))
}
const rewrittenNot = `:not(${rewrittenSelectors.join(", ")})`
ancestorSelector = ancestorSelector.replace(match[0], rewrittenNot)
}
}
ancestorSelector = replacePseudoStatesWithDescendantSelector(ancestorSelector)
ancestorSelector = replacePseudoStatesWithDescendantSelector(ancestorSelector, forShadowDOM)
}

return [selector, classSelector, ancestorSelector]
Expand Down

0 comments on commit 721e16f

Please sign in to comment.