@react-awesome/use-breakpoint
Version:
useBreakpoint triggers callback when a container's size is equal to one specific breakpoint.
97 lines (96 loc) • 2.95 kB
JavaScript
import { useState, useMemo, useCallback, useEffect } from "react";
import { smaller } from "../helpers/smaller/smaller.js";
import { smallerOrEqual } from "../helpers/smallerOrEqual/smallerOrEqual.js";
import { greater } from "../helpers/greater/greater.js";
import { greaterOrEqual } from "../helpers/greaterOrEqual/greaterOrEqual.js";
import { between } from "../helpers/between/between.js";
const DEFAULT_BREAKPOINTS = {
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
"2xl": 1536
};
function useBreakpoint(opts = {}) {
const {
breakpoints: BPS = DEFAULT_BREAKPOINTS,
callbacks,
fallbackValue,
containerEl
} = opts;
const [currentBreakpoint, setCurrentBreakpoint] = useState(fallbackValue);
const [el, setEl] = useState(null);
const BPS_VALUES_ARR = useMemo(
() => Object.values(BPS).sort((a, b) => a - b),
[BPS]
);
const BPS_BY_KEYS = useMemo(
() => Object.keys(BPS).reduce((obj, key) => {
const bpKey = BPS[key];
if (obj[bpKey]) {
throw new Error(
`Found two breakpoints has the same value: ${obj[bpKey]} and ${key}`
);
}
obj[bpKey] = key;
return obj;
}, {}),
[BPS]
);
const determineCurrentBreakpoint = useCallback(
({ width }) => {
let currentBp = BPS_VALUES_ARR[0];
for (let i = 0; i < BPS_VALUES_ARR.length; i++) {
currentBp = BPS_VALUES_ARR[i];
if (i === 0 && width <= currentBp) {
setCurrentBreakpoint(BPS_BY_KEYS[currentBp.toString()]);
break;
} else if (width > BPS_VALUES_ARR[i - 1] && width <= currentBp) {
setCurrentBreakpoint(BPS_BY_KEYS[currentBp.toString()]);
break;
} else if (i + 1 === BPS_VALUES_ARR.length && width > currentBp) {
setCurrentBreakpoint(BPS_BY_KEYS[currentBp.toString()]);
break;
}
}
return BPS_BY_KEYS[currentBp];
},
[BPS_BY_KEYS, BPS_VALUES_ARR]
);
useEffect(() => {
if (typeof containerEl === "undefined")
setEl(window.document.body);
else if (containerEl !== el)
setEl(containerEl);
}, [containerEl, el]);
useEffect(() => {
if (!el)
return;
const callback = (entries) => {
var _a;
const [entry] = entries;
const { width, height } = entry.contentRect;
const currentBp = determineCurrentBreakpoint({
width,
height
});
(_a = callbacks == null ? void 0 : callbacks[currentBp]) == null ? void 0 : _a.call(callbacks);
};
const resizeObserver = new ResizeObserver(callback);
resizeObserver.observe(el);
return () => {
resizeObserver.disconnect();
};
}, [callbacks, determineCurrentBreakpoint, el]);
return {
currentBreakpoint,
smaller: smaller(BPS, el),
smallerOrEqual: smallerOrEqual(BPS, el),
greater: greater(BPS, el),
greaterOrEqual: greaterOrEqual(BPS, el),
between: between(BPS, el)
};
}
export {
useBreakpoint
};