2023-12-15 16:24:50 -07:00
|
|
|
import { MutableRefObject, useEffect, useMemo, useState } from "react";
|
|
|
|
|
|
2024-03-05 14:19:56 -06:00
|
|
|
type RefType = MutableRefObject<Element | null> | Window;
|
|
|
|
|
|
|
|
|
|
export function useResizeObserver(...refs: RefType[]) {
|
|
|
|
|
const [dimensions, setDimensions] = useState<
|
|
|
|
|
{ width: number; height: number; x: number; y: number }[]
|
|
|
|
|
>(
|
2023-12-15 16:24:50 -07:00
|
|
|
new Array(refs.length).fill({
|
|
|
|
|
width: 0,
|
|
|
|
|
height: 0,
|
|
|
|
|
x: -Infinity,
|
|
|
|
|
y: -Infinity,
|
2024-02-28 15:23:56 -07:00
|
|
|
}),
|
2023-12-15 16:24:50 -07:00
|
|
|
);
|
|
|
|
|
const resizeObserver = useMemo(
|
|
|
|
|
() =>
|
|
|
|
|
new ResizeObserver((entries) => {
|
|
|
|
|
window.requestAnimationFrame(() => {
|
2025-02-10 10:42:35 -06:00
|
|
|
setDimensions((prevDimensions) => {
|
|
|
|
|
const newDimensions = entries.map((entry) => entry.contentRect);
|
|
|
|
|
if (
|
|
|
|
|
JSON.stringify(prevDimensions) !== JSON.stringify(newDimensions)
|
|
|
|
|
) {
|
|
|
|
|
return newDimensions;
|
|
|
|
|
}
|
|
|
|
|
return prevDimensions;
|
|
|
|
|
});
|
2023-12-15 16:24:50 -07:00
|
|
|
});
|
|
|
|
|
}),
|
2024-02-28 15:23:56 -07:00
|
|
|
[],
|
2023-12-15 16:24:50 -07:00
|
|
|
);
|
|
|
|
|
|
2026-03-05 08:42:38 -06:00
|
|
|
// Resolve refs to actual DOM elements for use as stable effect dependencies.
|
|
|
|
|
// Rest params create a new array each call, but the underlying elements are
|
|
|
|
|
// stable DOM nodes, so spreading them into the dep array avoids re-running
|
|
|
|
|
// the effect on every render.
|
|
|
|
|
const elements = refs.map((ref) =>
|
|
|
|
|
ref instanceof Window ? document.body : ref.current,
|
|
|
|
|
);
|
|
|
|
|
|
2023-12-15 16:24:50 -07:00
|
|
|
useEffect(() => {
|
2026-03-05 08:42:38 -06:00
|
|
|
elements.forEach((el) => {
|
|
|
|
|
if (el) resizeObserver.observe(el);
|
2023-12-15 16:24:50 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return () => {
|
2026-03-05 08:42:38 -06:00
|
|
|
resizeObserver.disconnect();
|
2023-12-15 16:24:50 -07:00
|
|
|
};
|
2026-03-05 08:42:38 -06:00
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, [...elements, resizeObserver]);
|
2023-12-15 16:24:50 -07:00
|
|
|
|
2024-05-09 15:06:29 -06:00
|
|
|
if (dimensions.length == refs.length) {
|
|
|
|
|
return dimensions;
|
|
|
|
|
} else {
|
|
|
|
|
const items = [...dimensions];
|
|
|
|
|
for (let i = dimensions.length; i < refs.length; i++) {
|
|
|
|
|
items.push({
|
|
|
|
|
width: 0,
|
|
|
|
|
height: 0,
|
|
|
|
|
x: -Infinity,
|
|
|
|
|
y: -Infinity,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return items;
|
|
|
|
|
}
|
2023-12-15 16:24:50 -07:00
|
|
|
}
|