Skip to content

Commit 25f1189

Browse files
committed
Move to :where() selector to keep specifity
1 parent 0729feb commit 25f1189

3 files changed

Lines changed: 98 additions & 39 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,10 @@ Use `lightSelector: '[data-theme="light"]'` if you will switch theme by setting
190190
Type: `string[]`, `string`. Default: `['html', ':root']`.
191191

192192
Selector for node for CSS Custom properties and dark/light theme classes.
193+
194+
195+
## `useWhere`
196+
197+
Type: `boolean`. Default: `true`.
198+
199+
Should plugin wrap added selector to `:where()` to keep origin specificity.

index.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ module.exports = (opts = {}) => {
1616
let roots = opts.rootSelector || ['html', ':root']
1717
if (!Array.isArray(roots)) roots = [roots]
1818

19+
let useWhere = opts.useWhere ?? true
20+
1921
let uniqueRoots = roots
2022
if (uniqueRoots.includes('html')) {
2123
uniqueRoots = uniqueRoots.filter(i => i !== ':root')
@@ -27,12 +29,22 @@ module.exports = (opts = {}) => {
2729
for (let root of roots) {
2830
if (selector.includes(root)) {
2931
changed = true
30-
selector = replaceAll(selector, root, root + add)
32+
if (useWhere) {
33+
selector = replaceAll(selector, root, `${root}:where(${add})`)
34+
} else {
35+
selector = replaceAll(selector, root, `${root}${add}`)
36+
}
3137
}
3238
}
3339
if (!changed) {
3440
selector = uniqueRoots
35-
.map(root => `${root}${add} ${selector}`)
41+
.map(root => {
42+
if (useWhere) {
43+
return `:where(${root}${add}) ${selector}`
44+
} else {
45+
return `${root}${add} ${selector}`
46+
}
47+
})
3648
.join(',')
3749
}
3850
return selector

index.test.js

Lines changed: 77 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ function run(input, output, opts) {
1111
}
1212

1313
test('replaces selectors', () => {
14+
run(
15+
`@media (prefers-color-scheme:dark) {
16+
html.is-a,
17+
html,
18+
:root,
19+
a { }
20+
}`,
21+
`@media (prefers-color-scheme:dark) {
22+
html:where(:not(.is-light)).is-a,
23+
html:where(:not(.is-light)),
24+
:root:where(:not(.is-light)),
25+
:where(html:not(.is-light)) a { }
26+
}
27+
html:where(.is-dark).is-a,
28+
html:where(.is-dark),
29+
:root:where(.is-dark),
30+
:where(html.is-dark) a { }`
31+
)
32+
})
33+
34+
test('disables :where() of request', () => {
1435
run(
1536
`@media (prefers-color-scheme:dark) {
1637
html.is-a,
@@ -27,22 +48,41 @@ test('replaces selectors', () => {
2748
html.is-dark.is-a,
2849
html.is-dark,
2950
:root.is-dark,
30-
html.is-dark a { }`
51+
html.is-dark a { }`,
52+
{ useWhere: false }
3153
)
3254
})
3355

3456
test('processes inner at-rules', () => {
3557
run(
3658
`@media (prefers-color-scheme: dark) {
37-
@media (min-width: 500px) { a { } }
38-
@media (min-width: 500px) { @media (print) { a { } } }
59+
@media (min-width: 500px) {
60+
a { }
61+
}
62+
@media (min-width: 500px) {
63+
@media (print) {
64+
a { }
65+
}
66+
}
3967
}`,
4068
`@media (prefers-color-scheme: dark) {
41-
@media (min-width: 500px) { html:not(.is-light) a { } }
42-
@media (min-width: 500px) { @media (print) { html:not(.is-light) a { } } }
69+
@media (min-width: 500px) {
70+
:where(html:not(.is-light)) a { }
71+
}
72+
@media (min-width: 500px) {
73+
@media (print) {
74+
:where(html:not(.is-light)) a { }
75+
}
76+
}
4377
}
44-
@media (min-width: 500px) { html.is-dark a { } }
45-
@media (min-width: 500px) { @media (print) { html.is-dark a { } } }`
78+
@media (min-width: 500px) {
79+
:where(html.is-dark) a { }
80+
}
81+
@media (min-width: 500px) {
82+
@media (print) {
83+
:where(html.is-dark) a { }
84+
}
85+
}`
4686
)
4787
})
4888

@@ -69,27 +109,27 @@ test('ignores whitespaces', () => {
69109
a { color: white }
70110
}`,
71111
`@media ( prefers-color-scheme:dark ) {
72-
html:not(.is-light) a { color: white }
112+
:where(html:not(.is-light)) a { color: white }
73113
}
74-
html.is-dark a { color: white }`
114+
:where(html.is-dark) a { color: white }`
75115
)
76116
})
77117

78118
test('reserve comments', () => {
79119
run(
80120
`@media (prefers-color-scheme:dark) {
81-
/* some comments */
121+
/* a */
82122
a { color: white }
83-
@media (min-width: 500px) { /* another comments */ a { } }
123+
@media (min-width: 500px) { /* b */ a { } }
84124
}`,
85125
`@media (prefers-color-scheme:dark) {
86-
/* some comments */
87-
html:not(.is-light) a { color: white }
88-
@media (min-width: 500px) { /* another comments */ html:not(.is-light) a { } }
126+
/* a */
127+
:where(html:not(.is-light)) a { color: white }
128+
@media (min-width: 500px) { /* b */ :where(html:not(.is-light)) a { } }
89129
}
90-
/* some comments */
91-
html.is-dark a { color: white }
92-
@media (min-width: 500px) { /* another comments */ html.is-dark a { } }`
130+
/* a */
131+
:where(html.is-dark) a { color: white }
132+
@media (min-width: 500px) { /* b */ :where(html.is-dark) a { } }`
93133
)
94134
})
95135

@@ -99,9 +139,9 @@ test('supports combined queries', () => {
99139
a { color: white }
100140
}`,
101141
`@media (min-width: 60px) and (prefers-color-scheme: dark) {
102-
html:not(.is-light) a { color: white }
142+
:where(html:not(.is-light)) a { color: white }
103143
}@media (min-width: 60px) {
104-
html.is-dark a { color: white }
144+
:where(html.is-dark) a { color: white }
105145
}`
106146
)
107147
})
@@ -112,9 +152,9 @@ test('supports combined queries in the middle', () => {
112152
a { color: white }
113153
}`,
114154
`@media (width > 0) and (prefers-color-scheme: dark) and (width > 0) {
115-
html:not(.is-light) a { color: white }
155+
:where(html:not(.is-light)) a { color: white }
116156
}@media (width > 0) and (width > 0) {
117-
html.is-dark a { color: white }
157+
:where(html.is-dark) a { color: white }
118158
}`
119159
)
120160
})
@@ -125,30 +165,30 @@ test('allows to change class', () => {
125165
a { color: white }
126166
}`,
127167
`@media (prefers-color-scheme: dark) {
128-
html:not(.light-theme) a { color: white }
168+
:where(html:not(.light-theme)) a { color: white }
129169
}
130-
html.dark-theme a { color: white }`,
170+
:where(html.dark-theme) a { color: white }`,
131171
{ darkSelector: '.dark-theme', lightSelector: '.light-theme' }
132172
)
133173
})
134174

135175
test('changes root selectors', () => {
136176
run(
137177
`@media (prefers-color-scheme: dark) {
138-
html, .storybook { --bg: black }
178+
html, .s { --bg: black }
139179
p { color: white }
140180
}
141-
html, .storybook { --bg: white }
181+
html, .s { --bg: white }
142182
p { color: black }`,
143183
`@media (prefers-color-scheme: dark) {
144-
html:not(.is-light), .storybook:not(.is-light) { --bg: black }
145-
html:not(.is-light) p,.storybook:not(.is-light) p { color: white }
184+
html:where(:not(.is-light)), .s:where(:not(.is-light)) { --bg: black }
185+
:where(html:not(.is-light)) p,:where(.s:not(.is-light)) p { color: white }
146186
}
147-
html.is-dark, .storybook.is-dark { --bg: black }
148-
html.is-dark p,.storybook.is-dark p { color: white }
149-
html, .storybook { --bg: white }
187+
html:where(.is-dark), .s:where(.is-dark) { --bg: black }
188+
:where(html.is-dark) p,:where(.s.is-dark) p { color: white }
189+
html, .s { --bg: white }
150190
p { color: black }`,
151-
{ rootSelector: ['html', ':root', '.storybook'] }
191+
{ rootSelector: ['html', ':root', '.s'] }
152192
)
153193
})
154194

@@ -161,11 +201,11 @@ test('changes root selector', () => {
161201
body { --bg: white }
162202
p { color: black }`,
163203
`@media (prefers-color-scheme: dark) {
164-
body:not(.is-light) { --bg: black }
165-
body:not(.is-light) p { color: white }
204+
body:where(:not(.is-light)) { --bg: black }
205+
:where(body:not(.is-light)) p { color: white }
166206
}
167-
body.is-dark { --bg: black }
168-
body.is-dark p { color: white }
207+
body:where(.is-dark) { --bg: black }
208+
:where(body.is-dark) p { color: white }
169209
body { --bg: white }
170210
p { color: black }`,
171211
{ rootSelector: 'body' }
@@ -181,9 +221,9 @@ test('ignores already transformed rules', () => {
181221
:root { --bg: white }`,
182222
`@media (prefers-color-scheme: dark) {
183223
:root:not(.is-light) { --bg: black }
184-
html:not(.is-light) p { color: white }
224+
:where(html:not(.is-light)) p { color: white }
185225
}
186-
html.is-dark p { color: white }
226+
:where(html.is-dark) p { color: white }
187227
:root { --bg: white }`
188228
)
189229
})

0 commit comments

Comments
 (0)