diff --git a/CHANGELOG.md b/CHANGELOG.md index 21c1bef88..3404eea0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/integrations/upgrade/js-config.test.ts b/integrations/upgrade/js-config.test.ts index e9ad772f6..56c77189c 100644 --- a/integrations/upgrade/js-config.test.ts +++ b/integrations/upgrade/js-config.test.ts @@ -1296,10 +1296,10 @@ describe('border compatibility', () => { " --- src/index.html ---
@@ -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) { diff --git a/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts index ce3940bc9..f0b4844ad 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts @@ -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%); } }" `) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts index d9e714e9e..59b1523b7 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts @@ -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]'], diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts index 33995c04a..643d000c6 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts @@ -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 } } diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts index f5f2a41db..2ff074010 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts @@ -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)]', diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts index b83e5add1..128b5e8b8 100644 --- a/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts @@ -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 diff --git a/packages/tailwindcss/src/compat/container.ts b/packages/tailwindcss/src/compat/container.ts index 99aea1e42..3cf72c4db 100644 --- a/packages/tailwindcss/src/compat/container.ts +++ b/packages/tailwindcss/src/compat/container.ts @@ -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')]), ) }