Skip to content

Commit 82589eb

Browse files
authored
Migrate theme(…) to --theme(…), migrate calc(var(--spacing)*x) to --spacing(x) (#15579)
This PR improves the codemod tool to simplify 2 things: 1. Whenever you have a `theme(…)` call, we try to change it to a `var(…)`, but if that doesn't work for some reason, we will make sure to at least convert it to the more modern `--theme(…)`. 2. When converting `theme(spacing.2)`, we used to convert it to `calc(var(--spacing)*2)`, but now we will convert it to `--spacing(2)` instead.
1 parent c766d7e commit 82589eb

File tree

8 files changed

+35
-31
lines changed

8 files changed

+35
-31
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2727
- Allow negative utility names in `@utilty` ([#15573](https://github.com/tailwindlabs/tailwindcss/pull/15573))
2828
- Remove all `@keyframes` contributed by JavaScript plugins when using `@reference` imports ([#15581](https://github.com/tailwindlabs/tailwindcss/pull/15581))
2929
- _Upgrade (experimental)_: Do not extract class names from functions (e.g. `shadow` in `filter: 'drop-shadow(…)'`) ([#15566](https://github.com/tailwindlabs/tailwindcss/pull/15566))
30+
- _Upgrade (experimental)_: Migrate `theme(spacing.2)` to `--spacing(2)` ([#15579](https://github.com/tailwindlabs/tailwindcss/pull/15579))
31+
- _Upgrade (experimental)_: Migrate `theme(…)` to `--theme(…)` ([#15579](https://github.com/tailwindlabs/tailwindcss/pull/15579))
3032

3133
### Changed
3234

integrations/upgrade/js-config.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,10 +1296,10 @@ describe('border compatibility', () => {
12961296
"
12971297
--- src/index.html ---
12981298
<div
1299-
class="[width:calc(var(--spacing)*2)]
1300-
[width:calc(var(--spacing)*4.5)]
1299+
class="[width:--spacing(2)]
1300+
[width:--spacing(4.5)]
13011301
[width:var(--spacing-5_5)]
1302-
[width:calc(var(--spacing)*13)]
1302+
[width:--spacing(13)]
13031303
[width:var(--spacing-100)]
13041304
[width:var(--spacing-miami)]"
13051305
></div>
@@ -1332,10 +1332,10 @@ describe('border compatibility', () => {
13321332
}
13331333
13341334
.container {
1335-
width: calc(var(--spacing) * 2);
1336-
width: calc(var(--spacing) * 4.5);
1335+
width: --spacing(2);
1336+
width: --spacing(4.5);
13371337
width: var(--spacing-5_5);
1338-
width: calc(var(--spacing) * 13);
1338+
width: --spacing(13);
13391339
width: var(--spacing-100);
13401340
width: var(--spacing-miami);
13411341
}
@@ -1515,7 +1515,7 @@ describe('border compatibility', () => {
15151515
@utility container {
15161516
margin-inline: auto;
15171517
padding-inline: 2rem;
1518-
@media (width >= theme(--breakpoint-sm)) {
1518+
@media (width >= --theme(--breakpoint-sm)) {
15191519
max-width: none;
15201520
}
15211521
@media (width >= 48rem) {

packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ it('should migrate `theme(…)` to `var(…)`', async () => {
3535
}
3636
`),
3737
).toMatchInlineSnapshot(`
38-
"@media theme(--breakpoint-sm) {
38+
"@media --theme(--breakpoint-sm) {
3939
.foo {
4040
background-color: var(--color-red-900);
41-
color: theme(--color-red-900 / 75%);
42-
border-color: theme(--color-red-200 / 75%);
41+
color: --theme(--color-red-900 / 75%);
42+
border-color: --theme(--color-red-200 / 75%);
4343
}
4444
}"
4545
`)

packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ test.each([
3636
['supports-[--test]:flex', 'supports-(--test):flex'],
3737
['supports-[_--test]:flex', 'supports-[--test]:flex'],
3838

39+
// Custom CSS functions that look like variables should not be converted
40+
['w-[--spacing(5)]', 'w-[--spacing(5)]'],
41+
['bg-[--theme(--color-red-500)]', 'bg-[--theme(--color-red-500)]'],
42+
3943
// Some properties never had var() injection in v3.
4044
['[scroll-timeline-name:--myTimeline]', '[scroll-timeline-name:--myTimeline]'],
4145
['[timeline-scope:--myScope]', '[timeline-scope:--myScope]'],

packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,13 +74,14 @@ export function automaticVarInjection(
7474

7575
function injectVar(value: string): { value: string; didChange: boolean } {
7676
let didChange = false
77-
if (value.startsWith('--')) {
77+
if (value.startsWith('--') && !value.includes('(')) {
7878
value = `var(${value})`
7979
didChange = true
8080
} else if (value.startsWith(' --')) {
8181
value = value.slice(1)
8282
didChange = true
8383
}
84+
8485
return { value, didChange }
8586
}
8687

packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ test.each([
99
['[color:red]', '[color:red]'],
1010

1111
// Handle special cases around `.1` in the `theme(…)`
12-
['[--value:theme(spacing.1)]', '[--value:calc(var(--spacing)*1)]'],
12+
['[--value:theme(spacing.1)]', '[--value:--spacing(1)]'],
1313
['[--value:theme(fontSize.xs.1.lineHeight)]', '[--value:var(--text-xs--line-height)]'],
14-
['[--value:theme(spacing[1.25])]', '[--value:calc(var(--spacing)*1.25)]'],
14+
['[--value:theme(spacing[1.25])]', '[--value:--spacing(1.25)]'],
1515

1616
// Should not convert invalid spacing values to calc
1717
['[--value:theme(spacing[1.1])]', '[--value:theme(spacing[1.1])]'],
@@ -20,7 +20,7 @@ test.each([
2020
['[color:theme(colors.red.500)]', '[color:var(--color-red-500)]'], // Arbitrary property
2121
['[color:theme(colors.red.500)]/50', '[color:var(--color-red-500)]/50'], // Arbitrary property + modifier
2222
['bg-[theme(colors.red.500)]', 'bg-(--color-red-500)'], // Arbitrary value
23-
['bg-[size:theme(spacing.4)]', 'bg-[size:calc(var(--spacing)*4)]'], // Arbitrary value + data type hint
23+
['bg-[size:theme(spacing.4)]', 'bg-[size:--spacing(4)]'], // Arbitrary value + data type hint
2424

2525
// Convert to `var(…)` if we can resolve the path, but keep fallback values
2626
['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'],
@@ -47,11 +47,11 @@ test.each([
4747
// to a candidate modifier _if_ all `theme(…)` calls use the same modifier.
4848
[
4949
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]',
50-
'[color:theme(--color-red-500/50,theme(--color-blue-500/50))]',
50+
'[color:--theme(--color-red-500/50,--theme(--color-blue-500/50))]',
5151
],
5252
[
5353
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]/50',
54-
'[color:theme(--color-red-500/50,theme(--color-blue-500/50))]/50',
54+
'[color:--theme(--color-red-500/50,--theme(--color-blue-500/50))]/50',
5555
],
5656

5757
// Convert the `theme(…)`, but try to move the inline modifier (e.g. `50%`),
@@ -75,22 +75,22 @@ test.each([
7575
['bg-[theme(colors.red.500/12.34%)]', 'bg-(--color-red-500)/[12.34%]'],
7676

7777
// Arbitrary property that already contains a modifier
78-
['[color:theme(colors.red.500/50%)]/50', '[color:theme(--color-red-500/50%)]/50'],
78+
['[color:theme(colors.red.500/50%)]/50', '[color:--theme(--color-red-500/50%)]/50'],
7979

8080
// Values that don't contain only `theme(…)` calls should not be converted to
8181
// use a modifier since the color is not the whole value.
8282
[
8383
'shadow-[shadow:inset_0px_1px_theme(colors.white/15%)]',
84-
'shadow-[shadow:inset_0px_1px_theme(--color-white/15%)]',
84+
'shadow-[shadow:inset_0px_1px_--theme(--color-white/15%)]',
8585
],
8686

8787
// Arbitrary value, where the candidate already contains a modifier
8888
// This should still migrate the `theme(…)` syntax to the modern syntax.
89-
['bg-[theme(colors.red.500/50%)]/50', 'bg-[theme(--color-red-500/50%)]/50'],
89+
['bg-[theme(colors.red.500/50%)]/50', 'bg-[--theme(--color-red-500/50%)]/50'],
9090

9191
// Variants, we can't use `var(…)` especially inside of `@media(…)`. We can
9292
// still upgrade the `theme(…)` to the modern syntax.
93-
['max-[theme(screens.lg)]:flex', 'max-[theme(--breakpoint-lg)]:flex'],
93+
['max-[theme(screens.lg)]:flex', 'max-[--theme(--breakpoint-lg)]:flex'],
9494
// There are no variables for `--spacing` multiples, so we can't convert this
9595
['max-[theme(spacing.4)]:flex', 'max-[theme(spacing.4)]:flex'],
9696

@@ -100,10 +100,7 @@ test.each([
100100

101101
// `theme(…)` calls in another CSS function is replaced correctly.
102102
// Additionally we remove unnecessary whitespace.
103-
[
104-
'grid-cols-[min(50%_,_theme(spacing.80))_auto]',
105-
'grid-cols-[min(50%,calc(var(--spacing)*80))_auto]',
106-
],
103+
['grid-cols-[min(50%_,_theme(spacing.80))_auto]', 'grid-cols-[min(50%,--spacing(80))_auto]'],
107104

108105
// `theme(…)` calls valid in v3, but not in v4 should still be converted.
109106
['[--foo:theme(transitionDuration.500)]', '[--foo:theme(transitionDuration.500)]'],
@@ -152,7 +149,7 @@ test('extended space scale converts to var or calc', async () => {
152149
},
153150
)
154151
expect(themeToVar(designSystem, {}, '[--value:theme(spacing.1)]')).toEqual(
155-
'[--value:calc(var(--spacing)*1)]',
152+
'[--value:--spacing(1)]',
156153
)
157154
expect(themeToVar(designSystem, {}, '[--value:theme(spacing.2)]')).toEqual(
158155
'[--value:var(--spacing-2)]',

packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
148148
let parts = segment(path, '/').map((part) => part.trim())
149149

150150
// Multiple `/` separators, which makes this an invalid path
151-
if (parts.length > 2) {
152-
return null
153-
}
151+
if (parts.length > 2) return null
154152

155153
// The path contains a `/`, which means that there is a modifier such as
156154
// `theme(colors.red.500/50%)`.
@@ -212,7 +210,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
212210
let multiplier = keyPath[1]
213211
if (!isValidSpacingMultiplier(multiplier)) return null
214212

215-
return 'calc(var(--spacing) * ' + multiplier + ')'
213+
return `--spacing(${multiplier})`
216214
}
217215

218216
return null
@@ -227,7 +225,9 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
227225

228226
let modifier =
229227
parts.length > 0 ? (prettyPrint ? ` / ${parts.join(' / ')}` : `/${parts.join('/')}`) : ''
230-
return fallback ? `theme(${variable}${modifier}, ${fallback})` : `theme(${variable}${modifier})`
228+
return fallback
229+
? `--theme(${variable}${modifier}, ${fallback})`
230+
: `--theme(${variable}${modifier})`
231231
}
232232

233233
return convert

packages/tailwindcss/src/compat/container.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function buildCustomContainerUtilityRules(
6060
let [key] = breakpoints[0]
6161
// Unset all default breakpoints
6262
rules.push(
63-
atRule('@media', `(width >= theme(--breakpoint-${key}))`, [decl('max-width', 'none')]),
63+
atRule('@media', `(width >= --theme(--breakpoint-${key}))`, [decl('max-width', 'none')]),
6464
)
6565
}
6666

0 commit comments

Comments
 (0)