Skip to content

Commit 41decce

Browse files
philipp-spiessRobinMalfaitadamwathan
committed
Upgrade: Migrate JS theme configuration keys with dot and slash in the property name (#14736)
This PR fixes an issue where JS configuration theme properties with dots or slashes in them would not migrate correctly. E.g.: ```ts import { type Config } from 'tailwindcss' module.exports = { theme: { width: { 1.5: '0.375rem', '1/2': '50%', } } } ``` This should convert to: ```css @theme { --width-1_5: 0.375rem; --width-1\/2: 50%; } ``` _Note: We will likely change the `--width-1_5` key to `--width-1\.5` in a follow-up PR._ --------- Co-authored-by: Robin Malfait <[email protected]> Co-authored-by: Adam Wathan <[email protected]> Co-authored-by: Adam Wathan <[email protected]>
1 parent a06245b commit 41decce

File tree

4 files changed

+120
-4
lines changed

4 files changed

+120
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333
- _Upgrade (experimental)_: Ensure legacy theme values ending in `1` (like `theme(spacing.1)`) are correctly migrated to custom properties ([#14724](https://github.com/tailwindlabs/tailwindcss/pull/14724))
3434
- _Upgrade (experimental)_: Migrate arbitrary values to bare values for the `from-*`, `via-*`, and `to-*` utilities ([#14725](https://github.com/tailwindlabs/tailwindcss/pull/14725))
3535
- _Upgrade (experimental)_: Ensure `layer(utilities)` is removed from `@import` to keep `@utility` top-level ([#14738](https://github.com/tailwindlabs/tailwindcss/pull/14738))
36+
- _Upgrade (experimental)_: Ensure JS theme keys with special characters are escaped when migrated to CSS variables ([#14736](https://github.com/tailwindlabs/tailwindcss/pull/14736))
3637
- _Upgrade (experimental)_: Don't migrate important modifiers that are actually logical negations (e.g. `let foo = !border` to `let foo = border!`) ([#14737](https://github.com/tailwindlabs/tailwindcss/pull/14737))
3738

3839
### Changed

integrations/upgrade/js-config.test.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,57 @@ test(
3434
sm: ['0.875rem', { lineHeight: '1.5rem' }],
3535
base: ['1rem', { lineHeight: '2rem' }],
3636
},
37+
width: {
38+
px: '1px',
39+
auto: 'auto',
40+
1: '0.25rem',
41+
1.5: '0.375rem',
42+
2: '0.5rem',
43+
2.5: '0.625rem',
44+
3: '0.75rem',
45+
3.5: '0.875rem',
46+
4: '1rem',
47+
5: '1.25rem',
48+
6: '1.5rem',
49+
8: '2rem',
50+
10: '2.5rem',
51+
11: '2.75rem',
52+
12: '3rem',
53+
16: '4rem',
54+
24: '6rem',
55+
32: '8rem',
56+
40: '10rem',
57+
48: '12rem',
58+
64: '16rem',
59+
80: '20rem',
60+
96: '24rem',
61+
128: '32rem',
62+
63+
full: '100%',
64+
0: '0%',
65+
'1/2': '50%',
66+
'1/3': 'calc(100% / 3)',
67+
'2/3': 'calc(100% / 3 * 2)',
68+
'1/4': '25%',
69+
'3/4': '75%',
70+
'1/5': '20%',
71+
'2/5': '40%',
72+
'3/5': '60%',
73+
'4/5': '80%',
74+
'1/6': 'calc(100% / 6)',
75+
'5/6': 'calc(100% / 6 * 5)',
76+
'1/7': 'calc(100% / 7)',
77+
'1/10': 'calc(100% / 10)',
78+
'3/10': 'calc(100% / 10 * 3)',
79+
'7/10': 'calc(100% / 10 * 7)',
80+
'9/10': 'calc(100% / 10 * 9)',
81+
screen: '100vw',
82+
83+
'full-minus-80': 'calc(100% - 20rem)',
84+
'full-minus-96': 'calc(100% - 24rem)',
85+
86+
'225px': '225px',
87+
},
3788
extend: {
3889
colors: {
3990
red: {
@@ -147,6 +198,54 @@ test(
147198
--font-size-base: 1rem;
148199
--font-size-base--line-height: 2rem;
149200
201+
--width-*: initial;
202+
--width-0: 0%;
203+
--width-1: 0.25rem;
204+
--width-2: 0.5rem;
205+
--width-3: 0.75rem;
206+
--width-4: 1rem;
207+
--width-5: 1.25rem;
208+
--width-6: 1.5rem;
209+
--width-8: 2rem;
210+
--width-10: 2.5rem;
211+
--width-11: 2.75rem;
212+
--width-12: 3rem;
213+
--width-16: 4rem;
214+
--width-24: 6rem;
215+
--width-32: 8rem;
216+
--width-40: 10rem;
217+
--width-48: 12rem;
218+
--width-64: 16rem;
219+
--width-80: 20rem;
220+
--width-96: 24rem;
221+
--width-128: 32rem;
222+
--width-px: 1px;
223+
--width-auto: auto;
224+
--width-1_5: 0.375rem;
225+
--width-2_5: 0.625rem;
226+
--width-3_5: 0.875rem;
227+
--width-full: 100%;
228+
--width-1\\/2: 50%;
229+
--width-1\\/3: calc(100% / 3);
230+
--width-2\\/3: calc(100% / 3 * 2);
231+
--width-1\\/4: 25%;
232+
--width-3\\/4: 75%;
233+
--width-1\\/5: 20%;
234+
--width-2\\/5: 40%;
235+
--width-3\\/5: 60%;
236+
--width-4\\/5: 80%;
237+
--width-1\\/6: calc(100% / 6);
238+
--width-5\\/6: calc(100% / 6 * 5);
239+
--width-1\\/7: calc(100% / 7);
240+
--width-1\\/10: calc(100% / 10);
241+
--width-3\\/10: calc(100% / 10 * 3);
242+
--width-7\\/10: calc(100% / 10 * 7);
243+
--width-9\\/10: calc(100% / 10 * 9);
244+
--width-screen: 100vw;
245+
--width-full-minus-80: calc(100% - 20rem);
246+
--width-full-minus-96: calc(100% - 24rem);
247+
--width-225px: 225px;
248+
150249
--font-family-sans: Inter, system-ui, sans-serif;
151250
--font-family-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif,
152251
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';

packages/@tailwindcss-upgrade/src/migrate-js-config.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { resolveConfig, type ConfigFile } from '../../tailwindcss/src/compat/con
1515
import type { ThemeConfig } from '../../tailwindcss/src/compat/config/types'
1616
import { darkModePlugin } from '../../tailwindcss/src/compat/dark-mode'
1717
import type { DesignSystem } from '../../tailwindcss/src/design-system'
18+
import { escape } from '../../tailwindcss/src/utils/escape'
1819
import { findStaticPlugins, type StaticPluginOptions } from './utils/extract-static-plugins'
1920
import { info } from './utils/renderer'
2021

@@ -121,10 +122,16 @@ async function migrateTheme(
121122

122123
if (resetNamespaces.has(key[0]) && resetNamespaces.get(key[0]) === false) {
123124
resetNamespaces.set(key[0], true)
124-
css += ` --${keyPathToCssProperty([key[0]])}-*: initial;\n`
125+
let property = keyPathToCssProperty([key[0]])
126+
if (property !== null) {
127+
css += ` ${escape(`--${property}`)}-*: initial;\n`
128+
}
125129
}
126130

127-
css += ` --${keyPathToCssProperty(key)}: ${value};\n`
131+
let property = keyPathToCssProperty(key)
132+
if (property !== null) {
133+
css += ` ${escape(`--${property}`)}: ${value};\n`
134+
}
128135
}
129136

130137
if ('keyframes' in resolvedConfig.theme) {

packages/tailwindcss/src/compat/apply-config-to-theme.test.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { expect, test } from 'vitest'
1+
import { describe, expect, test } from 'vitest'
22
import { buildDesignSystem } from '../design-system'
33
import { Theme, ThemeOptions } from '../theme'
4-
import { applyConfigToTheme } from './apply-config-to-theme'
4+
import { applyConfigToTheme, keyPathToCssProperty } from './apply-config-to-theme'
55
import { resolveConfig } from './config/resolve-config'
66

77
test('config values can be merged into the theme', () => {
@@ -157,3 +157,12 @@ test('invalid keys are not merged into the theme', () => {
157157

158158
expect(entries.length).toEqual(0)
159159
})
160+
161+
describe('keyPathToCssProperty', () => {
162+
test.each([
163+
[['width', '40', '2/5'], '--width-40-2/5'],
164+
[['spacing', '0.5'], '--spacing-0_5'],
165+
])('converts %s to %s', (keyPath, expected) => {
166+
expect(`--${keyPathToCssProperty(keyPath)}`).toEqual(expected)
167+
})
168+
})

0 commit comments

Comments
 (0)