Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- _Upgrade (experimental)_: Migrate v3 PostCSS setups to v4 in some cases ([#14612](https://github.com/tailwindlabs/tailwindcss/pull/14612))
- _Upgrade (experimental)_: Automatically discover JavaScript config files ([#14597](https://github.com/tailwindlabs/tailwindcss/pull/14597))
- _Upgrade (experimental)_: Migrate legacy classes to the v4 alternative ([#14643](https://github.com/tailwindlabs/tailwindcss/pull/14643))
- _Upgrade (experimental)_: Migrate static JS configurations to CSS ([#14639](https://github.com/tailwindlabs/tailwindcss/pull/14639), [#14650](https://github.com/tailwindlabs/tailwindcss/pull/14650), [#14648](https://github.com/tailwindlabs/tailwindcss/pull/14648))
- _Upgrade (experimental)_: Migrate static JS configurations to CSS ([#14639](https://github.com/tailwindlabs/tailwindcss/pull/14639), [#14650](https://github.com/tailwindlabs/tailwindcss/pull/14650), [#14648](https://github.com/tailwindlabs/tailwindcss/pull/14648), [#14666](https://github.com/tailwindlabs/tailwindcss/pull/14666))
- _Upgrade (experimental)_: Migrate `@media screen(…)` when running codemods ([#14603](https://github.com/tailwindlabs/tailwindcss/pull/14603))
- _Upgrade (experimental)_: Inject `@config "…"` when a `tailwind.config.{js,ts,…}` is detected ([#14635](https://github.com/tailwindlabs/tailwindcss/pull/14635))
- _Upgrade (experimental)_: Migrate `aria-*`, `data-*`, and `supports-*` variants from arbitrary values to bare values ([#14644](https://github.com/tailwindlabs/tailwindcss/pull/14644))
Expand Down
37 changes: 36 additions & 1 deletion integrations/upgrade/js-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ test(
borderRadius: {
'4xl': '2rem',
},
keyframes: {
'spin-clockwise': {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(360deg)' },
},
'spin-counterclockwise': {
'0%': { transform: 'rotate(0deg)' },
'100%': { transform: 'rotate(-360deg)' },
},
},
animation: {
'spin-clockwise': 'spin-clockwise 1s linear infinite',
'spin-counterclockwise': 'spin-counterclockwise 1s linear infinite',
},
},
},
plugins: [],
Expand Down Expand Up @@ -91,9 +105,30 @@ test(
--font-size-base--line-height: 2rem;

--font-family-sans: Inter, system-ui, sans-serif;
--font-family-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--font-family-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";

--radius-4xl: 2rem;

--animate-spin-clockwise: spin-clockwise 1s linear infinite;
--animate-spin-counterclockwise: spin-counterclockwise 1s linear infinite;

@keyframes spin-clockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes spin-counterclockwise {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(-360deg);
}
}
}
"
`)
Expand Down
5 changes: 4 additions & 1 deletion packages/@tailwindcss-upgrade/src/codemods/migrate-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ export function migrateConfig(
if (!sheet.file) return

let cssConfig = new AtRule()
cssConfig.raws.tailwind_pretty = true

if (jsConfigMigration === null) {
// Skip if there is already a `@config` directive
Expand Down Expand Up @@ -85,6 +84,10 @@ export function migrateConfig(
return WalkAction.Skip
})

for (let node of cssConfig?.nodes ?? []) {
node.raws.tailwind_pretty = true
}

if (!locationNode) {
root.prepend(cssConfig.nodes)
} else if (locationNode.name === 'import') {
Expand Down
23 changes: 22 additions & 1 deletion packages/@tailwindcss-upgrade/src/migrate-js-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import type { Config } from 'tailwindcss'
import defaultTheme from 'tailwindcss/defaultTheme'
import { fileURLToPath } from 'url'
import { loadModule } from '../../@tailwindcss-node/src/compile'
import { toCss, type AstNode } from '../../tailwindcss/src/ast'
import {
keyPathToCssProperty,
themeableValues,
} from '../../tailwindcss/src/compat/apply-config-to-theme'
import { applyKeyframesToAst } from '../../tailwindcss/src/compat/apply-keyframes-to-ast'
import { deepMerge } from '../../tailwindcss/src/compat/config/deep-merge'
import { mergeThemeExtension } from '../../tailwindcss/src/compat/config/resolve-config'
import type { ThemeConfig } from '../../tailwindcss/src/compat/config/types'
Expand Down Expand Up @@ -89,7 +91,11 @@ async function migrateTheme(unresolvedConfig: Config & { theme: any }): Promise<
}
}

let themeValues = deepMerge({}, [overwriteTheme, extendTheme], mergeThemeExtension)
let themeValues: Record<string, Record<string, unknown>> = deepMerge(
{},
[overwriteTheme, extendTheme],
mergeThemeExtension,
)

let prevSectionKey = ''

Expand All @@ -99,6 +105,10 @@ async function migrateTheme(unresolvedConfig: Config & { theme: any }): Promise<
if (typeof value !== 'string' && typeof value !== 'number') {
continue
}

if (key[0] === 'keyframes') {
continue
}
containsThemeKeys = true

let sectionKey = createSectionKey(key)
Expand All @@ -115,6 +125,11 @@ async function migrateTheme(unresolvedConfig: Config & { theme: any }): Promise<
css += ` --${keyPathToCssProperty(key)}: ${value};\n`
}

if ('keyframes' in themeValues) {
containsThemeKeys = true
css += '\n' + keyframesToCss(themeValues.keyframes)
}

if (!containsThemeKeys) {
return null
}
Expand Down Expand Up @@ -232,3 +247,9 @@ function onlyUsesAllowedTopLevelKeys(theme: ThemeConfig): boolean {
}
return true
}

function keyframesToCss(keyframes: Record<string, unknown>): string {
let ast: AstNode[] = []
applyKeyframesToAst(ast, { theme: { keyframes } })
return toCss(ast).trim() + '\n'
Comment on lines +252 to +254
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a sneaky way of handling this. I love it!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for real this is a pretty sweet way of doing it 💯

}
2 changes: 1 addition & 1 deletion packages/tailwindcss/src/compat/apply-keyframes-to-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { rule, type AstNode } from '../ast'
import type { ResolvedConfig } from './config/types'
import { objectToAst } from './plugin-api'

export function applyKeyframesToAst(ast: AstNode[], { theme }: ResolvedConfig) {
export function applyKeyframesToAst(ast: AstNode[], { theme }: Pick<ResolvedConfig, 'theme'>) {
if ('keyframes' in theme) {
for (let [name, keyframe] of Object.entries(theme.keyframes)) {
ast.push(rule(`@keyframes ${name}`, objectToAst(keyframe as any)))
Expand Down