Skip to content

Commit 28f0c84

Browse files
committed
Support advanced screens from JS configs
1 parent 76f89b0 commit 28f0c84

7 files changed

Lines changed: 83 additions & 12 deletions

File tree

packages/tailwindcss/src/compat/apply-compat-hooks.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { resolveConfig } from './config/resolve-config'
1010
import type { UserConfig } from './config/types'
1111
import { darkModePlugin } from './dark-mode'
1212
import { buildPluginApi, type CssPluginOptions, type Plugin } from './plugin-api'
13-
import { registerScreensConfig } from './screens-config'
13+
import { buildMediaQuery, registerScreensConfig } from './screens-config'
1414
import { registerThemeVariantOverrides } from './theme-variants'
1515

1616
export async function applyCompatibilityHooks({
@@ -191,6 +191,13 @@ export async function applyCompatibilityHooks({
191191
registerThemeVariantOverrides(resolvedUserConfig, designSystem)
192192
registerScreensConfig(resolvedUserConfig, designSystem)
193193

194+
// Replace `resolveBreakpointQuery` with a version that can handle more
195+
// complex breakpoint queries like objects, tuples, and custom media queries
196+
// that are present in JS theme configurations.
197+
designSystem.resolveBreakpointQuery = function resolveBreakpointQuery(name: string) {
198+
return buildMediaQuery(pluginApi.theme(`screens.${name}`))
199+
}
200+
194201
// Replace `resolveThemeValue` with a version that is backwards compatible
195202
// with dot-notation but also aware of any JS theme configurations registered
196203
// by plugins or JS config files. This is significantly slower than just

packages/tailwindcss/src/compat/plugin-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function buildPluginApi(
8585
let api: PluginAPI = {
8686
addBase(css) {
8787
let baseNodes = objectToAst(css)
88-
substituteFunctions(baseNodes, api.theme)
88+
substituteFunctions(baseNodes, api.theme, designSystem.resolveBreakpointQuery)
8989
ast.push(rule('@layer base', baseNodes))
9090
},
9191

packages/tailwindcss/src/compile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export function compileCandidates(
4949
substituteFunctions(
5050
rules.map(({ node }) => node),
5151
designSystem.resolveThemeValue,
52+
designSystem.resolveBreakpointQuery,
5253
)
5354
} catch (err) {
5455
// If substitution fails then the candidate likely contains a call to

packages/tailwindcss/src/css-functions.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,65 @@ describe('screen function', () => {
830830
}"
831831
`)
832832
})
833+
834+
test('@media screen(advanced)', async () => {
835+
let compiled = await compile(
836+
css`
837+
@config "./my-config.js";
838+
.foo {
839+
@media screen(simple) {
840+
--custom: simple;
841+
}
842+
@media screen(min-only) {
843+
--custom: min-only;
844+
}
845+
@media screen(max-only) {
846+
--custom: max-only;
847+
}
848+
@media screen(min-max) {
849+
--custom: min-max;
850+
}
851+
@media screen(multi) {
852+
--custom: multi;
853+
}
854+
}
855+
`,
856+
{
857+
loadConfig: async () => ({
858+
theme: {
859+
screens: {
860+
simple: '48rem',
861+
'min-only': { min: '48rem' },
862+
'max-only': { max: '64rem' },
863+
'min-max': { max: '64rem' },
864+
multi: ['32rem', { min: '48rem', max: '64rem' }],
865+
},
866+
},
867+
}),
868+
},
869+
)
870+
871+
expect(compiled.build([])).toMatchInlineSnapshot(`
872+
".foo {
873+
@media (width >= 48rem) {
874+
--custom: simple;
875+
}
876+
@media (width >= 48rem) {
877+
--custom: min-only;
878+
}
879+
@media (64rem >= width) {
880+
--custom: max-only;
881+
}
882+
@media (64rem >= width) {
883+
--custom: min-max;
884+
}
885+
@media (width >= 32rem), (64rem >= width >= 48rem) {
886+
--custom: multi;
887+
}
888+
}
889+
"
890+
`)
891+
})
833892
})
834893
})
835894

packages/tailwindcss/src/css-functions.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { walk, type AstNode } from './ast'
2-
import { buildMediaQuery } from './compat/screens-config'
32
import * as ValueParser from './value-parser'
43
import { type ValueAstNode } from './value-parser'
54

@@ -8,14 +7,11 @@ export const SCREEN_FUNCTION_INVOCATION = 'screen('
87

98
type ResolveThemeValue = (path: string) => string | undefined
109

11-
export function substituteFunctions(ast: AstNode[], resolveThemeValue: ResolveThemeValue) {
12-
function resolveBreakpointQuery(name: string) {
13-
let value = resolveThemeValue(`screens.${name}`) ?? resolveThemeValue(`--breakpoint-${name}`)
14-
if (value) {
15-
return buildMediaQuery(value)
16-
}
17-
}
18-
10+
export function substituteFunctions(
11+
ast: AstNode[],
12+
resolveThemeValue: ResolveThemeValue,
13+
resolveBreakpointQuery: ResolveThemeValue,
14+
) {
1915
walk(ast, (node) => {
2016
// Find all declaration values
2117
if (

packages/tailwindcss/src/design-system.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type DesignSystem = {
2323

2424
getVariantOrder(): Map<Variant, number>
2525
resolveThemeValue(path: string): string | undefined
26+
resolveBreakpointQuery(name: string): string | undefined
2627

2728
// Used by IntelliSense
2829
candidatesToCss(classes: string[]): (string | null)[]
@@ -123,6 +124,13 @@ export function buildDesignSystem(theme: Theme): DesignSystem {
123124

124125
return themeValue
125126
},
127+
128+
resolveBreakpointQuery(name: string) {
129+
let themeValue = theme.resolveValue(name, ['--breakpoint'])
130+
if (themeValue) {
131+
return `(width >= ${themeValue})`
132+
}
133+
},
126134
}
127135

128136
return designSystem

packages/tailwindcss/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ async function parseCss(
292292
}
293293

294294
if (css.includes(THEME_FUNCTION_INVOCATION) || css.includes(SCREEN_FUNCTION_INVOCATION)) {
295-
substituteFunctions(ast, designSystem.resolveThemeValue)
295+
substituteFunctions(ast, designSystem.resolveThemeValue, designSystem.resolveBreakpointQuery)
296296
}
297297

298298
// Remove `@utility`, we couldn't replace it before yet because we had to

0 commit comments

Comments
 (0)