diff --git a/CHANGELOG.md b/CHANGELOG.md index 1089c156e854..c5036c56e944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Support CSS `theme()` functions inside other `@custom-media`, `@container`, and `@supports` rules ([#14358])(https://github.com/tailwindlabs/tailwindcss/pull/14358) + ### Fixed - Ensure there is always CLI feedback on save even when no new classes were found ([#14351](https://github.com/tailwindlabs/tailwindcss/pull/14351)) diff --git a/packages/tailwindcss/src/css-functions.test.ts b/packages/tailwindcss/src/css-functions.test.ts index f33be7fc0934..dbec81d3f973 100644 --- a/packages/tailwindcss/src/css-functions.test.ts +++ b/packages/tailwindcss/src/css-functions.test.ts @@ -619,6 +619,82 @@ describe('theme function', () => { `) }) }) + + test('@custom-media --my-media (min-width: theme(breakpoint.md))', async () => { + expect( + await compileCss(css` + @theme { + --breakpoint-md: 48rem; + } + @custom-media --my-media (min-width: theme(breakpoint.md)); + @media (--my-media) { + .red { + color: red; + } + } + `), + ).toMatchInlineSnapshot(` + ":root { + --breakpoint-md: 48rem; + } + + @media (width >= 48rem) { + .red { + color: red; + } + }" + `) + }) + + test('@container (width > theme(breakpoint.md))', async () => { + expect( + await compileCss(css` + @theme { + --breakpoint-md: 48rem; + } + @container (width > theme(breakpoint.md)) { + .red { + color: red; + } + } + `), + ).toMatchInlineSnapshot(` + ":root { + --breakpoint-md: 48rem; + } + + @container (width > 48rem) { + .red { + color: red; + } + }" + `) + }) + + test('@supports (text-stroke: theme(--font-size-xs))', async () => { + expect( + await compileCss(css` + @theme { + --font-size-xs: 0.75rem; + } + @supports (text-stroke: theme(--font-size-xs)) { + .red { + color: red; + } + } + `), + ).toMatchInlineSnapshot(` + ":root { + --font-size-xs: .75rem; + } + + @supports (text-stroke: 0.75rem) { + .red { + color: red; + } + }" + `) + }) }) describe('in plugins', () => { diff --git a/packages/tailwindcss/src/css-functions.ts b/packages/tailwindcss/src/css-functions.ts index 6dd68bab2d8c..0c87d8bc07c6 100644 --- a/packages/tailwindcss/src/css-functions.ts +++ b/packages/tailwindcss/src/css-functions.ts @@ -13,11 +13,14 @@ export function substituteFunctions(ast: AstNode[], pluginApi: PluginAPI) { return } - // Find @media rules + // Find at-rules rules if (node.kind === 'rule') { if ( node.selector[0] === '@' && - node.selector.startsWith('@media ') && + (node.selector.startsWith('@media ') || + node.selector.startsWith('@custom-media ') || + node.selector.startsWith('@container ') || + node.selector.startsWith('@supports ')) && node.selector.includes(THEME_FUNCTION_INVOCATION) ) { node.selector = substituteFunctionsInValue(node.selector, pluginApi)