diff --git a/CHANGELOG.md b/CHANGELOG.md index b049c4cf7e68..1c2c86eb22e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Pass options when using `addComponents` and `matchComponents` ([#14590](https://github.com/tailwindlabs/tailwindcss/pull/14590)) - Ensure `boxShadow` and `animation` theme keys in JS config files are accessible under `--shadow-*` and `--animate-*` using the `theme()` function ([#14642](https://github.com/tailwindlabs/tailwindcss/pull/14642)) - Ensure all theme keys with new names are also accessible under their old names when using the `theme()` function with the legacy dot notation syntax ([#14642](https://github.com/tailwindlabs/tailwindcss/pull/14642)) +- Ensure `var(…)` can be used as the opacity value inside the `theme([path] / [modifier])` function ([#14653](https://github.com/tailwindlabs/tailwindcss/pull/14653)) - _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)) diff --git a/packages/tailwindcss/src/css-functions.test.ts b/packages/tailwindcss/src/css-functions.test.ts index cb54f3406972..a2df1994ff70 100644 --- a/packages/tailwindcss/src/css-functions.test.ts +++ b/packages/tailwindcss/src/css-functions.test.ts @@ -136,6 +136,27 @@ describe('theme function', () => { `) }) + test('theme(colors.red.500/75%)', async () => { + expect( + await compileCss(css` + @theme { + --color-red-500: #f00; + } + .red { + color: theme(colors.red.500/75%); + } + `), + ).toMatchInlineSnapshot(` + ":root { + --color-red-500: red; + } + + .red { + color: #ff0000bf; + }" + `) + }) + test('theme(colors.red.500 / 75%)', async () => { expect( await compileCss(css` @@ -178,6 +199,49 @@ describe('theme function', () => { `) }) + test('theme(colors.red.500/var(--opacity))', async () => { + expect( + await compileCss(css` + @theme { + --color-red-500: #f00; + } + .red { + color: theme(colors.red.500/var(--opacity)); + } + `), + ).toMatchInlineSnapshot(` + ":root { + --color-red-500: red; + } + + .red { + color: color-mix(in srgb, red calc(var(--opacity) * 100%), transparent); + }" + `) + }) + + test('theme(colors.red.500/var(--opacity,50%))', async () => { + expect( + await compileCss(css` + @theme { + --color-red-500: #f00; + } + .red { + /* prettier-ignore */ + color: theme(colors.red.500/var(--opacity,50%)); + } + `), + ).toMatchInlineSnapshot(` + ":root { + --color-red-500: red; + } + + .red { + color: color-mix(in srgb, red calc(var(--opacity, 50%) * 100%), transparent); + }" + `) + }) + test('theme(spacing.12)', async () => { expect( await compileCss(css` diff --git a/packages/tailwindcss/src/css-functions.ts b/packages/tailwindcss/src/css-functions.ts index 5decddca14d4..80cbd8fbe15c 100644 --- a/packages/tailwindcss/src/css-functions.ts +++ b/packages/tailwindcss/src/css-functions.ts @@ -68,7 +68,7 @@ export function substituteFunctionsInValue( if (node.nodes[i].value.includes(',')) { break } - path += node.nodes[i].value + path += ValueParser.toCss([node.nodes[i]]) skipUntilIndex = i + 1 } diff --git a/packages/tailwindcss/src/value-parser.test.ts b/packages/tailwindcss/src/value-parser.test.ts index b90033fbc0c3..2814b2e9efa1 100644 --- a/packages/tailwindcss/src/value-parser.test.ts +++ b/packages/tailwindcss/src/value-parser.test.ts @@ -66,6 +66,20 @@ describe('parse', () => { ]) }) + it('should parse a function with nested arguments separated by `/`', () => { + expect(parse('theme(colors.red.500/var(--opacity))')).toEqual([ + { + kind: 'function', + value: 'theme', + nodes: [ + { kind: 'word', value: 'colors.red.500' }, + { kind: 'separator', value: '/' }, + { kind: 'function', value: 'var', nodes: [{ kind: 'word', value: '--opacity' }] }, + ], + }, + ]) + }) + it('should handle calculations', () => { expect(parse('calc((1 + 2) * 3)')).toEqual([ { diff --git a/packages/tailwindcss/src/value-parser.ts b/packages/tailwindcss/src/value-parser.ts index e941a966403b..852ba6ed02e1 100644 --- a/packages/tailwindcss/src/value-parser.ts +++ b/packages/tailwindcss/src/value-parser.ts @@ -114,6 +114,7 @@ const SPACE = 0x20 const LESS_THAN = 0x3c const GREATER_THAN = 0x3e const EQUALS = 0x3d +const SLASH = 0x2f export function parse(input: string) { input = input.replaceAll('\r\n', '\n') @@ -143,6 +144,7 @@ export function parse(input: string) { case COLON: case COMMA: case SPACE: + case SLASH: case LESS_THAN: case GREATER_THAN: case EQUALS: {