Skip to content

Commit

Permalink
Refactor some screen compatibility code (#14465)
Browse files Browse the repository at this point in the history
These changes were extracted from our work on a `screen()` function for
CSS — we've decided to move those changes to a code mod instead of
implementing support for `screen()` in the compiler — but the
refactoring around the changes still makes sense to do so I'm landing
that here separately.

---------

Co-authored-by: Philipp Spiess <hello@philippspiess.com>
  • Loading branch information
thecrypticace and philipp-spiess committed Sep 20, 2024
1 parent ba5b9af commit 4e129be
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 35 deletions.
15 changes: 15 additions & 0 deletions packages/tailwindcss/src/compat/config/resolve-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,19 @@ function mergeTheme(ctx: ResolutionContext) {
for (let key in ctx.theme) {
ctx.theme[key] = resolveValue(ctx.theme[key])
}

// Turn {min: '123px'} into '123px' in screens
if (ctx.theme.screens && typeof ctx.theme.screens === 'object') {
for (let key of Object.keys(ctx.theme.screens)) {
let screen = ctx.theme.screens[key]
if (!screen) continue
if (typeof screen !== 'object') continue

if ('raw' in screen) continue
if ('max' in screen) continue
if (!('min' in screen)) continue

ctx.theme.screens[key] = screen.min
}
}
}
20 changes: 12 additions & 8 deletions packages/tailwindcss/src/compat/screens-config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ describe('complex screen configs', () => {
md: [
//
{ min: '668px', max: '767px' },
{ min: '868px' },
'868px',
],
lg: { min: '868px' },
xl: { min: '1024px', max: '1279px' },
Expand All @@ -468,15 +468,14 @@ describe('complex screen configs', () => {
}),
})

expect(
compiler.build(['min-sm:flex', 'min-md:flex', 'min-lg:flex', 'min-xl:flex', 'min-tall:flex']),
).toBe('')
expect(compiler.build(['min-sm:flex', 'min-md:flex', 'min-xl:flex', 'min-tall:flex'])).toBe('')

expect(
compiler.build([
'sm:flex',
'md:flex',
'lg:flex',
'min-lg:flex',
'xl:flex',
'tall:flex',

Expand All @@ -485,22 +484,27 @@ describe('complex screen configs', () => {
]),
).toMatchInlineSnapshot(`
".lg\\:flex {
@media (min-width: 868px) {
@media (width >= 868px) {
display: flex;
}
}
.min-lg\\:flex {
@media (width >= 868px) {
display: flex;
}
}
.sm\\:flex {
@media (max-width: 639px) {
@media (639px >= width) {
display: flex;
}
}
.md\\:flex {
@media (min-width: 668px and max-width: 767px), (min-width: 868px) {
@media (767px >= width >= 668px), (width >= 868px) {
display: flex;
}
}
.xl\\:flex {
@media (min-width: 1024px and max-width: 1279px) {
@media (1279px >= width >= 1024px) {
display: flex;
}
}
Expand Down
70 changes: 44 additions & 26 deletions packages/tailwindcss/src/compat/screens-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,14 @@ export function registerScreensConfig(userConfig: ResolvedConfig, designSystem:
continue
}

let query: string | undefined
let deferInsert = true

if (typeof value === 'string') {
query = `(width >= ${value})`
deferInsert = false
} else if (typeof value === 'object' && value !== null) {
if (Array.isArray(value)) {
query = value.map(ruleForComplexScreenValue).join(', ')
} else {
query = ruleForComplexScreenValue(value) ?? ''
if ('min' in value && !('max' in value)) {
deferInsert = false
}
}
} else {
continue
}

let query = buildMediaQuery(value)

function insert(order: number) {
// `min-*` and `max-*` rules do not need to be reconfigured, as they are
// reading the latest values from the theme.
Expand Down Expand Up @@ -87,19 +77,47 @@ export function registerScreensConfig(userConfig: ResolvedConfig, designSystem:
}
}

function ruleForComplexScreenValue(value: object): string | null {
let query = null
if ('raw' in value && typeof value.raw === 'string') {
query = value.raw
} else {
let rules: string[] = []
export function buildMediaQuery(values: unknown) {
type ScreenDescriptor = {
min?: string
max?: string
raw?: string
}

if ('min' in value) rules.push(`min-width: ${value.min}`)
if ('max' in value) rules.push(`max-width: ${value.max}`)
let list: unknown[] = Array.isArray(values) ? values : [values]
return list
.map((value): ScreenDescriptor | null => {
if (typeof value === 'string') {
return { min: value }
}

if (rules.length !== 0) {
query = `(${rules.join(' and ')})`
}
}
return query
if (value && typeof value === 'object') {
return value
}

return null
})
.map((screen) => {
if (screen === null) return null

if ('raw' in screen) {
return screen.raw
}

let query = ''

if (screen.max !== undefined) {
query += `${screen.max} >= `
}

query += 'width'

if (screen.min !== undefined) {
query += ` >= ${screen.min}`
}

return `(${query})`
})
.filter(Boolean)
.join(', ')
}
6 changes: 5 additions & 1 deletion packages/tailwindcss/src/css-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ export function substituteFunctions(ast: AstNode[], resolveThemeValue: ResolveTh
if (
node.selector[0] === '@' &&
(node.selector.startsWith('@media ') ||
node.selector.startsWith('@media(') ||
node.selector.startsWith('@custom-media ') ||
node.selector.startsWith('@custom-media(') ||
node.selector.startsWith('@container ') ||
node.selector.startsWith('@supports ')) &&
node.selector.startsWith('@container(') ||
node.selector.startsWith('@supports ') ||
node.selector.startsWith('@supports(')) &&
node.selector.includes(THEME_FUNCTION_INVOCATION)
) {
node.selector = substituteFunctionsInValue(node.selector, resolveThemeValue)
Expand Down

0 comments on commit 4e129be

Please sign in to comment.