UNPKG

react-resize-detector

Version:
106 lines (103 loc) 4.19 kB
import * as React from 'react'; import debounce from 'lodash/debounce.js'; import throttle from 'lodash/throttle.js'; /** * Wraps the resize callback with a lodash debounce / throttle based on the refresh mode */ const patchResizeCallback = (resizeCallback, refreshMode, refreshRate, refreshOptions) => { switch (refreshMode) { case 'debounce': return debounce(resizeCallback, refreshRate, refreshOptions); case 'throttle': return throttle(resizeCallback, refreshRate, refreshOptions); default: return resizeCallback; } }; /** * A custom hook that converts a callback to a ref to avoid triggering re-renders when passed as a * prop or avoid re-executing effects when passed as a dependency */ const useCallbackRef = // eslint-disable-next-line @typescript-eslint/no-explicit-any (callback) => { const callbackRef = React.useRef(callback); React.useEffect(() => { callbackRef.current = callback; }); return React.useMemo(() => ((...args) => { var _a; return (_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, ...args); }), []); }; /** `useRef` hook doesn't handle conditional rendering or dynamic ref changes. * This hook creates a proxy that ensures that `refElement` is updated whenever the ref is changed. */ const useRefProxy = // eslint-disable-next-line @typescript-eslint/no-explicit-any (targetRef) => { // we are going to use this ref to store the last element that was passed to the hook const [refElement, setRefElement] = React.useState((targetRef === null || targetRef === void 0 ? void 0 : targetRef.current) || null); // if targetRef is passed, we need to update the refElement // we have to use setTimeout because ref get assigned after the hook is called // in the future releases we are going to remove targetRef and force users to use ref returned by the hook if (targetRef) { setTimeout(() => { if (targetRef.current !== refElement) { setRefElement(targetRef.current); } }, 0); } // this is a memo that will be called every time the ref is changed // This proxy will properly call setState either when the ref is called as a function or when `.current` is set // we call setState inside to trigger rerender const refProxy = React.useMemo(() => new Proxy((node) => { if (node !== refElement) { setRefElement(node); } }, { get(target, prop) { if (prop === 'current') { return refElement; } return target[prop]; }, set(target, prop, value) { if (prop === 'current') { setRefElement(value); } else { target[prop] = value; } return true; }, }), [refElement]); return { refProxy, refElement, setRefElement }; }; /** Calculates the dimensions of the element based on the current box model. * @see https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/The_box_model */ const getDimensions = (entry, box) => { // Value Border Padding Inner Content // --------------------------------------------------- // 'border-box' Yes Yes Yes // 'content-box' No No Yes // undefined No No? Yes var _a, _b; const borderBox = (_a = entry.borderBoxSize) === null || _a === void 0 ? void 0 : _a[0]; const contentBox = (_b = entry.contentBoxSize) === null || _b === void 0 ? void 0 : _b[0]; if (box === 'border-box' && borderBox) { return { width: borderBox.inlineSize, height: borderBox.blockSize, }; } if (box === 'content-box' && contentBox) { return { width: contentBox.inlineSize, height: contentBox.blockSize, }; } return { width: entry.contentRect.width, height: entry.contentRect.height, }; }; export { getDimensions, patchResizeCallback, useCallbackRef, useRefProxy }; //# sourceMappingURL=utils.js.map