Skip to content

Commit

Permalink
Merge pull request #118 from m-akinc/support-host-context
Browse files Browse the repository at this point in the history
Support `:host-context()` selector
  • Loading branch information
ghengeveld authored May 6, 2024
2 parents 59cb994 + a129089 commit a5ea4c7
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 6 deletions.
36 changes: 36 additions & 0 deletions src/preview/rewriteStyleSheet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
21 changes: 15 additions & 6 deletions src/preview/rewriteStyleSheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down

0 comments on commit a5ea4c7

Please sign in to comment.