diff --git a/CHANGELOG.md b/CHANGELOG.md index 24d35cb1e..92e99cac1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Don't convert underscores in the first argument to `var()` to spaces ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776)) +- Don't convert underscores in the first argument to `var()` and `theme()` to spaces ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776), [#14781](https://github.com/tailwindlabs/tailwindcss/pull/14781)) ### Fixed diff --git a/packages/tailwindcss/src/candidate.test.ts b/packages/tailwindcss/src/candidate.test.ts index c1280a2fd..832f348e1 100644 --- a/packages/tailwindcss/src/candidate.test.ts +++ b/packages/tailwindcss/src/candidate.test.ts @@ -1105,6 +1105,31 @@ it('should not replace `_` in the first argument to `var()`', () => { `) }) +it('should not replace `_` in the first argument to `theme()`', () => { + let utilities = new Utilities() + utilities.functional('ml', () => []) + + expect(run('ml-[theme(--spacing-1_5,_theme(--spacing-2_5,_1rem))]', { utilities })) + .toMatchInlineSnapshot(` + [ + { + "important": false, + "kind": "functional", + "modifier": null, + "negative": false, + "raw": "ml-[theme(--spacing-1_5,_theme(--spacing-2_5,_1rem))]", + "root": "ml", + "value": { + "dataType": null, + "kind": "arbitrary", + "value": "theme(--spacing-1_5, theme(--spacing-2_5, 1rem))", + }, + "variants": [], + }, + ] + `) +}) + it('should parse arbitrary properties', () => { expect(run('[color:red]')).toMatchInlineSnapshot(` [ diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index d7d1f0f56..c1ce01b9e 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -116,7 +116,7 @@ describe('compiling CSS', () => { ).toMatchSnapshot() }) - test('unescapes underscores to spaces inside arbitrary values except for `url()` and first argument of `var()`', async () => { + test('unescapes underscores to spaces inside arbitrary values except for `url()` and first argument of `var()` and `theme()`', async () => { expect( await compileCss( css` @@ -126,7 +126,11 @@ describe('compiling CSS', () => { } @tailwind utilities; `, - ['bg-[no-repeat_url(./my_file.jpg)', 'ml-[var(--spacing-1_5,_var(--spacing-2_5,_1rem))]'], + [ + 'bg-[no-repeat_url(./my_file.jpg)', + 'ml-[var(--spacing-1_5,_var(--spacing-2_5,_1rem))]', + 'ml-[theme(--spacing-1_5,theme(--spacing-2_5,_1rem)))]', + ], ), ).toMatchInlineSnapshot(` ":root { @@ -134,6 +138,10 @@ describe('compiling CSS', () => { --spacing-2_5: 2.5rem; } + .ml-\\[theme\\(--spacing-1_5\\,theme\\(--spacing-2_5\\,_1rem\\)\\)\\)\\] { + margin-left: 1.5rem; + } + .ml-\\[var\\(--spacing-1_5\\,_var\\(--spacing-2_5\\,_1rem\\)\\)\\] { margin-left: var(--spacing-1_5, var(--spacing-2_5, 1rem)); } diff --git a/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts b/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts index 351a99330..2dccd897f 100644 --- a/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts +++ b/packages/tailwindcss/src/utils/decode-arbitrary-value.test.ts @@ -29,6 +29,14 @@ describe('decoding arbitrary values', () => { ) }) + it('should not replace underscores in the first argument of theme()', () => { + expect(decodeArbitraryValue('theme(--spacing-1_5)')).toBe('theme(--spacing-1_5)') + expect(decodeArbitraryValue('theme(--spacing-1_5,_1rem)')).toBe('theme(--spacing-1_5, 1rem)') + expect(decodeArbitraryValue('theme(--spacing-1_5,_theme(--spacing-2_5,_1rem))')).toBe( + 'theme(--spacing-1_5, theme(--spacing-2_5, 1rem))', + ) + }) + it('should leave var(…) as is', () => { expect(decodeArbitraryValue('var(--foo)')).toBe('var(--foo)') expect(decodeArbitraryValue('var(--headings-h1-size)')).toBe('var(--headings-h1-size)') diff --git a/packages/tailwindcss/src/utils/decode-arbitrary-value.ts b/packages/tailwindcss/src/utils/decode-arbitrary-value.ts index 349d2dddc..11ec871c5 100644 --- a/packages/tailwindcss/src/utils/decode-arbitrary-value.ts +++ b/packages/tailwindcss/src/utils/decode-arbitrary-value.ts @@ -55,7 +55,12 @@ function recursivelyDecodeArbitraryValues(ast: ValueParser.ValueAstNode[]) { break } - if (node.value === 'var' || node.value.endsWith('_var')) { + if ( + node.value === 'var' || + node.value.endsWith('_var') || + node.value === 'theme' || + node.value.endsWith('_theme') + ) { // Don't decode underscores in the first argument of var() but do // decode the function name node.value = convertUnderscoresToWhitespace(node.value) @@ -78,11 +83,11 @@ function recursivelyDecodeArbitraryValues(ast: ValueParser.ValueAstNode[]) { break } default: - never() + never(node) } } } -function never(): never { - throw new Error('This should never happen') +function never(value: never): never { + throw new Error(`Unexpected value: ${value}`) }