UNPKG

@react-md/utils

Version:
179 lines 6.7 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; import { ResizeObserver } from "@juggle/resize-observer"; import { useEnsuredRef } from "../useEnsuredRef"; import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect"; /** * @internal */ function isHeightChange(prevSize, nextSize) { return (!prevSize || prevSize.height !== nextSize.height || prevSize.scrollHeight !== nextSize.scrollHeight); } /** * @internal */ function isWidthChange(prevSize, nextSize) { return (!prevSize || prevSize.width !== nextSize.width || prevSize.scrollWidth !== nextSize.scrollWidth); } /** * Why is there a single shared observer instead of multiple and a * "subscription" model? * * Note: Probably a bit of a premature optimization right now... * * @see https://github.com/WICG/resize-observer/issues/59 * @internal */ var sharedObserver; /** * * @internal */ var subscriptions = []; /** * Lazy initializes the shared resize observer which will loop through all the * subscriptions when a resize event is called. * * @internal */ function init() { if (sharedObserver || typeof document === "undefined") { return; } sharedObserver = new ResizeObserver(function (entries) { var _loop_1 = function (i) { var entry = entries[i]; var currentSubscriptions = subscriptions.filter(function (_a) { var target = _a.target; return target === entry.target; }); if (!currentSubscriptions.length) { return { value: void 0 }; } var _a = entry.contentRect, height = _a.height, width = _a.width; var _b = entry.target, scrollHeight = _b.scrollHeight, scrollWidth = _b.scrollWidth; var nextSize = { height: height, width: width, scrollHeight: scrollHeight, scrollWidth: scrollWidth, }; for (var j = 0; j < currentSubscriptions.length; j += 1) { var subscription = currentSubscriptions[j]; var handler = subscription.handler, prevSize = subscription.prevSize, disableHeight = subscription.disableHeight, disableWidth = subscription.disableWidth; var isNewHeight = isHeightChange(prevSize, nextSize); var isNewWidth = isWidthChange(prevSize, nextSize); if ((isNewHeight && !disableHeight) || (isNewWidth && !disableWidth)) { subscription.prevSize = nextSize; handler(__assign(__assign({}, nextSize), { element: entry.target })); } } }; // Note: might need to wait until an requestAnimationFrame has completed to // fix the resize observer loop exceeded error if switching to // `useIsomorphicLayoutEffect` and a shared observer didn't fix that error: // https://stackoverflow.com/questions/49384120/resizeobserver-loop-limit-exceeded for (var i = 0; i < entries.length; i += 1) { var state_1 = _loop_1(i); if (typeof state_1 === "object") return state_1.value; } }); } /** * * @internal */ function subscribe(target, onResize, disableHeight, disableWidth) { var exists = subscriptions.find(function (sub) { return sub.target === target; }); subscriptions.push({ target: target, handler: onResize, disableWidth: disableWidth, disableHeight: disableHeight, prevSize: undefined, }); if (!exists) { // I'll silently fail non-initialized observers for now until it becomes an // issue... But how will I ever know? sharedObserver === null || sharedObserver === void 0 ? void 0 : sharedObserver.observe(target); } } /** * * @internal */ function unsubscribe(target, onResize, disableHeight, disableWidth) { var i = subscriptions.findIndex(function (sub) { return sub.target === target && sub.handler === onResize && sub.disableWidth === disableWidth && sub.disableHeight === disableHeight; }); if (i !== -1) { subscriptions.splice(i, 1); } var remaining = subscriptions.some(function (sub) { return sub.target === target; }); if (!remaining) { // I'll silently fail non-initialized observers for now until it becomes an // issue... But how will I ever know? sharedObserver === null || sharedObserver === void 0 ? void 0 : sharedObserver.unobserve(target); } } /** * The new resize observer API that returns a `refHandler` to attach to a DOM * node instead of using the weird `target` API. * * @remarks \@since 2.3.0 * @param onResize - The resize handler to call when the element has changed * height or width. If you notice performance issues or other oddities, it is * recommended to wrap this function in `useCallback`. * @param options - Any additional options to use for the resize observer. */ export function useResizeObserver(onResize, options) { if (options === void 0) { options = {}; } var propRef = options.ref, _a = options.disableWidth, disableWidth = _a === void 0 ? false : _a, _b = options.disableHeight, disableHeight = _b === void 0 ? false : _b; var _c = __read(useEnsuredRef(propRef), 2), ref = _c[0], refHandler = _c[1]; useIsomorphicLayoutEffect(function () { var target = ref.current; if ((disableHeight && disableWidth) || !target) { return; } init(); subscribe(target, onResize, disableHeight, disableWidth); return function () { unsubscribe(target, onResize, disableHeight, disableWidth); }; }, [disableHeight, disableWidth, onResize]); return [ref, refHandler]; } //# sourceMappingURL=useResizeObserver.js.map