From ee35a1d047cbbede413868f13580f651c56bd648 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Fri, 6 Sep 2024 19:05:48 +0200 Subject: [PATCH] Support CSS `theme()` functions inside `@custom-media` rules (#14358) This PR will now also scan `@custom-media` rules for invocations of the CSS `theme()` function. --- CHANGELOG.md | 4 + .../tailwindcss/src/css-functions.test.ts | 76 +++++++++++++++++++ packages/tailwindcss/src/css-functions.ts | 7 +- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9111c69af..87256839c 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 f33be7fc0..dbec81d3f 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 6dd68bab2..0c87d8bc0 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)