mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
Fixes #17924 When an `@apply` pointed to utility that nested usages of `@apply`, these nested usages were not properly carried through the dependency chain. This was because we were only tracking dependencies on the immediate parent rather than all parents. To fix this, this PR: - Modifies the dependency resolution to track dependencies through the entire parent path - Uses a `walk(…)` for the node replacement logic so that all nested `@apply` usages are also resolved (as these are now tracked in the dependency list anyways ## Test Plan - Added a regression test for #17924 to the unit tests and ensure existing tests don't break
This commit is contained in:
parent
179e5ddd7c
commit
17ca56d386
@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Fix incorrectly replacing `_` with ` ` in arbitrary modifier shorthand `bg-red-500/(--my_opacity)` ([#17889](https://github.com/tailwindlabs/tailwindcss/pull/17889))
|
||||
- Upgrade: Bump dependencies in parallel and make the upgrade faster ([#17898](https://github.com/tailwindlabs/tailwindcss/pull/17898))
|
||||
- Don't scan `.log` files for classes by default ([#17906](https://github.com/tailwindlabs/tailwindcss/pull/17906))
|
||||
- Ensure that custom utilities applying other custom utilities don't swallow nested `@apply` rules ([#17925](https://github.com/tailwindlabs/tailwindcss/pull/17925))
|
||||
|
||||
## [4.1.5] - 2025-04-30
|
||||
|
||||
|
||||
@ -23,7 +23,7 @@ export function substituteAtApply(ast: AstNode[], designSystem: DesignSystem) {
|
||||
let definitions = new DefaultMap(() => new Set<AstNode>())
|
||||
|
||||
// Collect all new `@utility` definitions and all `@apply` rules first
|
||||
walk([root], (node, { parent }) => {
|
||||
walk([root], (node, { parent, path }) => {
|
||||
if (node.kind !== 'at-rule') return
|
||||
|
||||
// Do not allow `@apply` rules inside `@keyframes` rules.
|
||||
@ -66,7 +66,12 @@ export function substituteAtApply(ast: AstNode[], designSystem: DesignSystem) {
|
||||
parents.add(parent)
|
||||
|
||||
for (let dependency of resolveApplyDependencies(node, designSystem)) {
|
||||
dependencies.get(parent).add(dependency)
|
||||
// Mark every parent in the path as having a dependency to that utility.
|
||||
for (let parent of path) {
|
||||
if (parent === node) continue
|
||||
if (!parents.has(parent)) continue
|
||||
dependencies.get(parent).add(dependency)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -151,11 +156,10 @@ export function substituteAtApply(ast: AstNode[], designSystem: DesignSystem) {
|
||||
for (let parent of sorted) {
|
||||
if (!('nodes' in parent)) continue
|
||||
|
||||
for (let i = 0; i < parent.nodes.length; i++) {
|
||||
let node = parent.nodes[i]
|
||||
if (node.kind !== 'at-rule' || node.name !== '@apply') continue
|
||||
walk(parent.nodes, (child, { replaceWith }) => {
|
||||
if (child.kind !== 'at-rule' || child.name !== '@apply') return
|
||||
|
||||
let candidates = node.params.split(/\s+/g)
|
||||
let candidates = child.params.split(/\s+/g)
|
||||
|
||||
// Replace the `@apply` rule with the actual utility classes
|
||||
{
|
||||
@ -181,10 +185,11 @@ export function substituteAtApply(ast: AstNode[], designSystem: DesignSystem) {
|
||||
}
|
||||
}
|
||||
|
||||
parent.nodes.splice(i, 1, ...newNodes)
|
||||
replaceWith(newNodes)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return features
|
||||
}
|
||||
|
||||
|
||||
@ -612,6 +612,84 @@ describe('@apply', () => {
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
// https://github.com/tailwindlabs/tailwindcss/issues/17924
|
||||
it('should correctly apply nested usages of @apply when one @utility applies another', async () => {
|
||||
expect(
|
||||
await compileCss(
|
||||
css`
|
||||
@theme {
|
||||
--color-green-500: green;
|
||||
--color-red-500: red;
|
||||
--color-indigo-500: indigo;
|
||||
}
|
||||
|
||||
@tailwind utilities;
|
||||
|
||||
@utility test2 {
|
||||
@apply test;
|
||||
}
|
||||
|
||||
@utility test {
|
||||
@apply bg-green-500;
|
||||
&:hover {
|
||||
@apply bg-red-500;
|
||||
}
|
||||
&:disabled {
|
||||
@apply bg-indigo-500;
|
||||
}
|
||||
}
|
||||
|
||||
.foo {
|
||||
@apply test2;
|
||||
}
|
||||
`,
|
||||
['foo', 'test', 'test2'],
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
":root, :host {
|
||||
--color-green-500: green;
|
||||
--color-red-500: red;
|
||||
--color-indigo-500: indigo;
|
||||
}
|
||||
|
||||
.test {
|
||||
background-color: var(--color-green-500);
|
||||
}
|
||||
|
||||
.test:hover {
|
||||
background-color: var(--color-red-500);
|
||||
}
|
||||
|
||||
.test:disabled {
|
||||
background-color: var(--color-indigo-500);
|
||||
}
|
||||
|
||||
.test2 {
|
||||
background-color: var(--color-green-500);
|
||||
}
|
||||
|
||||
.test2:hover {
|
||||
background-color: var(--color-red-500);
|
||||
}
|
||||
|
||||
.test2:disabled {
|
||||
background-color: var(--color-indigo-500);
|
||||
}
|
||||
|
||||
.foo {
|
||||
background-color: var(--color-green-500);
|
||||
}
|
||||
|
||||
.foo:hover {
|
||||
background-color: var(--color-red-500);
|
||||
}
|
||||
|
||||
.foo:disabled {
|
||||
background-color: var(--color-indigo-500);
|
||||
}"
|
||||
`)
|
||||
})
|
||||
})
|
||||
|
||||
describe('arbitrary variants', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user