mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Fix generation of div:not(.foo) if .foo is never defined (#7815)
* fix little typo * ensure that `div:not(.unknown-class)` gets generated * update changelog
This commit is contained in:
parent
7b4cc36f5e
commit
48728ed5d3
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Correctly parse and prefix animation names with dots ([#7163](https://github.com/tailwindlabs/tailwindcss/pull/7163))
|
||||
- Fix extraction from template literal/function with array ([#7481](https://github.com/tailwindlabs/tailwindcss/pull/7481))
|
||||
- Don't output unparsable arbitrary values ([#7789](https://github.com/tailwindlabs/tailwindcss/pull/7789))
|
||||
- Fix generation of `div:not(.foo)` if `.foo` is never defined ([#7815](https://github.com/tailwindlabs/tailwindcss/pull/7815))
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@ -85,12 +85,18 @@ function parseStyles(styles) {
|
||||
})
|
||||
}
|
||||
|
||||
function getClasses(selector) {
|
||||
function getClasses(selector, mutate) {
|
||||
let parser = selectorParser((selectors) => {
|
||||
let allClasses = []
|
||||
|
||||
if (mutate) {
|
||||
mutate(selectors)
|
||||
}
|
||||
|
||||
selectors.walkClasses((classNode) => {
|
||||
allClasses.push(classNode.value)
|
||||
})
|
||||
|
||||
return allClasses
|
||||
})
|
||||
return parser.transformSync(selector)
|
||||
@ -101,8 +107,20 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
||||
|
||||
// Handle normal rules
|
||||
if (node.type === 'rule') {
|
||||
// Ignore everything inside a :not(...). This allows you to write code like
|
||||
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to
|
||||
// not generated it. But now we will ignore everything inside a `:not`, so
|
||||
// that it still gets generated.
|
||||
function ignoreNot(selectors) {
|
||||
selectors.walkPseudos((pseudo) => {
|
||||
if (pseudo.value === ':not') {
|
||||
pseudo.remove()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for (let selector of node.selectors) {
|
||||
let classCandidates = getClasses(selector)
|
||||
let classCandidates = getClasses(selector, ignoreNot)
|
||||
// At least one of the selectors contains non-"on-demandable" candidates.
|
||||
if (classCandidates.length === 0) {
|
||||
state.containsNonOnDemandable = true
|
||||
@ -117,9 +135,7 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
|
||||
// Handle at-rules (which contains nested rules)
|
||||
else if (node.type === 'atrule') {
|
||||
node.walkRules((rule) => {
|
||||
for (let classCandidate of rule.selectors.flatMap((selector) =>
|
||||
getClasses(selector, state, depth + 1)
|
||||
)) {
|
||||
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
|
||||
classes.push(classCandidate)
|
||||
}
|
||||
})
|
||||
|
||||
@ -349,7 +349,7 @@ it('does not produce duplicate output when seeing variants preceding a wildcard
|
||||
})
|
||||
})
|
||||
|
||||
it('it can parse box shadows with variables', () => {
|
||||
it('can parse box shadows with variables', () => {
|
||||
let config = {
|
||||
content: [{ raw: html`<div class="shadow-lg"></div>` }],
|
||||
theme: {
|
||||
@ -376,3 +376,28 @@ it('it can parse box shadows with variables', () => {
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => {
|
||||
let config = {
|
||||
content: [{ raw: html`<div></div>` }],
|
||||
corePlugins: { preflight: false },
|
||||
}
|
||||
|
||||
let input = css`
|
||||
@tailwind components;
|
||||
|
||||
@layer components {
|
||||
div:not(.unknown-class) {
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return run(input, config).then((result) => {
|
||||
expect(result.css).toMatchFormattedCss(css`
|
||||
div:not(.unknown-class) {
|
||||
color: red;
|
||||
}
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user