Convert to/from v3 theme keys in configs and plugins (#14642)

A few theme keys have changed in v4 relative to v3:
- `screens` -> `--breakpoint-*`
- `colors` -> `--color-*`
- `animation` -> `--animate-*`
- `borderRadius` -> `--radius-*`
- `boxShadow` -> `--shadow-*`

When using the `theme()` function we wouldn't pick up values from the
CSS for some of these. Likewise, when loading a v3 config not all of
these would be pushed back into the CSS theme and they should've been.

This PR addresses both of these problems.
This commit is contained in:
Jordan Pittman 2024-10-11 10:24:53 -04:00 • committed by GitHub
parent 88b52b66e5
commit d9fe39c30a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 127 additions and 4 deletions

View file

@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Ensure custom variants using the JS API have access to modifiers ([#14637](https://github.com/tailwindlabs/tailwindcss/pull/14637))
- Ensure auto complete suggestions work when using `matchUtilities` ([#14589](https://github.com/tailwindlabs/tailwindcss/pull/14589))
- Pass options when using `addComponents` and `matchComponents` ([#14590](https://github.com/tailwindlabs/tailwindcss/pull/14590))
- Convert to/from v3 theme keys in configs and plugins ([#14642](https://github.com/tailwindlabs/tailwindcss/pull/14642))
- _Upgrade (experimental)_: Ensure CSS before a layer stays unlayered when running codemods ([#14596](https://github.com/tailwindlabs/tailwindcss/pull/14596))
- _Upgrade (experimental)_: Resolve issues where some prefixed candidates were not properly migrated ([#14600](https://github.com/tailwindlabs/tailwindcss/pull/14600))

View file

@ -74,8 +74,8 @@ test(
@variant dark (&:where(.dark, .dark *));
@theme {
--box-shadow-*: initial;
--box-shadow-sm: 0 2px 6px rgb(15 23 42 / 0.08);
--shadow-*: initial;
--shadow-sm: 0 2px 6px rgb(15 23 42 / 0.08);
--color-*: initial;
--color-red-400: #f87171;

View file

@ -19,6 +19,22 @@ test('Config values can be merged into the theme', () => {
},
},
screens: {
sm: '1234px',
},
boxShadow: {
normal: '0 1px 3px black',
},
borderRadius: {
sm: '0.33rem',
},
animation: {
blink: 'blink 1s linear infinite',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['Potato Mono', { fontVariationSettings: '"XHGT" 0.7' }],
@ -41,6 +57,10 @@ test('Config values can be merged into the theme', () => {
applyConfigToTheme(design, resolvedUserConfig)
expect(theme.resolve('primary', ['--color'])).toEqual('#c0ffee')
expect(theme.resolve('sm', ['--breakpoint'])).toEqual('1234px')
expect(theme.resolve('normal', ['--shadow'])).toEqual('0 1px 3px black')
expect(theme.resolve('sm', ['--radius'])).toEqual('0.33rem')
expect(theme.resolve('blink', ['--animate'])).toEqual('blink 1s linear infinite')
expect(theme.resolve('red-500', ['--color'])).toEqual('red')
expect(theme.resolve('sans', ['--font-family'])).toEqual('Inter, system-ui, sans-serif')
expect(theme.resolveWith('mono', ['--font-family'], ['--font-variation-settings'])).toEqual([

View file

@ -114,6 +114,8 @@ export function keyPathToCssProperty(path: string[]) {
if (path[0] === 'colors') path[0] = 'color'
if (path[0] === 'screens') path[0] = 'breakpoint'
if (path[0] === 'borderRadius') path[0] = 'radius'
if (path[0] === 'boxShadow') path[0] = 'shadow'
if (path[0] === 'animation') path[0] = 'animate'
return (
path

View file

@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest'
import { describe, expect, test, vi } from 'vitest'
import { compile, type Config } from '..'
import plugin from '../plugin'
import { default as plugin } from '../plugin'
import { flattenColorPalette } from './flatten-color-palette'
const css = String.raw
@ -1512,3 +1512,82 @@ test('blocklisted canddiates cannot be used with `@apply`', async () => {
`[Error: Cannot apply unknown utility class: bg-white]`,
)
})
test('old theme values are merged with their renamed counterparts in the CSS theme', async () => {
let didCallPluginFn = vi.fn()
await compile(
css`
@theme reference {
--breakpoint-a: 1;
--breakpoint-b: 2;
--color-a: 1;
--color-b: 2;
--radius-a: 1;
--radius-b: 2;
--shadow-a: 1;
--shadow-b: 2;
--animate-a: 1;
--animate-b: 2;
}
@plugin "./plugin.js";
`,
{
async loadModule(id, base) {
return {
base,
module: plugin(function ({ theme }) {
didCallPluginFn()
expect(theme('screens')).toMatchObject({
a: '1',
b: '2',
})
expect(theme('screens.a')).toEqual('1')
expect(theme('screens.b')).toEqual('2')
expect(theme('colors')).toMatchObject({
a: '1',
b: '2',
})
expect(theme('colors.a')).toEqual('1')
expect(theme('colors.b')).toEqual('2')
expect(theme('borderRadius')).toMatchObject({
a: '1',
b: '2',
})
expect(theme('borderRadius.a')).toEqual('1')
expect(theme('borderRadius.b')).toEqual('2')
expect(theme('animation')).toMatchObject({
a: '1',
b: '2',
})
expect(theme('animation.a')).toEqual('1')
expect(theme('animation.b')).toEqual('2')
expect(theme('boxShadow')).toMatchObject({
a: '1',
b: '2',
})
expect(theme('boxShadow.a')).toEqual('1')
expect(theme('boxShadow.b')).toEqual('2')
}),
}
},
},
)
expect(didCallPluginFn).toHaveBeenCalled()
})

View file

@ -13,10 +13,31 @@ export function createCompatConfig(cssTheme: Theme): UserConfig {
// and only allow colors from the CSS theme.
colors: ({ theme }) => theme('color', {}),
boxShadow: ({ theme }) => ({
...defaultTheme.boxShadow,
...theme('shadow', {}),
}),
animation: ({ theme }) => ({
...defaultTheme.animation,
...theme('animate', {}),
}),
borderRadius: ({ theme }) => ({
...defaultTheme.borderRadius,
...theme('radius', {}),
}),
screens: ({ theme }) => ({
...defaultTheme.screens,
...theme('breakpoint', {}),
}),
transitionDuration: {
...defaultTheme.transitionDuration,
DEFAULT: cssTheme.get(['--default-transition-duration']) ?? null,
},
transitionTimingFunction: {
...defaultTheme.transitionTimingFunction,
DEFAULT: cssTheme.get(['--default-transition-timing-function']) ?? null,