-
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ba295c7
commit e327095
Showing
8 changed files
with
268 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
packages/atomic-layout/src/utils/getBreakpointsByQuery.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { getBreakpointsByQuery } from './getBreakpointsByQuery' | ||
|
||
describe('getBreakpointsByQuery', () => { | ||
describe('given an exact breakpoint (for)', () => { | ||
let result: ReturnType<typeof getBreakpointsByQuery> | ||
|
||
beforeAll(() => { | ||
result = getBreakpointsByQuery({ for: 'md' }) | ||
}) | ||
|
||
it('should return a single enclosed breakpoint', () => { | ||
expect(result).toEqual([ | ||
{ | ||
minWidth: '768px', | ||
maxWidth: '991px', | ||
}, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('given a high-pass breakpoint range (from)', () => { | ||
let result: ReturnType<typeof getBreakpointsByQuery> | ||
|
||
beforeAll(() => { | ||
result = getBreakpointsByQuery({ from: 'sm' }) | ||
}) | ||
|
||
it('should return breakpoints for that high-pass range', () => { | ||
expect(result).toEqual([ | ||
{ | ||
minWidth: '576px', | ||
}, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('given a low-pass breakpoint range (to)', () => { | ||
let result: ReturnType<typeof getBreakpointsByQuery> | ||
|
||
beforeAll(() => { | ||
result = getBreakpointsByQuery({ to: 'md' }) | ||
}) | ||
|
||
it('should return breakpoints for that low-pass range', () => { | ||
expect(result).toEqual([ | ||
{ | ||
maxWidth: '767px', | ||
}, | ||
]) | ||
}) | ||
}) | ||
|
||
describe.only('given a bell breakpoint range (from/to)', () => { | ||
let result: ReturnType<typeof getBreakpointsByQuery> | ||
|
||
beforeAll(() => { | ||
result = getBreakpointsByQuery({ from: 'sm', to: 'lg' }) | ||
}) | ||
|
||
it('should return breakpoints for that inclusive range', () => { | ||
expect(result).toEqual([ | ||
{ | ||
minWidth: '576px', | ||
maxWidth: 'calc(992px - 1px)', | ||
}, | ||
]) | ||
}) | ||
}) | ||
|
||
describe('given a notch breakpoint range (except/from/to)', () => { | ||
let result: ReturnType<typeof getBreakpointsByQuery> | ||
|
||
beforeAll(() => { | ||
result = getBreakpointsByQuery({ except: true, from: 'sm', to: 'lg' }) | ||
}) | ||
|
||
it('should return breakpoints for that exclusive range', () => { | ||
expect(result).toEqual([ | ||
{ | ||
maxWidth: '575px', | ||
}, | ||
{ | ||
maxWidth: undefined, | ||
minWidth: '992px', | ||
}, | ||
]) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { | ||
mergeAreaRecords, | ||
Breakpoint, | ||
Layout, | ||
openBreakpoint, | ||
closeBreakpoint, | ||
} from '@atomic-layout/core' | ||
import { | ||
ResponsiveQueryParams, | ||
BreakpointRef, | ||
} from '../hooks/useResponsiveQuery' | ||
|
||
export const resolveBreakpoint = (breakpointRef: BreakpointRef): Breakpoint => { | ||
return typeof breakpointRef === 'string' | ||
? Layout.breakpoints[breakpointRef] | ||
: breakpointRef | ||
} | ||
|
||
/** | ||
* Returns a list of breakpoints based on a responsive query. | ||
* @example | ||
* getBreakpointsByQuery({ from: 'md' }) | ||
* // [{ minWidth: 768 }] | ||
* getBreakpointsByQuery({ from: 'sm', to: 'lg' }) | ||
* // [{ minWidth: 576 }, { maxWidth: 1199 }] | ||
*/ | ||
export const getBreakpointsByQuery = ( | ||
params: ResponsiveQueryParams, | ||
): Breakpoint[] => { | ||
const { for: exactBreakpoint, from, to, except } = params | ||
|
||
// Explicit breakpoint | ||
if (exactBreakpoint) { | ||
return [resolveBreakpoint(exactBreakpoint)] | ||
} | ||
|
||
const minBreakpoint = resolveBreakpoint(from) | ||
const maxBreakpoint = resolveBreakpoint(to) | ||
|
||
// Bell, __/--\__ | ||
if (minBreakpoint && maxBreakpoint && !except) { | ||
const mergedAreaRecord = mergeAreaRecords( | ||
{ | ||
behavior: 'down', | ||
breakpoint: maxBreakpoint, | ||
}, | ||
{ | ||
behavior: 'up', | ||
breakpoint: minBreakpoint, | ||
}, | ||
false, | ||
) | ||
|
||
return [mergedAreaRecord.breakpoint] | ||
} | ||
|
||
// Notch, --\__/-- | ||
if (minBreakpoint && maxBreakpoint && except) { | ||
return [closeBreakpoint(minBreakpoint), openBreakpoint(maxBreakpoint)] | ||
} | ||
|
||
// High-pass, __/-- | ||
if (minBreakpoint && !maxBreakpoint) { | ||
return [openBreakpoint(minBreakpoint)] | ||
} | ||
|
||
// Low-pass, --\__ | ||
if (!minBreakpoint && maxBreakpoint) { | ||
return [closeBreakpoint(maxBreakpoint)] | ||
} | ||
|
||
return [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { query } from './query' | ||
|
||
describe('query', () => { | ||
describe('given an exact breakpoint (for)', () => { | ||
let result: ReturnType<typeof query> | ||
|
||
beforeAll(() => { | ||
result = query({ for: 'md' }) | ||
}) | ||
|
||
it('should return an enclosed media query for the given breakpoint', () => { | ||
expect(result).toEqual('(min-width:768px) and (max-width:991px)') | ||
}) | ||
}) | ||
|
||
describe('given a high-pass breakpoint range (from)', () => { | ||
let result: ReturnType<typeof query> | ||
|
||
beforeAll(() => { | ||
result = query({ from: 'md' }) | ||
}) | ||
|
||
it('should return an enclosed media query for the given range', () => { | ||
expect(result).toEqual('(min-width:768px)') | ||
}) | ||
}) | ||
|
||
describe('given a low-pass breakpoint range (to)', () => { | ||
let result: ReturnType<typeof query> | ||
|
||
beforeAll(() => { | ||
result = query({ to: 'lg' }) | ||
}) | ||
|
||
it('should return an enclosed media query for the given range', () => { | ||
expect(result).toEqual('(max-width:991px)') | ||
}) | ||
}) | ||
|
||
describe('given a bell breakpoint range (from/to)', () => { | ||
let result: ReturnType<typeof query> | ||
|
||
beforeAll(() => { | ||
result = query({ from: 'sm', to: 'lg' }) | ||
}) | ||
|
||
it('should return an enclosed media query for the given range', () => { | ||
expect(result).toEqual( | ||
'(min-width:576px) and (max-width:calc(992px - 1px))', | ||
) | ||
}) | ||
}) | ||
|
||
describe('given a notch breakpoint range (except/from/to)', () => { | ||
let result: ReturnType<typeof query> | ||
|
||
beforeAll(() => { | ||
result = query({ except: true, from: 'sm', to: 'lg' }) | ||
}) | ||
|
||
it('should return an enclosed media query for the given range', () => { | ||
expect(result).toEqual('(max-width:575px),(min-width:992px)') | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { memoizeWith } from '@atomic-layout/core' | ||
import { createMediaQuery } from '../hooks/useMediaQuery' | ||
import { ResponsiveQueryParams } from '../hooks/useResponsiveQuery' | ||
import { getBreakpointsByQuery } from './getBreakpointsByQuery' | ||
|
||
const createQuery = (params: ResponsiveQueryParams): string => { | ||
const breakpoints = getBreakpointsByQuery(params) | ||
return breakpoints.map(createMediaQuery).join(params.except ? ',' : ' ') | ||
} | ||
|
||
/** | ||
* Converts a responsive query into a @media query string. | ||
* @example | ||
* query({ from: 'md' }) | ||
* // (min-width: 768px) | ||
* query({ from: 'sm', to: 'lg' }) | ||
* // (min-width: 576px) and (max-width: 1199px) | ||
* query({ for: 'md' }) | ||
* // (min-width: 768px) and (max-width: 991px) | ||
* query({ except: true, from: 'sm', to: 'lg' }) | ||
* // (max-width: 575px), (min-width: 992px) | ||
*/ | ||
export const query = memoizeWith<typeof createQuery>((params) => { | ||
return Object.entries(params) | ||
.filter(([, value]) => value != null) | ||
.reduce((acc, [key, value]) => { | ||
return acc.concat(`${key}=${value.toString()}`) | ||
}, []) | ||
.join() | ||
})(createQuery) |