mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
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.
This commit is contained in:
parent
c766d7e274
commit
82589eb2c1
@ -27,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Allow negative utility names in `@utilty` ([#15573](https://github.com/tailwindlabs/tailwindcss/pull/15573))
|
||||
- Remove all `@keyframes` contributed by JavaScript plugins when using `@reference` imports ([#15581](https://github.com/tailwindlabs/tailwindcss/pull/15581))
|
||||
- _Upgrade (experimental)_: Do not extract class names from functions (e.g. `shadow` in `filter: 'drop-shadow(…)'`) ([#15566](https://github.com/tailwindlabs/tailwindcss/pull/15566))
|
||||
- _Upgrade (experimental)_: Migrate `theme(spacing.2)` to `--spacing(2)` ([#15579](https://github.com/tailwindlabs/tailwindcss/pull/15579))
|
||||
- _Upgrade (experimental)_: Migrate `theme(…)` to `--theme(…)` ([#15579](https://github.com/tailwindlabs/tailwindcss/pull/15579))
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@ -1296,10 +1296,10 @@ describe('border compatibility', () => {
|
||||
"
|
||||
--- src/index.html ---
|
||||
<div
|
||||
class="[width:calc(var(--spacing)*2)]
|
||||
[width:calc(var(--spacing)*4.5)]
|
||||
class="[width:--spacing(2)]
|
||||
[width:--spacing(4.5)]
|
||||
[width:var(--spacing-5_5)]
|
||||
[width:calc(var(--spacing)*13)]
|
||||
[width:--spacing(13)]
|
||||
[width:var(--spacing-100)]
|
||||
[width:var(--spacing-miami)]"
|
||||
></div>
|
||||
@ -1332,10 +1332,10 @@ describe('border compatibility', () => {
|
||||
}
|
||||
|
||||
.container {
|
||||
width: calc(var(--spacing) * 2);
|
||||
width: calc(var(--spacing) * 4.5);
|
||||
width: --spacing(2);
|
||||
width: --spacing(4.5);
|
||||
width: var(--spacing-5_5);
|
||||
width: calc(var(--spacing) * 13);
|
||||
width: --spacing(13);
|
||||
width: var(--spacing-100);
|
||||
width: var(--spacing-miami);
|
||||
}
|
||||
@ -1515,7 +1515,7 @@ describe('border compatibility', () => {
|
||||
@utility container {
|
||||
margin-inline: auto;
|
||||
padding-inline: 2rem;
|
||||
@media (width >= theme(--breakpoint-sm)) {
|
||||
@media (width >= --theme(--breakpoint-sm)) {
|
||||
max-width: none;
|
||||
}
|
||||
@media (width >= 48rem) {
|
||||
|
||||
@ -35,11 +35,11 @@ it('should migrate `theme(…)` to `var(…)`', async () => {
|
||||
}
|
||||
`),
|
||||
).toMatchInlineSnapshot(`
|
||||
"@media theme(--breakpoint-sm) {
|
||||
"@media --theme(--breakpoint-sm) {
|
||||
.foo {
|
||||
background-color: var(--color-red-900);
|
||||
color: theme(--color-red-900 / 75%);
|
||||
border-color: theme(--color-red-200 / 75%);
|
||||
color: --theme(--color-red-900 / 75%);
|
||||
border-color: --theme(--color-red-200 / 75%);
|
||||
}
|
||||
}"
|
||||
`)
|
||||
|
||||
@ -36,6 +36,10 @@ test.each([
|
||||
['supports-[--test]:flex', 'supports-(--test):flex'],
|
||||
['supports-[_--test]:flex', 'supports-[--test]:flex'],
|
||||
|
||||
// Custom CSS functions that look like variables should not be converted
|
||||
['w-[--spacing(5)]', 'w-[--spacing(5)]'],
|
||||
['bg-[--theme(--color-red-500)]', 'bg-[--theme(--color-red-500)]'],
|
||||
|
||||
// Some properties never had var() injection in v3.
|
||||
['[scroll-timeline-name:--myTimeline]', '[scroll-timeline-name:--myTimeline]'],
|
||||
['[timeline-scope:--myScope]', '[timeline-scope:--myScope]'],
|
||||
|
||||
@ -74,13 +74,14 @@ export function automaticVarInjection(
|
||||
|
||||
function injectVar(value: string): { value: string; didChange: boolean } {
|
||||
let didChange = false
|
||||
if (value.startsWith('--')) {
|
||||
if (value.startsWith('--') && !value.includes('(')) {
|
||||
value = `var(${value})`
|
||||
didChange = true
|
||||
} else if (value.startsWith(' --')) {
|
||||
value = value.slice(1)
|
||||
didChange = true
|
||||
}
|
||||
|
||||
return { value, didChange }
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,9 @@ test.each([
|
||||
['[color:red]', '[color:red]'],
|
||||
|
||||
// Handle special cases around `.1` in the `theme(…)`
|
||||
['[--value:theme(spacing.1)]', '[--value:calc(var(--spacing)*1)]'],
|
||||
['[--value:theme(spacing.1)]', '[--value:--spacing(1)]'],
|
||||
['[--value:theme(fontSize.xs.1.lineHeight)]', '[--value:var(--text-xs--line-height)]'],
|
||||
['[--value:theme(spacing[1.25])]', '[--value:calc(var(--spacing)*1.25)]'],
|
||||
['[--value:theme(spacing[1.25])]', '[--value:--spacing(1.25)]'],
|
||||
|
||||
// Should not convert invalid spacing values to calc
|
||||
['[--value:theme(spacing[1.1])]', '[--value:theme(spacing[1.1])]'],
|
||||
@ -20,7 +20,7 @@ test.each([
|
||||
['[color:theme(colors.red.500)]', '[color:var(--color-red-500)]'], // Arbitrary property
|
||||
['[color:theme(colors.red.500)]/50', '[color:var(--color-red-500)]/50'], // Arbitrary property + modifier
|
||||
['bg-[theme(colors.red.500)]', 'bg-(--color-red-500)'], // Arbitrary value
|
||||
['bg-[size:theme(spacing.4)]', 'bg-[size:calc(var(--spacing)*4)]'], // Arbitrary value + data type hint
|
||||
['bg-[size:theme(spacing.4)]', 'bg-[size:--spacing(4)]'], // Arbitrary value + data type hint
|
||||
|
||||
// Convert to `var(…)` if we can resolve the path, but keep fallback values
|
||||
['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'],
|
||||
@ -47,11 +47,11 @@ test.each([
|
||||
// to a candidate modifier _if_ all `theme(…)` calls use the same modifier.
|
||||
[
|
||||
'[color:theme(colors.red.500/50,theme(colors.blue.500/50))]',
|
||||
'[color:theme(--color-red-500/50,theme(--color-blue-500/50))]',
|
||||
'[color:--theme(--color-red-500/50,--theme(--color-blue-500/50))]',
|
||||
],
|
||||
[
|
||||
'[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))]/50',
|
||||
],
|
||||
|
||||
// Convert the `theme(…)`, but try to move the inline modifier (e.g. `50%`),
|
||||
@ -75,22 +75,22 @@ test.each([
|
||||
['bg-[theme(colors.red.500/12.34%)]', 'bg-(--color-red-500)/[12.34%]'],
|
||||
|
||||
// Arbitrary property that already contains a modifier
|
||||
['[color:theme(colors.red.500/50%)]/50', '[color:theme(--color-red-500/50%)]/50'],
|
||||
['[color:theme(colors.red.500/50%)]/50', '[color:--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// Values that don't contain only `theme(…)` calls should not be converted to
|
||||
// use a modifier since the color is not the whole value.
|
||||
[
|
||||
'shadow-[shadow:inset_0px_1px_theme(colors.white/15%)]',
|
||||
'shadow-[shadow:inset_0px_1px_theme(--color-white/15%)]',
|
||||
'shadow-[shadow:inset_0px_1px_--theme(--color-white/15%)]',
|
||||
],
|
||||
|
||||
// Arbitrary value, where the candidate already contains a modifier
|
||||
// This should still migrate the `theme(…)` syntax to the modern syntax.
|
||||
['bg-[theme(colors.red.500/50%)]/50', 'bg-[theme(--color-red-500/50%)]/50'],
|
||||
['bg-[theme(colors.red.500/50%)]/50', 'bg-[--theme(--color-red-500/50%)]/50'],
|
||||
|
||||
// Variants, we can't use `var(…)` especially inside of `@media(…)`. We can
|
||||
// still upgrade the `theme(…)` to the modern syntax.
|
||||
['max-[theme(screens.lg)]:flex', 'max-[theme(--breakpoint-lg)]:flex'],
|
||||
['max-[theme(screens.lg)]:flex', 'max-[--theme(--breakpoint-lg)]:flex'],
|
||||
// There are no variables for `--spacing` multiples, so we can't convert this
|
||||
['max-[theme(spacing.4)]:flex', 'max-[theme(spacing.4)]:flex'],
|
||||
|
||||
@ -100,10 +100,7 @@ test.each([
|
||||
|
||||
// `theme(…)` calls in another CSS function is replaced correctly.
|
||||
// Additionally we remove unnecessary whitespace.
|
||||
[
|
||||
'grid-cols-[min(50%_,_theme(spacing.80))_auto]',
|
||||
'grid-cols-[min(50%,calc(var(--spacing)*80))_auto]',
|
||||
],
|
||||
['grid-cols-[min(50%_,_theme(spacing.80))_auto]', 'grid-cols-[min(50%,--spacing(80))_auto]'],
|
||||
|
||||
// `theme(…)` calls valid in v3, but not in v4 should still be converted.
|
||||
['[--foo:theme(transitionDuration.500)]', '[--foo:theme(transitionDuration.500)]'],
|
||||
@ -152,7 +149,7 @@ test('extended space scale converts to var or calc', async () => {
|
||||
},
|
||||
)
|
||||
expect(themeToVar(designSystem, {}, '[--value:theme(spacing.1)]')).toEqual(
|
||||
'[--value:calc(var(--spacing)*1)]',
|
||||
'[--value:--spacing(1)]',
|
||||
)
|
||||
expect(themeToVar(designSystem, {}, '[--value:theme(spacing.2)]')).toEqual(
|
||||
'[--value:var(--spacing-2)]',
|
||||
|
||||
@ -148,9 +148,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
|
||||
let parts = segment(path, '/').map((part) => part.trim())
|
||||
|
||||
// Multiple `/` separators, which makes this an invalid path
|
||||
if (parts.length > 2) {
|
||||
return null
|
||||
}
|
||||
if (parts.length > 2) return null
|
||||
|
||||
// The path contains a `/`, which means that there is a modifier such as
|
||||
// `theme(colors.red.500/50%)`.
|
||||
@ -212,7 +210,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
|
||||
let multiplier = keyPath[1]
|
||||
if (!isValidSpacingMultiplier(multiplier)) return null
|
||||
|
||||
return 'calc(var(--spacing) * ' + multiplier + ')'
|
||||
return `--spacing(${multiplier})`
|
||||
}
|
||||
|
||||
return null
|
||||
@ -227,7 +225,9 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals
|
||||
|
||||
let modifier =
|
||||
parts.length > 0 ? (prettyPrint ? ` / ${parts.join(' / ')}` : `/${parts.join('/')}`) : ''
|
||||
return fallback ? `theme(${variable}${modifier}, ${fallback})` : `theme(${variable}${modifier})`
|
||||
return fallback
|
||||
? `--theme(${variable}${modifier}, ${fallback})`
|
||||
: `--theme(${variable}${modifier})`
|
||||
}
|
||||
|
||||
return convert
|
||||
|
||||
@ -60,7 +60,7 @@ export function buildCustomContainerUtilityRules(
|
||||
let [key] = breakpoints[0]
|
||||
// Unset all default breakpoints
|
||||
rules.push(
|
||||
atRule('@media', `(width >= theme(--breakpoint-${key}))`, [decl('max-width', 'none')]),
|
||||
atRule('@media', `(width >= --theme(--breakpoint-${key}))`, [decl('max-width', 'none')]),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user