diff --git a/src/preview/rewriteStyleSheet.test.ts b/src/preview/rewriteStyleSheet.test.ts index c746f43..cb234ec 100644 --- a/src/preview/rewriteStyleSheet.test.ts +++ b/src/preview/rewriteStyleSheet.test.ts @@ -243,6 +243,42 @@ describe("rewriteStyleSheet", () => { expect(selectors).toContain(":host(.a.pseudo-focus-all.pseudo-hover-all) .b") }) + it('supports ":host-context"', () => { + const sheet = new Sheet(":host-context(:hover) { color: red }") + rewriteStyleSheet(sheet as any, true) + const selectors = sheet.cssRules[0].getSelectors() + expect(selectors).toContain(":host-context(:hover)") + expect(selectors).toContain(":host-context(.pseudo-hover)") + expect(selectors).toContain(":host(.pseudo-hover-all)") + }) + + it('supports ":host-context" with classes', () => { + const sheet = new Sheet(":host-context(.a:hover) .b { color: red }") + rewriteStyleSheet(sheet as any, true) + const selectors = sheet.cssRules[0].getSelectors() + expect(selectors).toContain(":host-context(.a:hover) .b") + expect(selectors).toContain(":host-context(.a.pseudo-hover) .b") + expect(selectors).toContain(":host-context(.a).pseudo-hover-all .b") + }) + + it('supports ":host-context" with state selectors in descendant selector', () => { + const sheet = new Sheet(":host-context(.a) .b:hover { color: red }") + rewriteStyleSheet(sheet as any, true) + const selectors = sheet.cssRules[0].getSelectors() + expect(selectors).toContain(":host-context(.a) .b:hover") + expect(selectors).toContain(":host-context(.a) .b.pseudo-hover") + expect(selectors).toContain(":host-context(.a).pseudo-hover-all .b") + }) + + it('supports ":host-context" with state selectors in :host-context and descendant selector', () => { + const sheet = new Sheet(":host-context(.a:focus) .b:hover { color: red }") + rewriteStyleSheet(sheet as any, true) + const selectors = sheet.cssRules[0].getSelectors() + expect(selectors).toContain(":host-context(.a:focus) .b:hover") + expect(selectors).toContain(":host-context(.a.pseudo-focus) .b.pseudo-hover") + expect(selectors).toContain(":host-context(.a).pseudo-focus-all.pseudo-hover-all .b") + }) + it('supports "::slotted"', () => { const sheet = new Sheet("::slotted(:hover) { color: red }") rewriteStyleSheet(sheet as any, true) diff --git a/src/preview/rewriteStyleSheet.ts b/src/preview/rewriteStyleSheet.ts index 3c6bfa9..4960a46 100644 --- a/src/preview/rewriteStyleSheet.ts +++ b/src/preview/rewriteStyleSheet.ts @@ -24,13 +24,22 @@ const replacePseudoStates = (selector: string, allClass?: boolean) => { // Does not handle :host() or :not() containing pseudo-states. Need to call replaceNotSelectors on the input first. const replacePseudoStatesWithAncestorSelector = (selector: string, forShadowDOM: boolean, additionalHostSelectors?: string) => { - const { states, withoutPseudoStates } = extractPseudoStates(selector) - const classes = states.map((s) => `.pseudo-${s}-all`).join("") - return states.length === 0 && !additionalHostSelectors - ? selector + let { states, withoutPseudoStates } = extractPseudoStates(selector) + if (states.length === 0 && !additionalHostSelectors) { + return selector + } + const selectors = `${additionalHostSelectors ?? ""}${states.map((s) => `.pseudo-${s}-all`).join("")}` + + // If there was a :host-context() containing only pseudo-states, we will later add a :host selector that replaces it. + withoutPseudoStates = withoutPseudoStates.replace(":host-context(*)", "").trimStart() + + // If there is a :host-context() selector, we don't need to introduce a :host() selector. + // We can just append the pseudo-state classes to the :host-context() selector. + return withoutPseudoStates.startsWith(":host-context(") + ? withoutPseudoStates.replace(/(?<=:host-context\(\S+)\)/, `)${selectors}`) : forShadowDOM - ? `:host(${additionalHostSelectors ?? ""}${classes}) ${withoutPseudoStates}` - : `${classes} ${withoutPseudoStates}` + ? `:host(${selectors}) ${withoutPseudoStates}` + : `${selectors} ${withoutPseudoStates}` } const extractPseudoStates = (selector: string) => {