Skip to content

Commit

Permalink
Move to :where() selector to keep specifity
Browse files Browse the repository at this point in the history
  • Loading branch information
ai committed Aug 11, 2023
1 parent 0729feb commit 25f1189
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 39 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,10 @@ Use `lightSelector: '[data-theme="light"]'` if you will switch theme by setting
Type: `string[]`, `string`. Default: `['html', ':root']`.

Selector for node for CSS Custom properties and dark/light theme classes.


## `useWhere`

Type: `boolean`. Default: `true`.

Should plugin wrap added selector to `:where()` to keep origin specificity.
16 changes: 14 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ module.exports = (opts = {}) => {
let roots = opts.rootSelector || ['html', ':root']
if (!Array.isArray(roots)) roots = [roots]

let useWhere = opts.useWhere ?? true

let uniqueRoots = roots
if (uniqueRoots.includes('html')) {
uniqueRoots = uniqueRoots.filter(i => i !== ':root')
Expand All @@ -27,12 +29,22 @@ module.exports = (opts = {}) => {
for (let root of roots) {
if (selector.includes(root)) {
changed = true
selector = replaceAll(selector, root, root + add)
if (useWhere) {
selector = replaceAll(selector, root, `${root}:where(${add})`)
} else {
selector = replaceAll(selector, root, `${root}${add}`)
}
}
}
if (!changed) {
selector = uniqueRoots
.map(root => `${root}${add} ${selector}`)
.map(root => {
if (useWhere) {
return `:where(${root}${add}) ${selector}`
} else {
return `${root}${add} ${selector}`
}
})
.join(',')
}
return selector
Expand Down
114 changes: 77 additions & 37 deletions index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ function run(input, output, opts) {
}

test('replaces selectors', () => {
run(
`@media (prefers-color-scheme:dark) {
html.is-a,
html,
:root,
a { }
}`,
`@media (prefers-color-scheme:dark) {
html:where(:not(.is-light)).is-a,
html:where(:not(.is-light)),
:root:where(:not(.is-light)),
:where(html:not(.is-light)) a { }
}
html:where(.is-dark).is-a,
html:where(.is-dark),
:root:where(.is-dark),
:where(html.is-dark) a { }`
)
})

test('disables :where() of request', () => {
run(
`@media (prefers-color-scheme:dark) {
html.is-a,
Expand All @@ -27,22 +48,41 @@ test('replaces selectors', () => {
html.is-dark.is-a,
html.is-dark,
:root.is-dark,
html.is-dark a { }`
html.is-dark a { }`,
{ useWhere: false }
)
})

test('processes inner at-rules', () => {
run(
`@media (prefers-color-scheme: dark) {
@media (min-width: 500px) { a { } }
@media (min-width: 500px) { @media (print) { a { } } }
@media (min-width: 500px) {
a { }
}
@media (min-width: 500px) {
@media (print) {
a { }
}
}
}`,
`@media (prefers-color-scheme: dark) {
@media (min-width: 500px) { html:not(.is-light) a { } }
@media (min-width: 500px) { @media (print) { html:not(.is-light) a { } } }
@media (min-width: 500px) {
:where(html:not(.is-light)) a { }
}
@media (min-width: 500px) {
@media (print) {
:where(html:not(.is-light)) a { }
}
}
}
@media (min-width: 500px) { html.is-dark a { } }
@media (min-width: 500px) { @media (print) { html.is-dark a { } } }`
@media (min-width: 500px) {
:where(html.is-dark) a { }
}
@media (min-width: 500px) {
@media (print) {
:where(html.is-dark) a { }
}
}`
)
})

Expand All @@ -69,27 +109,27 @@ test('ignores whitespaces', () => {
a { color: white }
}`,
`@media ( prefers-color-scheme:dark ) {
html:not(.is-light) a { color: white }
:where(html:not(.is-light)) a { color: white }
}
html.is-dark a { color: white }`
:where(html.is-dark) a { color: white }`
)
})

test('reserve comments', () => {
run(
`@media (prefers-color-scheme:dark) {
/* some comments */
/* a */
a { color: white }
@media (min-width: 500px) { /* another comments */ a { } }
@media (min-width: 500px) { /* b */ a { } }
}`,
`@media (prefers-color-scheme:dark) {
/* some comments */
html:not(.is-light) a { color: white }
@media (min-width: 500px) { /* another comments */ html:not(.is-light) a { } }
/* a */
:where(html:not(.is-light)) a { color: white }
@media (min-width: 500px) { /* b */ :where(html:not(.is-light)) a { } }
}
/* some comments */
html.is-dark a { color: white }
@media (min-width: 500px) { /* another comments */ html.is-dark a { } }`
/* a */
:where(html.is-dark) a { color: white }
@media (min-width: 500px) { /* b */ :where(html.is-dark) a { } }`
)
})

Expand All @@ -99,9 +139,9 @@ test('supports combined queries', () => {
a { color: white }
}`,
`@media (min-width: 60px) and (prefers-color-scheme: dark) {
html:not(.is-light) a { color: white }
:where(html:not(.is-light)) a { color: white }
}@media (min-width: 60px) {
html.is-dark a { color: white }
:where(html.is-dark) a { color: white }
}`
)
})
Expand All @@ -112,9 +152,9 @@ test('supports combined queries in the middle', () => {
a { color: white }
}`,
`@media (width > 0) and (prefers-color-scheme: dark) and (width > 0) {
html:not(.is-light) a { color: white }
:where(html:not(.is-light)) a { color: white }
}@media (width > 0) and (width > 0) {
html.is-dark a { color: white }
:where(html.is-dark) a { color: white }
}`
)
})
Expand All @@ -125,30 +165,30 @@ test('allows to change class', () => {
a { color: white }
}`,
`@media (prefers-color-scheme: dark) {
html:not(.light-theme) a { color: white }
:where(html:not(.light-theme)) a { color: white }
}
html.dark-theme a { color: white }`,
:where(html.dark-theme) a { color: white }`,
{ darkSelector: '.dark-theme', lightSelector: '.light-theme' }
)
})

test('changes root selectors', () => {
run(
`@media (prefers-color-scheme: dark) {
html, .storybook { --bg: black }
html, .s { --bg: black }
p { color: white }
}
html, .storybook { --bg: white }
html, .s { --bg: white }
p { color: black }`,
`@media (prefers-color-scheme: dark) {
html:not(.is-light), .storybook:not(.is-light) { --bg: black }
html:not(.is-light) p,.storybook:not(.is-light) p { color: white }
html:where(:not(.is-light)), .s:where(:not(.is-light)) { --bg: black }
:where(html:not(.is-light)) p,:where(.s:not(.is-light)) p { color: white }
}
html.is-dark, .storybook.is-dark { --bg: black }
html.is-dark p,.storybook.is-dark p { color: white }
html, .storybook { --bg: white }
html:where(.is-dark), .s:where(.is-dark) { --bg: black }
:where(html.is-dark) p,:where(.s.is-dark) p { color: white }
html, .s { --bg: white }
p { color: black }`,
{ rootSelector: ['html', ':root', '.storybook'] }
{ rootSelector: ['html', ':root', '.s'] }
)
})

Expand All @@ -161,11 +201,11 @@ test('changes root selector', () => {
body { --bg: white }
p { color: black }`,
`@media (prefers-color-scheme: dark) {
body:not(.is-light) { --bg: black }
body:not(.is-light) p { color: white }
body:where(:not(.is-light)) { --bg: black }
:where(body:not(.is-light)) p { color: white }
}
body.is-dark { --bg: black }
body.is-dark p { color: white }
body:where(.is-dark) { --bg: black }
:where(body.is-dark) p { color: white }
body { --bg: white }
p { color: black }`,
{ rootSelector: 'body' }
Expand All @@ -181,9 +221,9 @@ test('ignores already transformed rules', () => {
:root { --bg: white }`,
`@media (prefers-color-scheme: dark) {
:root:not(.is-light) { --bg: black }
html:not(.is-light) p { color: white }
:where(html:not(.is-light)) p { color: white }
}
html.is-dark p { color: white }
:where(html.is-dark) p { color: white }
:root { --bg: white }`
)
})
Expand Down

0 comments on commit 25f1189

Please sign in to comment.