@intility/bifrost-react
Version:
React library for Intility's design system, Bifrost.
115 lines (112 loc) • 3.61 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
"use client";
import { c as _c } from "react-compiler-runtime";
import useLayoutEffect from "./useIsomorphicLayoutEffect.js";
import useEffectEvent from "./useEffectEvent.js";
// stolen from https://github.com/jaredLunde/react-hook/tree/master/packages/resize-observer
// reworked slightly since it caused crashes when building static site for next.js
// for some reason they think polyfilling should be the responsibility of the consumer for SSR/RSC
// but we want bifrost to be ssr friendly out of the box https://github.com/jaredLunde/react-hook/issues/310
/**
* A React hook that fires a callback whenever ResizeObserver detects a change to its size
*
* @param target A React ref created by `useRef()` or an HTML element
* @param callback Invoked with a single `ResizeObserverEntry` any time
* the `target` resizes
*/
function useResizeObserver(target, callback, t0) {
const $ = _c(9);
let t1;
if ($[0] !== t0) {
t1 = t0 === undefined ? {} : t0;
$[0] = t0;
$[1] = t1;
} else {
t1 = $[1];
}
const options = t1;
const callbackEvent = useEffectEvent(callback);
let t2;
if ($[2] !== callbackEvent || $[3] !== options.polyfill || $[4] !== target) {
t2 = () => {
const resizeObserver = getResizeObserver(options.polyfill);
let didUnsubscribe = false;
const targetEl = target && "current" in target ? target.current : target;
if (!targetEl) {
return;
}
const cb = function cb(entry, observer) {
if (didUnsubscribe) {
return;
}
callbackEvent(entry, observer);
};
resizeObserver.subscribe(targetEl, cb);
return () => {
didUnsubscribe = true;
resizeObserver.unsubscribe(targetEl, cb);
};
};
$[2] = callbackEvent;
$[3] = options.polyfill;
$[4] = target;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== options.polyfill || $[7] !== target) {
t3 = [target, options.polyfill];
$[6] = options.polyfill;
$[7] = target;
$[8] = t3;
} else {
t3 = $[8];
}
useLayoutEffect(t2, t3);
}
function createResizeObserver(polyfill) {
let ticking = false;
let allEntries = [];
const callbacks = new Map();
const observer = new (polyfill || window.ResizeObserver)((entries, obs) => {
allEntries = allEntries.concat(entries);
if (!ticking) {
window.requestAnimationFrame(() => {
const triggered = new Set();
for (let i = 0; i < allEntries.length; i++) {
if (triggered.has(allEntries[i].target)) continue;
triggered.add(allEntries[i].target);
const cbs = callbacks.get(allEntries[i].target);
cbs?.forEach(cb => cb(allEntries[i], obs));
}
allEntries = [];
ticking = false;
});
}
ticking = true;
});
return {
observer,
subscribe(target, callback) {
observer.observe(target);
const cbs = callbacks.get(target) ?? [];
cbs.push(callback);
callbacks.set(target, cbs);
},
unsubscribe(target, callback) {
const cbs = callbacks.get(target) ?? [];
if (cbs.length === 1) {
observer.unobserve(target);
callbacks.delete(target);
return;
}
const cbIndex = cbs.indexOf(callback);
if (cbIndex !== -1) cbs.splice(cbIndex, 1);
callbacks.set(target, cbs);
}
};
}
let _resizeObserver;
const getResizeObserver = polyfill => !_resizeObserver ? _resizeObserver = createResizeObserver(polyfill) : _resizeObserver;
export default useResizeObserver;