Skip to content

Commit

Permalink
normalizeMediaQuery: Parses query into a workable object
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Jan 13, 2020
1 parent 43373e6 commit 85c57d2
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ import {
BreakpointBehavior,
} from '../../../const/defaultOptions'
import transformNumeric from '../../math/transformNumeric'
import normalizeQuery from '../../styles/normalizeQuery'
import normalizeQuery, {
NormalizedQueryParam,
} from '../../styles/normalizeQuery'
import compose from '../../functions/compose'

type MediaQueryPair = [string, Numeric]

/**
* Determines whether a given media query param should be added
* to the media query string based on a breakpoint's behavior.
*/
const shouldAppendProperty = (
queryParam: string,
queryParam: NormalizedQueryParam,
behavior: BreakpointBehavior,
): boolean => {
const [prefix, splitPropName] = queryParam.split('-')
const isDimensionalProp = ['height', 'width'].includes(splitPropName)
const { prefix, name } = queryParam
const isDimensionalProp = ['height', 'width'].includes(name)

if (!isDimensionalProp) {
return true
Expand All @@ -31,31 +31,46 @@ const shouldAppendProperty = (
}

const filterRelevantQueryParams = (behavior: BreakpointBehavior) => (
queryList: MediaQueryPair[],
): MediaQueryPair[] => {
return queryList.filter(([queryParam]) =>
shouldAppendProperty(queryParam, behavior),
queryList: NormalizedQueryParam[],
): NormalizedQueryParam[] => {
return queryList.filter((normalizedQueryParam) =>
shouldAppendProperty(normalizedQueryParam, behavior),
)
}

/**
* Joins a given media query params list with the given transformer function.
*/
export const joinQueryList = (transformer: (pair: MediaQueryPair) => any) => (
queryList: MediaQueryPair[],
export const joinQueryList = (
queryList: NormalizedQueryParam[],
transformer: (pair: NormalizedQueryParam) => any,
) => {
return queryList.map(transformer).join(' and ')
}

export default function createMediaQuery(
export const createQueryList = (
breakpoint: Breakpoint,
behavior: BreakpointBehavior,
): string {
): NormalizedQueryParam[] => {
return compose(
joinQueryList(([dashedQueryProp, propValue]) => {
return `(${dashedQueryProp}:${String(transformNumeric(propValue))})`
}),
filterRelevantQueryParams(behavior),
normalizeQuery,
)(breakpoint)
}

export default function createMediaQuery(
breakpoint: Breakpoint,
behavior: BreakpointBehavior,
): string {
const queryList = createQueryList(breakpoint, behavior)

const mediaQueryString = joinQueryList(
queryList,
({ prefix, name, value }) => {
const dashedQueryParamName = [prefix, name].filter(Boolean).join('-')
return `(${dashedQueryParamName}:${String(transformNumeric(value))})`
},
)

return mediaQueryString
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,30 @@ import normalizeQuery from './normalizeQuery'

describe('normalizeQuery', () => {
describe('given a media query Object', () => {
it('returns its [key, value] pairs', () => {
it('returns its { prefix, name, value } data', () => {
expect(
normalizeQuery({
height: 100,
minWidth: 120,
maxAspectRatio: '3/4',
}),
).toEqual([['min-width', 120], ['max-aspect-ratio', '3/4']])
).toEqual([
{
prefix: undefined,
name: 'height',
value: 100,
},
{
prefix: 'min',
name: 'width',
value: 120,
},
{
prefix: 'max',
name: 'aspectRatio',
value: '3/4',
},
])
})
})
})
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { Numeric, Breakpoint } from '../../../const/defaultOptions'
import isset from '../../functions/isset'
import toDashedString from '../../strings/toDashedString'
import toLowerCaseFirst from '../../strings/toLowerCaseFirst'

export interface NormalizedQueryParam {
prefix: string
name: string
value: Numeric
}

/**
* Normalizes given media query object to a list of [propName, propValue].
* @example
* normalizeQuery({ minWidth: 120 })
* // [['min-width', 120]]
*/
export default function normalizeQuery(
queryProps: Breakpoint,
): Array<[string, Numeric]> {
return Object.entries<Numeric>(queryProps)
.filter(([_, propValue]) => isset(propValue))
.map<[string, Numeric]>(([propName, propValue]) => [
toDashedString(propName),
propValue,
])
breakpoint: Breakpoint,
): NormalizedQueryParam[] {
return Object.entries<Numeric>(breakpoint)
.filter(([_, value]) => isset(value))
.map(([propName, value]) => {
const [_, prefix, restName] = propName.match(/(min|max)?(.+)/)
const normalizedName = toLowerCaseFirst(restName)

return { prefix, name: normalizedName, value }
})
}
35 changes: 17 additions & 18 deletions packages/atomic-layout/src/hooks/useMediaQuery.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useState, useMemo, useLayoutEffect } from 'react'
import {
MediaQuery as MediaQueryParams,
compose,
joinQueryList,
normalizeQuery,
transformNumeric,
Expand All @@ -11,24 +10,24 @@ import {
* Creates a media querty string based on the given params.
*/
const createMediaQuery = (queryParams: MediaQueryParams): string => {
return compose(
joinQueryList(([paramName, paramValue]) => {
/**
* Transform values that begin with a number to prevent
* transformations of "calc" expressions.
* Transformation of numerics is necessary when a simple
* number is used as a value (min-width: 750) is not valid.
*
* (min-width: 750) ==> (min-width: 750px)
*/
const resolvedParamValue = /^\d/.test(String(paramValue))
? transformNumeric(paramValue)
: paramValue
const queryList = normalizeQuery(queryParams)
const mediaQueryString = joinQueryList(queryList, ({ name, value }) => {
/**
* Transform values that begin with a number to prevent
* transformations of "calc" expressions.
* Transformation of numerics is necessary when a simple
* number is used as a value (min-width: 750) is not valid.
*
* (min-width: 750) ==> (min-width: 750px)
*/
const resolvedParamValue = /^\d/.test(String(value))
? transformNumeric(value)
: value

return `(${paramName}:${resolvedParamValue})`
}),
normalizeQuery,
)(queryParams)
return `(${name}:${resolvedParamValue})`
})

return mediaQueryString
}

type UseMediaQuery = (
Expand Down

0 comments on commit 85c57d2

Please sign in to comment.