mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-09-21 13:22:35 +00:00
68 lines
1.6 KiB
TypeScript
68 lines
1.6 KiB
TypeScript
import { useLayoutEffect, useRef } from "react";
|
|
import ResizeObserver from "resize-observer-polyfill";
|
|
|
|
export function useResizeNotifier(
|
|
element: HTMLElement | undefined,
|
|
callback: () => void
|
|
) {
|
|
const callBackRef = useRef(callback);
|
|
useLayoutEffect(() => {
|
|
callBackRef.current = callback;
|
|
}, [callback]);
|
|
|
|
useLayoutEffect(() => {
|
|
if (!element) return;
|
|
|
|
const resizeObserver = new ResizeObserver(
|
|
withResizeLoopDetection(() => {
|
|
callBackRef.current!();
|
|
})
|
|
);
|
|
|
|
resizeObserver.observe(element);
|
|
|
|
return () => {
|
|
resizeObserver.disconnect();
|
|
};
|
|
}, [element]);
|
|
}
|
|
|
|
function withResizeLoopDetection(callback: () => void) {
|
|
return (entries: ResizeObserverEntry[], resizeObserver: ResizeObserver) => {
|
|
const elements = entries.map((entry) => entry.target);
|
|
|
|
const rectsBefore = elements.map((element) =>
|
|
element.getBoundingClientRect()
|
|
);
|
|
|
|
callback();
|
|
|
|
const rectsAfter = elements.map((element) =>
|
|
element.getBoundingClientRect()
|
|
);
|
|
|
|
const changedElements = elements.filter(
|
|
(_, i) => !areRectSizesEqual(rectsBefore[i], rectsAfter[i])
|
|
);
|
|
|
|
changedElements.forEach((element) =>
|
|
unobserveUntilNextFrame(element, resizeObserver)
|
|
);
|
|
};
|
|
}
|
|
|
|
function unobserveUntilNextFrame(
|
|
element: Element,
|
|
resizeObserver: ResizeObserver
|
|
) {
|
|
resizeObserver.unobserve(element);
|
|
|
|
requestAnimationFrame(() => {
|
|
resizeObserver.observe(element);
|
|
});
|
|
}
|
|
|
|
function areRectSizesEqual(rect1: DOMRect, rect2: DOMRect) {
|
|
return rect1.width === rect2.width && rect1.height === rect2.height;
|
|
}
|