Refactor some screen compatibility code (#14465)

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>
This commit is contained in:
Jordan Pittman 2024-09-20 09:42:22 -04:00 • committed by GitHub
parent ba5b9afc8a
commit 4e129be2b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 77 additions and 36 deletions

View file

@ -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
}
}
}

View file

@ -457,7 +457,7 @@ describe('complex screen configs', () => {
md: [
//
{ min: '668px', max: '767px' },
{ min: '868px' },
'868px',
],
lg: { min: '868px' },
xl: { min: '1024px', max: '1279px' },
@ -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',
@ -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;
}
}

View file

@ -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.
@ -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[] = []
if ('min' in value) rules.push(`min-width: ${value.min}`)
if ('max' in value) rules.push(`max-width: ${value.max}`)
if (rules.length !== 0) {
query = `(${rules.join(' and ')})`
}
export function buildMediaQuery(values: unknown) {
type ScreenDescriptor = {
min?: string
max?: string
raw?: string
}
return query
let list: unknown[] = Array.isArray(values) ? values : [values]
return list
.map((value): ScreenDescriptor | null => {
if (typeof value === 'string') {
return { min: value }
}
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(', ')
}

View file

@ -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)