116 lines
4.3 KiB
JavaScript
116 lines
4.3 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = useResponsiveObserver;
|
||
|
exports.responsiveArray = exports.matchScreen = void 0;
|
||
|
var _react = _interopRequireDefault(require("react"));
|
||
|
var _internal = require("../theme/internal");
|
||
|
const responsiveArray = exports.responsiveArray = ['xxl', 'xl', 'lg', 'md', 'sm', 'xs'];
|
||
|
const getResponsiveMap = token => ({
|
||
|
xs: `(max-width: ${token.screenXSMax}px)`,
|
||
|
sm: `(min-width: ${token.screenSM}px)`,
|
||
|
md: `(min-width: ${token.screenMD}px)`,
|
||
|
lg: `(min-width: ${token.screenLG}px)`,
|
||
|
xl: `(min-width: ${token.screenXL}px)`,
|
||
|
xxl: `(min-width: ${token.screenXXL}px)`
|
||
|
});
|
||
|
/**
|
||
|
* Ensures that the breakpoints token are valid, in good order
|
||
|
* For each breakpoint : screenMin <= screen <= screenMax and screenMax <= nextScreenMin
|
||
|
*/
|
||
|
const validateBreakpoints = token => {
|
||
|
const indexableToken = token;
|
||
|
const revBreakpoints = [].concat(responsiveArray).reverse();
|
||
|
revBreakpoints.forEach((breakpoint, i) => {
|
||
|
const breakpointUpper = breakpoint.toUpperCase();
|
||
|
const screenMin = `screen${breakpointUpper}Min`;
|
||
|
const screen = `screen${breakpointUpper}`;
|
||
|
if (!(indexableToken[screenMin] <= indexableToken[screen])) {
|
||
|
throw new Error(`${screenMin}<=${screen} fails : !(${indexableToken[screenMin]}<=${indexableToken[screen]})`);
|
||
|
}
|
||
|
if (i < revBreakpoints.length - 1) {
|
||
|
const screenMax = `screen${breakpointUpper}Max`;
|
||
|
if (!(indexableToken[screen] <= indexableToken[screenMax])) {
|
||
|
throw new Error(`${screen}<=${screenMax} fails : !(${indexableToken[screen]}<=${indexableToken[screenMax]})`);
|
||
|
}
|
||
|
const nextBreakpointUpperMin = revBreakpoints[i + 1].toUpperCase();
|
||
|
const nextScreenMin = `screen${nextBreakpointUpperMin}Min`;
|
||
|
if (!(indexableToken[screenMax] <= indexableToken[nextScreenMin])) {
|
||
|
throw new Error(`${screenMax}<=${nextScreenMin} fails : !(${indexableToken[screenMax]}<=${indexableToken[nextScreenMin]})`);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
return token;
|
||
|
};
|
||
|
function useResponsiveObserver() {
|
||
|
const [, token] = (0, _internal.useToken)();
|
||
|
const responsiveMap = getResponsiveMap(validateBreakpoints(token));
|
||
|
// To avoid repeat create instance, we add `useMemo` here.
|
||
|
return _react.default.useMemo(() => {
|
||
|
const subscribers = new Map();
|
||
|
let subUid = -1;
|
||
|
let screens = {};
|
||
|
return {
|
||
|
matchHandlers: {},
|
||
|
dispatch(pointMap) {
|
||
|
screens = pointMap;
|
||
|
subscribers.forEach(func => func(screens));
|
||
|
return subscribers.size >= 1;
|
||
|
},
|
||
|
subscribe(func) {
|
||
|
if (!subscribers.size) this.register();
|
||
|
subUid += 1;
|
||
|
subscribers.set(subUid, func);
|
||
|
func(screens);
|
||
|
return subUid;
|
||
|
},
|
||
|
unsubscribe(paramToken) {
|
||
|
subscribers.delete(paramToken);
|
||
|
if (!subscribers.size) this.unregister();
|
||
|
},
|
||
|
unregister() {
|
||
|
Object.keys(responsiveMap).forEach(screen => {
|
||
|
const matchMediaQuery = responsiveMap[screen];
|
||
|
const handler = this.matchHandlers[matchMediaQuery];
|
||
|
handler === null || handler === void 0 ? void 0 : handler.mql.removeListener(handler === null || handler === void 0 ? void 0 : handler.listener);
|
||
|
});
|
||
|
subscribers.clear();
|
||
|
},
|
||
|
register() {
|
||
|
Object.keys(responsiveMap).forEach(screen => {
|
||
|
const matchMediaQuery = responsiveMap[screen];
|
||
|
const listener = _ref => {
|
||
|
let {
|
||
|
matches
|
||
|
} = _ref;
|
||
|
this.dispatch(Object.assign(Object.assign({}, screens), {
|
||
|
[screen]: matches
|
||
|
}));
|
||
|
};
|
||
|
const mql = window.matchMedia(matchMediaQuery);
|
||
|
mql.addListener(listener);
|
||
|
this.matchHandlers[matchMediaQuery] = {
|
||
|
mql,
|
||
|
listener
|
||
|
};
|
||
|
listener(mql);
|
||
|
});
|
||
|
},
|
||
|
responsiveMap
|
||
|
};
|
||
|
}, [token]);
|
||
|
}
|
||
|
const matchScreen = (screens, screenSizes) => {
|
||
|
if (screenSizes && typeof screenSizes === 'object') {
|
||
|
for (let i = 0; i < responsiveArray.length; i++) {
|
||
|
const breakpoint = responsiveArray[i];
|
||
|
if (screens[breakpoint] && screenSizes[breakpoint] !== undefined) {
|
||
|
return screenSizes[breakpoint];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
exports.matchScreen = matchScreen;
|