Skip to content

Commit

Permalink
feat(hooks): add useValueBreakPoint hook
Browse files Browse the repository at this point in the history
  • Loading branch information
chornos13 committed Feb 18, 2021
1 parent c3fabac commit 4d4fedc
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/hooks/useValueBreakpoint/__mocks__/mockWindowMatchMedia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Breakpoint } from 'antd/lib/_util/responsiveObserve'
import { breakpoints } from 'hooks/useValueBreakpoint/useValueBreakpoint'

function mockWindowMatchMedia(breakpoint: Breakpoint | string) {
const mapQueryIndex = breakpoints.reduce((acc, curVal, index) => {
acc[curVal] = index
return acc
}, {})
// By jsdom mock, actual jsdom not implemented matchMedia
// https://jestjs.io/docs/en/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation((query) => {
return {
// mock matches to match screen, xs, sm, md, lg, xl and xxl
matches: [
'(max-width: 575px)',
'(min-width: 576px)',
'(min-width: 768px)',
'(min-width: 992px)',
'(min-width: 1200px)',
'(min-width: 1600px)',
]
.filter((value, index) => index <= mapQueryIndex[breakpoint])
.includes(query),
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
}
}),
})
}

export default mockWindowMatchMedia
26 changes: 26 additions & 0 deletions src/hooks/useValueBreakpoint/__test__/useValueBreakpoint.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { renderHook } from '@testing-library/react-hooks'
import useValueBreakpoint, {
breakpoints,
} from 'hooks/useValueBreakpoint/useValueBreakpoint'
import mockWindowMatchMedia from 'hooks/useValueBreakpoint/__mocks__/mockWindowMatchMedia'

describe('basic function', () => {
const configs = {
xs: 'anyXsValue',
sm: 'anySmValue',
md: 'anyMdValue',
lg: 'anyLgValue',
xl: 'anyXlValue',
xxl: 'anyXxlValue',
}

test.each(breakpoints)(
'should return value "%s" that match in breakpoint value',
(curScreen) => {
// arrange
mockWindowMatchMedia(curScreen)
const { result } = renderHook(() => useValueBreakpoint(configs))
expect(result.current.value).toBe(configs[curScreen])
},
)
})
3 changes: 3 additions & 0 deletions src/hooks/useValueBreakpoint/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import useValueBreakpoint from 'hooks/useValueBreakpoint/useValueBreakpoint'

export default useValueBreakpoint
33 changes: 33 additions & 0 deletions src/hooks/useValueBreakpoint/useValueBreakpoint.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import useBreakpoint from 'antd/lib/grid/hooks/useBreakpoint'
import { Breakpoint, ScreenMap } from 'antd/lib/_util/responsiveObserve'

export const breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl']
export const priorityBreakpoint = [...breakpoints].reverse()

type UseValueBreakpointConfigs<T> = {
[key in Breakpoint]?: T
}

function useValueBreakpoint<T>(
configs: UseValueBreakpointConfigs<T>,
): { screens: ScreenMap; value: T } {
const _configs = { ...configs }
const screenMap = useBreakpoint()
let value = _configs.xs
const curBreakpoints = priorityBreakpoint.map((key) => {
return [key, screenMap[key]]
})

for (let i = 0; i < curBreakpoints.length; i += 1) {
const [screen, isMatch] = curBreakpoints[i]

if (isMatch && Object.prototype.hasOwnProperty.call(_configs, screen)) {
value = _configs[screen]
break
}
}

return { screens: screenMap, value }
}

export default useValueBreakpoint

0 comments on commit 4d4fedc

Please sign in to comment.