diff --git a/packages/tailwindcss/src/ast.ts b/packages/tailwindcss/src/ast.ts index 36194d9f4..5a23f4e48 100644 --- a/packages/tailwindcss/src/ast.ts +++ b/packages/tailwindcss/src/ast.ts @@ -286,7 +286,9 @@ export function optimizeAst( // Track variables defined in `@theme` if (context.theme && node.property[0] === '-' && node.property[1] === '-') { - cssThemeVariables.get(parent).add(node) + if (!context.keyframes) { + cssThemeVariables.get(parent).add(node) + } } // Track used CSS variables @@ -354,6 +356,10 @@ export function optimizeAst( // AtRule else if (node.kind === 'at-rule') { + if (node.name === '@keyframes') { + context = { ...context, keyframes: true } + } + let copy = { ...node, nodes: [] } for (let child of node.nodes) { transform(child, copy.nodes, context, depth + 1) diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index 67b6c3c53..d5b71c6b6 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -1613,6 +1613,44 @@ describe('Parsing theme values from CSS', () => { `) }) + // https://github.com/tailwindlabs/tailwindcss/issues/16374 + test('custom properties in keyframes preserved', async () => { + expect( + await compileCss( + css` + @theme { + --animate-foo: used 1s infinite; + + @keyframes used { + to { + --other: var(--angle); + --angle: 360deg; + } + } + } + + @tailwind utilities; + `, + ['animate-foo'], + ), + ).toMatchInlineSnapshot(` + ":root, :host { + --animate-foo: used 1s infinite; + } + + .animate-foo { + animation: var(--animate-foo); + } + + @keyframes used { + to { + --other: var(--angle); + --angle: 360deg; + } + }" + `) + }) + test('keyframes are generated when used in an animation using `@theme inline`', async () => { expect( await compileCss(