@restart/hooks
Version:
A set of utility and general-purpose React hooks.
123 lines (119 loc) • 3.85 kB
JavaScript
exports.__esModule = true;
exports.createBreakpointHook = createBreakpointHook;
exports.default = void 0;
var _useMediaQuery = _interopRequireDefault(require("./useMediaQuery"));
var _react = require("react");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Create a responsive hook we a set of breakpoint names and widths.
* You can use any valid css units as well as a numbers (for pixels).
*
* **NOTE:** The object key order is important! it's assumed to be in order from smallest to largest
*
* ```ts
* const useBreakpoint = createBreakpointHook({
* xs: 0,
* sm: 576,
* md: 768,
* lg: 992,
* xl: 1200,
* })
* ```
*
* **Watch out!** using string values will sometimes construct media queries using css `calc()` which
* is NOT supported in media queries by all browsers at the moment. use numbers for
* the widest range of browser support.
*
* @param breakpointValues A object hash of names to breakpoint dimensions
*/
function createBreakpointHook(breakpointValues) {
const names = Object.keys(breakpointValues);
function and(query, next) {
if (query === next) {
return next;
}
return query ? `${query} and ${next}` : next;
}
function getNext(breakpoint) {
return names[Math.min(names.indexOf(breakpoint) + 1, names.length - 1)];
}
function getMaxQuery(breakpoint) {
const next = getNext(breakpoint);
let value = breakpointValues[next];
if (typeof value === 'number') value = `${value - 0.2}px`;else value = `calc(${value} - 0.2px)`;
return `(max-width: ${value})`;
}
function getMinQuery(breakpoint) {
let value = breakpointValues[breakpoint];
if (typeof value === 'number') {
value = `${value}px`;
}
return `(min-width: ${value})`;
}
/**
* Match a set of breakpoints
*
* ```tsx
* const MidSizeOnly = () => {
* const isMid = useBreakpoint({ lg: 'down', sm: 'up' });
*
* if (isMid) return <div>On a Reasonable sized Screen!</div>
* return null;
* }
* ```
* @param breakpointMap An object map of breakpoints and directions, queries are constructed using "and" to join
* breakpoints together
* @param window Optionally specify the target window to match against (useful when rendering into iframes)
*/
/**
* Match a single breakpoint exactly, up, or down.
*
* ```tsx
* const PhoneOnly = () => {
* const isSmall = useBreakpoint('sm', 'down');
*
* if (isSmall) return <div>On a Small Screen!</div>
* return null;
* }
* ```
*
* @param breakpoint The breakpoint key
* @param direction A direction 'up' for a max, 'down' for min, true to match only the breakpoint
* @param window Optionally specify the target window to match against (useful when rendering into iframes)
*/
function useBreakpoint(breakpointOrMap, direction, window) {
let breakpointMap;
if (typeof breakpointOrMap === 'object') {
breakpointMap = breakpointOrMap;
window = direction;
direction = true;
} else {
direction = direction || true;
breakpointMap = {
[breakpointOrMap]: direction
};
}
let query = (0, _react.useMemo)(() => Object.entries(breakpointMap).reduce((query, [key, direction]) => {
if (direction === 'up' || direction === true) {
query = and(query, getMinQuery(key));
}
if (direction === 'down' || direction === true) {
query = and(query, getMaxQuery(key));
}
return query;
}, ''), [JSON.stringify(breakpointMap)]);
return (0, _useMediaQuery.default)(query, window);
}
return useBreakpoint;
}
const useBreakpoint = createBreakpointHook({
xs: 0,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
xxl: 1400
});
var _default = useBreakpoint;
exports.default = _default;
;