diff --git a/CHANGELOG.md b/CHANGELOG.md index e7143ff1b106..9a7793e09915 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Vite: Ensure setups with multiple Vite builds work as expected ([#16631](https://github.com/tailwindlabs/tailwindcss/pull/16631)) - Vite: Ensure Astro production builds contain classes for client-only components ([#16631](https://github.com/tailwindlabs/tailwindcss/pull/16631)) - Vite: Ensure utility classes are read without escaping special characters ([#16631](https://github.com/tailwindlabs/tailwindcss/pull/16631)) +- Allow `theme(…)` options when using `@import` ([#16514](https://github.com/tailwindlabs/tailwindcss/pull/16514)) ## [4.0.7] - 2025-02-18 diff --git a/packages/tailwindcss/src/index.test.ts b/packages/tailwindcss/src/index.test.ts index 8478cc39ed29..aa68796073f0 100644 --- a/packages/tailwindcss/src/index.test.ts +++ b/packages/tailwindcss/src/index.test.ts @@ -1021,8 +1021,7 @@ describe('sorting', () => { }) }) -// Parsing theme values from CSS -describe('Parsing themes values from CSS', () => { +describe('Parsing theme values from CSS', () => { test('Can read values from `@theme`', async () => { expect( await compileCss( @@ -2020,7 +2019,44 @@ describe('Parsing themes values from CSS', () => { `) }) - test('`@media theme(…)` can only contain `@theme` rules', () => { + test('`@import "tailwindcss" theme(static)` will always generate theme values, regardless of whether they were used or not', async () => { + expect( + await compileCss( + css` + @import 'tailwindcss' theme(static); + `, + ['bg-tomato'], + { + async loadStylesheet() { + return { + content: css` + @theme { + --color-tomato: #e10c04; + --color-potato: #ac855b; + --color-primary: var(--primary); + } + + @tailwind utilities; + `, + base: '', + } + }, + }, + ), + ).toMatchInlineSnapshot(` + ":root, :host { + --color-tomato: #e10c04; + --color-potato: #ac855b; + --color-primary: var(--primary); + } + + .bg-tomato { + background-color: var(--color-tomato); + }" + `) + }) + + test('`@media theme(reference)` can only contain `@theme` rules', () => { return expect( compileCss( css` @@ -2034,7 +2070,10 @@ describe('Parsing themes values from CSS', () => { ['bg-tomato', 'bg-potato', 'bg-avocado'], ), ).rejects.toThrowErrorMatchingInlineSnapshot( - `[Error: Files imported with \`@import "…" theme(…)\` must only contain \`@theme\` blocks.]`, + ` + [Error: Files imported with \`@import "…" theme(reference)\` must only contain \`@theme\` blocks. + Use \`@reference "…";\` instead.] + `, ) }) @@ -2073,6 +2112,43 @@ describe('Parsing themes values from CSS', () => { `) }) + test('`@import "tailwindcss" theme(inline)` theme values added as `inline` are not wrapped in `var(…)` when used as utility values', async () => { + expect( + await compileCss( + css` + @import 'tailwindcss' theme(inline); + `, + ['bg-tomato'], + { + async loadStylesheet() { + return { + content: css` + @theme { + --color-tomato: #e10c04; + --color-potato: #ac855b; + --color-primary: var(--primary); + } + + @tailwind utilities; + `, + base: '', + } + }, + }, + ), + ).toMatchInlineSnapshot(` + ":root, :host { + --color-tomato: #e10c04; + --color-potato: #ac855b; + --color-primary: var(--primary); + } + + .bg-tomato { + background-color: #e10c04; + }" + `) + }) + test('theme values added as `static` will always be generated, regardless of whether they were used or not', async () => { expect( await compileCss( diff --git a/packages/tailwindcss/src/index.ts b/packages/tailwindcss/src/index.ts index 07956ab421ce..b7e7886c28b1 100644 --- a/packages/tailwindcss/src/index.ts +++ b/packages/tailwindcss/src/index.ts @@ -380,18 +380,24 @@ async function parseCss( // Handle `@media theme(…)` // - // We support `@import "tailwindcss/theme" theme(reference)` as a way to + // We support `@import "tailwindcss" theme(reference)` as a way to // import an external theme file as a reference, which becomes `@media // theme(reference) { … }` when the `@import` is processed. else if (param.startsWith('theme(')) { let themeParams = param.slice(6, -1) + let hasReference = themeParams.includes('reference') walk(node.nodes, (child) => { if (child.kind !== 'at-rule') { - throw new Error( - 'Files imported with `@import "…" theme(…)` must only contain `@theme` blocks.', - ) + if (hasReference) { + throw new Error( + `Files imported with \`@import "…" theme(reference)\` must only contain \`@theme\` blocks.\nUse \`@reference "…";\` instead.`, + ) + } + + return WalkAction.Continue } + if (child.name === '@theme') { child.params += ' ' + themeParams return WalkAction.Skip diff --git a/packages/tailwindcss/src/test-utils/run.ts b/packages/tailwindcss/src/test-utils/run.ts index 31ba8417c4ec..2951ef576ab8 100644 --- a/packages/tailwindcss/src/test-utils/run.ts +++ b/packages/tailwindcss/src/test-utils/run.ts @@ -1,7 +1,11 @@ import { Features, transform } from 'lightningcss' import { compile } from '..' -export async function compileCss(css: string, candidates: string[] = [], options = {}) { +export async function compileCss( + css: string, + candidates: string[] = [], + options: Parameters[1] = {}, +) { let { build } = await compile(css, options) return optimizeCss(build(candidates)).trim() }