Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow theme(…) options when using @import #16514

Merged
merged 4 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
84 changes: 80 additions & 4 deletions packages/tailwindcss/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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`
Expand All @@ -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.]
`,
)
})

Expand Down Expand Up @@ -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(
Expand Down
14 changes: 10 additions & 4 deletions packages/tailwindcss/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion packages/tailwindcss/src/test-utils/run.ts
Original file line number Diff line number Diff line change
@@ -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<typeof compile>[1] = {},
) {
let { build } = await compile(css, options)
return optimizeCss(build(candidates)).trim()
}
Expand Down