From 9a25403566895503eaa60d15d7fa23c9f28ed2f1 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Mon, 24 Mar 2025 12:05:48 +0100 Subject: [PATCH] Extract keyframe name when followed by comma --- CHANGELOG.md | 1 + packages/tailwindcss/src/ast.ts | 12 ++++--- packages/tailwindcss/src/index.test.ts | 43 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a275a0134562..073ea8ed9ebd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Vite: Ensure that updates to an imported CSS file are properly propagated after updating templates ([#17347](https://github.com/tailwindlabs/tailwindcss/pull/17347)) - Fix class extraction followed by `(` in Pug ([#17320](https://github.com/tailwindlabs/tailwindcss/pull/17320)) +- Ensure `@keyframes` for theme animations are emitted if they are referenced following a comma ### [4.0.15] - 2025-03-20 diff --git a/packages/tailwindcss/src/ast.ts b/packages/tailwindcss/src/ast.ts index 83674d1148e9..e13e19743209 100644 --- a/packages/tailwindcss/src/ast.ts +++ b/packages/tailwindcss/src/ast.ts @@ -310,8 +310,8 @@ export function optimizeAst(ast: AstNode[], designSystem: DesignSystem) { // Track used animation names if (node.property === 'animation') { - let parts = node.value.split(/\s+/) - for (let part of parts) usedKeyframeNames.add(part) + for (let keyframeName of extractKeyframeNames(node.value)) + usedKeyframeNames.add(keyframeName) } parent.push(node) @@ -438,8 +438,8 @@ export function optimizeAst(ast: AstNode[], designSystem: DesignSystem) { ) if (variableUsed) { if (declaration.property.startsWith(designSystem.theme.prefixKey('--animate-'))) { - let parts = declaration.value!.split(/\s+/) - for (let part of parts) usedKeyframeNames.add(part) + for (let keyframeName of extractKeyframeNames(declaration.value!)) + usedKeyframeNames.add(keyframeName) } continue @@ -605,3 +605,7 @@ function isVariableUsed( return false } + +function extractKeyframeNames(value: string): string[] { + return value.split(/[\s,]+/) +} diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index ce3dd9d47182..25d30f2ea670 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -1939,6 +1939,49 @@ describe('Parsing theme values from CSS', () => { `) }) + // https://github.com/tailwindlabs/tailwindcss/issues/17332 + test('extracts keyframe names followed by comma', async () => { + expect( + await compileCss( + css` + @theme { + --animate-test: 500ms both fade-in, 1000ms linear 500ms spin infinite; + + @keyframes fade-in { + from { + opacity: 0%; + } + to { + opacity: 100%; + } + } + } + + @tailwind utilities; + `, + ['animate-test'], + ), + ).toMatchInlineSnapshot(` + ":root, :host { + --animate-test: .5s both fade-in, 1s linear .5s spin infinite; + } + + .animate-test { + animation: var(--animate-test); + } + + @keyframes fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } + }" + `) + }) + test('keyframes outside of `@theme are always preserved', async () => { expect( await compileCss(