UNPKG

3.22 kBJavaScriptView Raw
1import useMediaQuery from './useMediaQuery';
2import { useMemo } from 'react';
3
4/**
5 * Create a responsive hook we a set of breakpoint names and widths.
6 * You can use any valid css units as well as a numbers (for pixels).
7 *
8 * **NOTE:** The object key order is important! it's assumed to be in order from smallest to largest
9 *
10 * ```ts
11 * const useBreakpoint = createBreakpointHook({
12 * xs: 0,
13 * sm: 576,
14 * md: 768,
15 * lg: 992,
16 * xl: 1200,
17 * })
18 * ```
19 *
20 * **Watch out!** using string values will sometimes construct media queries using css `calc()` which
21 * is NOT supported in media queries by all browsers at the moment. use numbers for
22 * the widest range of browser support.
23 *
24 * @param breakpointValues A object hash of names to breakpoint dimensions
25 */
26export function createBreakpointHook(breakpointValues) {
27 var names = Object.keys(breakpointValues);
28
29 function and(query, next) {
30 if (query === next) {
31 return next;
32 }
33
34 return query ? query + " and " + next : next;
35 }
36
37 function getNext(breakpoint) {
38 return names[Math.min(names.indexOf(breakpoint) + 1, names.length - 1)];
39 }
40
41 function getMaxQuery(breakpoint) {
42 var next = getNext(breakpoint);
43 var value = breakpointValues[next];
44 if (typeof value === 'number') value = value - 0.2 + "px";else value = "calc(" + value + " - 0.2px)";
45 return "(max-width: " + value + ")";
46 }
47
48 function getMinQuery(breakpoint) {
49 var value = breakpointValues[breakpoint];
50
51 if (typeof value === 'number') {
52 value = value + "px";
53 }
54
55 return "(min-width: " + value + ")";
56 }
57 /**
58 * Match a set of breakpoints
59 *
60 * ```tsx
61 * const MidSizeOnly = () => {
62 * const isMid = useBreakpoint({ lg: 'down', sm: 'up' });
63 *
64 * if (isMid) return <div>On a Reasonable sized Screen!</div>
65 * return null;
66 * }
67 * ```
68 * @param breakpointMap An object map of breakpoints and directions, queries are constructed using "and" to join
69 * breakpoints together
70 * @param window Optionally specify the target window to match against (useful when rendering into iframes)
71 */
72
73
74 function useBreakpoint(breakpointOrMap, direction, window) {
75 var breakpointMap;
76
77 if (typeof breakpointOrMap === 'object') {
78 breakpointMap = breakpointOrMap;
79 window = direction;
80 direction = true;
81 } else {
82 var _breakpointMap;
83
84 direction = direction || true;
85 breakpointMap = (_breakpointMap = {}, _breakpointMap[breakpointOrMap] = direction, _breakpointMap);
86 }
87
88 var query = useMemo(function () {
89 return Object.entries(breakpointMap).reduce(function (query, _ref) {
90 var key = _ref[0],
91 direction = _ref[1];
92
93 if (direction === 'up' || direction === true) {
94 query = and(query, getMinQuery(key));
95 }
96
97 if (direction === 'down' || direction === true) {
98 query = and(query, getMaxQuery(key));
99 }
100
101 return query;
102 }, '');
103 }, [JSON.stringify(breakpointMap)]);
104 return useMediaQuery(query, window);
105 }
106
107 return useBreakpoint;
108}
109var useBreakpoint = createBreakpointHook({
110 xs: 0,
111 sm: 576,
112 md: 768,
113 lg: 992,
114 xl: 1200,
115 xxl: 1400
116});
117export default useBreakpoint;
\No newline at end of file