Add tuple syntax to guarantee screens order (#6104)

* add normalizeScreens function

This will allow us to normalize the various kinds of inputs to a stable
version that is consistent regardless of the input.

* use normalized screens

* add dedicated test for new tuple syntax

* make test consistent with other tests

While working on the normalizeScreens feature, some tests started
failing (the one with multiple screens), while looking at them I made
them consistent with the rest of the codebase.

* add test to ensure consistent order in screens output

* update changelog

* Update CHANGELOG.md

* Update CHANGELOG.md

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
This commit is contained in:
Robin Malfait 2021-11-16 18:01:06 +01:00 • committed by GitHub
parent 6c4b86d438
commit ef325ea35b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 527 additions and 190 deletions

View file

@ -1,24 +1,20 @@
export default function buildMediaQuery(screens) {
if (typeof screens === 'string') {
screens = { min: screens }
}
if (!Array.isArray(screens)) {
screens = [screens]
}
screens = Array.isArray(screens) ? screens : [screens]
return screens
.map((screen) => {
if (screen?.hasOwnProperty?.('raw')) {
return screen.raw
}
.map((screen) =>
screen.values.map((screen) => {
if (screen.raw !== undefined) {
return screen.raw
}
return Object.entries(screen)
.map(([feature, value]) => {
feature = { min: 'min-width', max: 'max-width' }[feature] ?? feature
return `(${feature}: ${value})`
})
.join(' and ')
})
return [
screen.min && `(min-width: ${screen.min})`,
screen.max && `(max-width: ${screen.max})`,
]
.filter(Boolean)
.join(' and ')
})
)
.join(', ')
}

View file

@ -0,0 +1,42 @@
/**
* A function that normalizes the various forms that the screens object can be
* provided in.
*
* Input(s):
* - ['100px', '200px'] // Raw strings
* - { sm: '100px', md: '200px' } // Object with string values
* - { sm: { min: '100px' }, md: { max: '100px' } } // Object with object values
* - { sm: [{ min: '100px' }, { max: '200px' }] } // Object with object array (multiple values)
* - [['sm', '100px'], ['md', '200px']] // Tuple object
*
* Output(s):
* - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
*/
export function normalizeScreens(screens) {
if (Array.isArray(screens)) {
return screens.map((screen) => {
if (typeof screen === 'string') {
return { name: screen.toString(), values: [{ min: screen, max: undefined }] }
}
let [name, options] = screen
name = name.toString()
if (typeof options === 'string') {
return { name, values: [{ min: options, max: undefined }] }
}
if (Array.isArray(options)) {
return { name, values: options.map((option) => resolveValue(option)) }
}
return { name, values: [resolveValue(options)] }
})
}
return normalizeScreens(Object.entries(screens ?? {}))
}
function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
return { min, max, raw }
}