diff --git a/CHANGELOG.md b/CHANGELOG.md index ab6ba8230..d55a21cdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Ensure content globs defined in `@config` files are relative to that file ([#14314](https://github.com/tailwindlabs/tailwindcss/pull/14314)) +- Ensure CSS `theme()` functions are evaluated in media query ranges with collapsed whitespace ((#14321)[https://github.com/tailwindlabs/tailwindcss/pull/14321]) ## [4.0.0-alpha.21] - 2024-09-02 diff --git a/packages/tailwindcss/src/functions.test.ts b/packages/tailwindcss/src/functions.test.ts index e6703227a..e39978152 100644 --- a/packages/tailwindcss/src/functions.test.ts +++ b/packages/tailwindcss/src/functions.test.ts @@ -540,14 +540,15 @@ describe('theme function', () => { }) describe('in @media queries', () => { - test('@media (min-width: theme(breakpoint.md)) and (max-width: theme(--breakpoint-lg))', async () => { + test('@media (min-width:theme(breakpoint.md)) and (max-width: theme(--breakpoint-lg))', async () => { expect( await compileCss(css` @theme { --breakpoint-md: 48rem; --breakpoint-lg: 64rem; } - @media (min-width: theme(breakpoint.md)) and (max-width: theme(--breakpoint-lg)) { + /* prettier-ignore */ + @media (min-width:theme(breakpoint.md)) and (max-width: theme(--breakpoint-lg)) { .red { color: red; } @@ -566,5 +567,32 @@ describe('theme function', () => { }" `) }) + + test('@media (width >= theme(breakpoint.md)) and (width { + expect( + await compileCss(css` + @theme { + --breakpoint-md: 48rem; + --breakpoint-lg: 64rem; + } + @media (width >= theme(breakpoint.md)) and (width= 48rem) and (width < 64rem) { + .red { + color: red; + } + }" + `) + }) }) }) diff --git a/packages/tailwindcss/src/value-parser.test.ts b/packages/tailwindcss/src/value-parser.test.ts index b512f9d45..b90033fbc 100644 --- a/packages/tailwindcss/src/value-parser.test.ts +++ b/packages/tailwindcss/src/value-parser.test.ts @@ -93,7 +93,11 @@ describe('parse', () => { }) it('should handle media query params with functions', () => { - expect(parse('(min-width: 600px) and (max-width:theme(colors.red.500))')).toEqual([ + expect( + parse( + '(min-width: 600px) and (max-width:theme(colors.red.500)) and (theme(--breakpoint-sm) { { kind: 'function', value: 'theme', nodes: [{ kind: 'word', value: 'colors.red.500' }] }, ], }, + { kind: 'separator', value: ' ' }, + { kind: 'word', value: 'and' }, + { kind: 'separator', value: ' ' }, + { + kind: 'function', + value: '', + nodes: [ + { kind: 'function', value: 'theme', nodes: [{ kind: 'word', value: '--breakpoint-sm' }] }, + { kind: 'separator', value: '<' }, + { kind: 'word', value: 'width' }, + { kind: 'separator', value: '<=' }, + { kind: 'function', value: 'theme', nodes: [{ kind: 'word', value: '--breakpoint-md' }] }, + ], + }, ]) }) }) diff --git a/packages/tailwindcss/src/value-parser.ts b/packages/tailwindcss/src/value-parser.ts index 7485b9e69..e941a9664 100644 --- a/packages/tailwindcss/src/value-parser.ts +++ b/packages/tailwindcss/src/value-parser.ts @@ -111,6 +111,9 @@ const DOUBLE_QUOTE = 0x22 const OPEN_PAREN = 0x28 const SINGLE_QUOTE = 0x27 const SPACE = 0x20 +const LESS_THAN = 0x3c +const GREATER_THAN = 0x3e +const EQUALS = 0x3d export function parse(input: string) { input = input.replaceAll('\r\n', '\n') @@ -139,7 +142,10 @@ export function parse(input: string) { // ``` case COLON: case COMMA: - case SPACE: { + case SPACE: + case LESS_THAN: + case GREATER_THAN: + case EQUALS: { // 1. Handle everything before the separator as a word // Handle everything before the closing paren a word if (buffer.length > 0) { @@ -157,7 +163,14 @@ export function parse(input: string) { let end = i + 1 for (; end < input.length; end++) { peekChar = input.charCodeAt(end) - if (peekChar !== COLON && peekChar !== COMMA && peekChar !== SPACE) { + if ( + peekChar !== COLON && + peekChar !== COMMA && + peekChar !== SPACE && + peekChar !== LESS_THAN && + peekChar !== GREATER_THAN && + peekChar !== EQUALS + ) { break } }