mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Try to use lowest impact selector when filling in defaults (#4866)
This commit is contained in:
parent
81e9f651e4
commit
4a070ac0be
@ -1,14 +1,43 @@
|
||||
import postcss from 'postcss'
|
||||
import selectorParser from 'postcss-selector-parser'
|
||||
|
||||
function minimumImpactSelector(nodes) {
|
||||
let pseudos = nodes.filter((n) => n.type === 'pseudo')
|
||||
let [bestNode] = nodes
|
||||
|
||||
for (let [type, getNode = (n) => n] of [
|
||||
['class'],
|
||||
[
|
||||
'id',
|
||||
(n) =>
|
||||
selectorParser.attribute({
|
||||
attribute: 'id',
|
||||
operator: '=',
|
||||
value: n.value,
|
||||
quoteMark: '"',
|
||||
}),
|
||||
],
|
||||
['attribute'],
|
||||
]) {
|
||||
let match = nodes.find((n) => n.type === type)
|
||||
|
||||
if (match) {
|
||||
bestNode = getNode(match)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return [bestNode, ...pseudos].join('').trim()
|
||||
}
|
||||
|
||||
let elementSelectorParser = selectorParser((selectors) => {
|
||||
return selectors.map((s) => {
|
||||
return s
|
||||
let nodes = s
|
||||
.split((n) => n.type === 'combinator')
|
||||
.pop()
|
||||
.filter((n) => n.type !== 'pseudo' || n.value.startsWith('::'))
|
||||
.join('')
|
||||
.trim()
|
||||
|
||||
return minimumImpactSelector(nodes)
|
||||
})
|
||||
})
|
||||
|
||||
@ -28,7 +57,7 @@ export default function resolveDefaultsAtRules() {
|
||||
let universals = new Set()
|
||||
|
||||
root.walkAtRules('defaults', (rule) => {
|
||||
if (rule.nodes.length > 0) {
|
||||
if (rule.nodes && rule.nodes.length > 0) {
|
||||
universals.add(rule)
|
||||
return
|
||||
}
|
||||
|
||||
@ -605,3 +605,104 @@ test('when a utility uses defaults but they do not exist', async () => {
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
test('selectors are reduced to the lowest possible specificity', async () => {
|
||||
let config = {
|
||||
mode: 'jit',
|
||||
purge: [
|
||||
{
|
||||
raw: '<div class="foo"></div>',
|
||||
},
|
||||
],
|
||||
theme: {},
|
||||
plugins: [],
|
||||
corePlugins: [],
|
||||
}
|
||||
|
||||
let css = `
|
||||
@defaults test {
|
||||
--color: black;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
.foo {
|
||||
@defaults test;
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
#app {
|
||||
@defaults test;
|
||||
border-color: var(--color);
|
||||
}
|
||||
|
||||
span#page {
|
||||
@defaults test;
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
div[data-foo="bar"]#other {
|
||||
@defaults test;
|
||||
fill: var(--color);
|
||||
}
|
||||
|
||||
div[data-bar="baz"] {
|
||||
@defaults test;
|
||||
stroke: var(--color);
|
||||
}
|
||||
|
||||
article {
|
||||
@defaults test;
|
||||
--article: var(--color);
|
||||
}
|
||||
|
||||
div[data-foo="bar"]#another::before {
|
||||
@defaults test;
|
||||
fill: var(--color);
|
||||
}
|
||||
`
|
||||
|
||||
return run(css, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(`
|
||||
.foo,
|
||||
[id="app"],
|
||||
[id="page"],
|
||||
[id="other"],
|
||||
[data-bar="baz"],
|
||||
article,
|
||||
[id="another"]::before {
|
||||
--color: black;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
.foo {
|
||||
background-color: var(--color);
|
||||
}
|
||||
|
||||
#app {
|
||||
border-color: var(--color);
|
||||
}
|
||||
|
||||
span#page {
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
div[data-foo="bar"]#other {
|
||||
fill: var(--color);
|
||||
}
|
||||
|
||||
div[data-bar="baz"] {
|
||||
stroke: var(--color);
|
||||
}
|
||||
|
||||
article {
|
||||
--article: var(--color);
|
||||
}
|
||||
|
||||
div[data-foo="bar"]#another::before {
|
||||
fill: var(--color);
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user