UNPKG

4.03 kBJavaScriptView Raw
1import React from 'react';
2import { useToken } from '../theme/internal';
3export const responsiveArray = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
4const getResponsiveMap = token => ({
5 xs: `(max-width: ${token.screenXSMax}px)`,
6 sm: `(min-width: ${token.screenSM}px)`,
7 md: `(min-width: ${token.screenMD}px)`,
8 lg: `(min-width: ${token.screenLG}px)`,
9 xl: `(min-width: ${token.screenXL}px)`,
10 xxl: `(min-width: ${token.screenXXL}px)`
11});
12/**
13 * Ensures that the breakpoints token are valid, in good order
14 * For each breakpoint : screenMin <= screen <= screenMax and screenMax <= nextScreenMin
15 */
16const validateBreakpoints = token => {
17 const indexableToken = token;
18 const revBreakpoints = [].concat(responsiveArray).reverse();
19 revBreakpoints.forEach((breakpoint, i) => {
20 const breakpointUpper = breakpoint.toUpperCase();
21 const screenMin = `screen${breakpointUpper}Min`;
22 const screen = `screen${breakpointUpper}`;
23 if (!(indexableToken[screenMin] <= indexableToken[screen])) {
24 throw new Error(`${screenMin}<=${screen} fails : !(${indexableToken[screenMin]}<=${indexableToken[screen]})`);
25 }
26 if (i < revBreakpoints.length - 1) {
27 const screenMax = `screen${breakpointUpper}Max`;
28 if (!(indexableToken[screen] <= indexableToken[screenMax])) {
29 throw new Error(`${screen}<=${screenMax} fails : !(${indexableToken[screen]}<=${indexableToken[screenMax]})`);
30 }
31 const nextBreakpointUpperMin = revBreakpoints[i + 1].toUpperCase();
32 const nextScreenMin = `screen${nextBreakpointUpperMin}Min`;
33 if (!(indexableToken[screenMax] <= indexableToken[nextScreenMin])) {
34 throw new Error(`${screenMax}<=${nextScreenMin} fails : !(${indexableToken[screenMax]}<=${indexableToken[nextScreenMin]})`);
35 }
36 }
37 });
38 return token;
39};
40export default function useResponsiveObserver() {
41 const [, token] = useToken();
42 const responsiveMap = getResponsiveMap(validateBreakpoints(token));
43 // To avoid repeat create instance, we add `useMemo` here.
44 return React.useMemo(() => {
45 const subscribers = new Map();
46 let subUid = -1;
47 let screens = {};
48 return {
49 matchHandlers: {},
50 dispatch(pointMap) {
51 screens = pointMap;
52 subscribers.forEach(func => func(screens));
53 return subscribers.size >= 1;
54 },
55 subscribe(func) {
56 if (!subscribers.size) this.register();
57 subUid += 1;
58 subscribers.set(subUid, func);
59 func(screens);
60 return subUid;
61 },
62 unsubscribe(paramToken) {
63 subscribers.delete(paramToken);
64 if (!subscribers.size) this.unregister();
65 },
66 unregister() {
67 Object.keys(responsiveMap).forEach(screen => {
68 const matchMediaQuery = responsiveMap[screen];
69 const handler = this.matchHandlers[matchMediaQuery];
70 handler === null || handler === void 0 ? void 0 : handler.mql.removeListener(handler === null || handler === void 0 ? void 0 : handler.listener);
71 });
72 subscribers.clear();
73 },
74 register() {
75 Object.keys(responsiveMap).forEach(screen => {
76 const matchMediaQuery = responsiveMap[screen];
77 const listener = _ref => {
78 let {
79 matches
80 } = _ref;
81 this.dispatch(Object.assign(Object.assign({}, screens), {
82 [screen]: matches
83 }));
84 };
85 const mql = window.matchMedia(matchMediaQuery);
86 mql.addListener(listener);
87 this.matchHandlers[matchMediaQuery] = {
88 mql,
89 listener
90 };
91 listener(mql);
92 });
93 },
94 responsiveMap
95 };
96 }, [token]);
97}
98export const matchScreen = (screens, screenSizes) => {
99 if (screenSizes && typeof screenSizes === 'object') {
100 for (let i = 0; i < responsiveArray.length; i++) {
101 const breakpoint = responsiveArray[i];
102 if (screens[breakpoint] && screenSizes[breakpoint] !== undefined) {
103 return screenSizes[breakpoint];
104 }
105 }
106 }
107};
\No newline at end of file