@w11r/use-breakpoint
Version:
React useBreakpoint hook to have different values for a variable based on a breakpoints.
75 lines (64 loc) • 2.83 kB
JavaScript
import { useContext, useMemo } from 'react';
import { options, LANDSCAPE, PORTRAIT } from '.';
import { Context } from "./provider";
// We will save the calculated value until innerWidth changes
let cachedProplessValue = {};
const calculateProplessValue = function calculateProplessValue(iw, ih) {
const key = `${iw}${ih}`;
if (cachedProplessValue[key]) return cachedProplessValue[key];
const isLandscape = iw > ih;
const proplessValue = {
isLandscape,
isPortrait: !isLandscape,
isHDPI: typeof window !== 'undefined' && window.devicePixelRatio > 1,
innerWidth: iw,
innerHeight: ih,
media: {}
}; // @ts-ignore
for (const [k, [from, to]] of Object.entries(options.breakpoints)) {
// It's a prefix breakpoint, no need to process
if (from === true) continue;
const [firstLetter, secondLetter, ...restLetter] = k;
const isOrientedLandscape = LANDSCAPE === firstLetter;
const isOrientedPortrait = PORTRAIT === firstLetter;
const isOriented = isOrientedLandscape || isOrientedPortrait;
const key = isOriented ? `${firstLetter}${secondLetter.toUpperCase()}${restLetter.join('')}` : `${firstLetter.toUpperCase()}${secondLetter}${restLetter.join('')}`;
proplessValue[`is${key}`] = iw > from && iw <= to && (!isOriented || isOrientedLandscape && isLandscape || isOrientedPortrait && !isLandscape);
proplessValue.media[k] = `(min-width: ${from}px) and (max-width: ${to}px)`;
}
cachedProplessValue[key] = proplessValue;
return proplessValue;
};
/* eslint-disable no-continue */
export const calculateValue = function calculateValue(defaultValue) {
let breakpointValues = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
let iw = arguments.length > 2 ? arguments[2] : undefined;
let ih = arguments.length > 3 ? arguments[3] : undefined;
if (defaultValue === undefined && !breakpointValues.length) {
return calculateProplessValue(iw, ih);
}
const isLandscape = iw > ih;
if (!breakpointValues || !breakpointValues.length) {
return defaultValue;
}
if (typeof breakpointValues[0] === 'string') {
// @ts-ignore
breakpointValues = [breakpointValues]; // eslint-disable-line
}
for (const [key, value] of breakpointValues) {
if (!options.breakpoints[key]) continue;
const bp = options.breakpoints[key];
if (isLandscape && key[0] === PORTRAIT) continue;
if (!isLandscape && key[0] === LANDSCAPE) continue;
if (iw >= bp[0] && iw <= bp[1]) return value;
}
return defaultValue;
};
export function useBreakpoint(defaultValue, breakpointValues) {
const {
innerWidth,
innerHeight
} = useContext(Context);
return useMemo(() => calculateValue(defaultValue, breakpointValues, innerWidth, innerHeight), [innerWidth, innerHeight, defaultValue]);
}
export default useBreakpoint;