Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import { type ReactNode, createContext, useContext } from 'react';
import { useViewportSize } from '@react-aria/utils';
import { breakpoints } from './tokens';
type TResponsiveContext = {
atLeastMediumWidth: boolean;
isNarrowWidth: boolean;
isSmallWidth: boolean;
isMediumWidth: boolean;
isWideWidth: boolean;
height: number;
width: number;
};
const ResponsiveContext = createContext<TResponsiveContext>(null);
export function ResponsiveProvider(props: { children: ReactNode }) {
/*
* Ensure we render on every viewport size change,
* even though we're interested in document.documentElement.client<Width|Height>
* clientWidth/Height are the document size, do not change on pinch-zoom,
* and are what our `min-width` media queries are reading
* Viewport size changes on pinch-zoom, which may be useful later when dealing with on-screen keyboards
*/
useViewportSize();
const height = document.documentElement.clientHeight;
const width = document.documentElement.clientWidth;
// Possible view modes: narrow, small, medium, wide
// To check if we're at least small width, check !isNarrowWidth
const viewportInfo = {
// atLeastMediumWidth is provided to avoid checking (isMediumWidth || isWideWidth)
atLeastMediumWidth: width >= breakpoints.medium,
isNarrowWidth: width < breakpoints.small,
isSmallWidth: width >= breakpoints.small && width < breakpoints.medium,
isMediumWidth: width >= breakpoints.medium && width < breakpoints.wide,
// No atLeastWideWidth because that's identical to isWideWidth
isWideWidth: width >= breakpoints.wide,
height,
width,
};
return (
<ResponsiveContext.Provider value={viewportInfo}>
{props.children}
</ResponsiveContext.Provider>
);
}
export function useResponsive() {
return useContext(ResponsiveContext);
}