2024-09-03 18:43:59 -07:00
|
|
|
import useResizeObserver from "@react-hook/resize-observer";
|
|
|
|
|
import { useCallback, useRef, useState } from "react";
|
|
|
|
|
import { debounce } from "throttle-debounce";
|
2024-08-23 15:18:49 +08:00
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
/**
|
|
|
|
|
* Get the current dimensions for the specified element, and whether it is currently changing size. Update when the element resizes.
|
|
|
|
|
* @param ref The reference to the element to observe.
|
|
|
|
|
* @param delay The debounce delay to use for updating the dimensions.
|
|
|
|
|
* @returns The dimensions of the element, and direction in which the dimensions are changing.
|
|
|
|
|
*/
|
2024-08-23 15:18:49 +08:00
|
|
|
const useDimensions = (ref: React.RefObject<HTMLElement>, delay = 0) => {
|
|
|
|
|
const [dimensions, setDimensions] = useState<{
|
|
|
|
|
height: number | null;
|
|
|
|
|
width: number | null;
|
|
|
|
|
widthDirection?: string;
|
|
|
|
|
heightDirection?: string;
|
|
|
|
|
}>({
|
|
|
|
|
height: null,
|
|
|
|
|
width: null,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const previousDimensions = useRef<{ height: number | null; width: number | null }>({
|
|
|
|
|
height: null,
|
|
|
|
|
width: null,
|
|
|
|
|
});
|
|
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
const updateDimensions = useCallback((entry: ResizeObserverEntry) => {
|
|
|
|
|
const parentHeight = entry.contentRect.height;
|
|
|
|
|
const parentWidth = entry.contentRect.width;
|
2024-08-23 15:18:49 +08:00
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
let widthDirection = "";
|
|
|
|
|
let heightDirection = "";
|
2024-08-23 15:18:49 +08:00
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
if (previousDimensions.current.width !== null && previousDimensions.current.height !== null) {
|
|
|
|
|
if (parentWidth > previousDimensions.current.width) {
|
|
|
|
|
widthDirection = "expanding";
|
|
|
|
|
} else if (parentWidth < previousDimensions.current.width) {
|
|
|
|
|
widthDirection = "shrinking";
|
|
|
|
|
} else {
|
|
|
|
|
widthDirection = "unchanged";
|
2024-08-23 15:18:49 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
if (parentHeight > previousDimensions.current.height) {
|
|
|
|
|
heightDirection = "expanding";
|
|
|
|
|
} else if (parentHeight < previousDimensions.current.height) {
|
|
|
|
|
heightDirection = "shrinking";
|
|
|
|
|
} else {
|
|
|
|
|
heightDirection = "unchanged";
|
|
|
|
|
}
|
2024-08-23 15:18:49 +08:00
|
|
|
}
|
|
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
previousDimensions.current = { height: parentHeight, width: parentWidth };
|
|
|
|
|
|
|
|
|
|
setDimensions({ height: parentHeight, width: parentWidth, widthDirection, heightDirection });
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const fUpdateDimensions = useCallback(delay > 0 ? debounce(delay, updateDimensions) : updateDimensions, [
|
2024-08-23 15:18:49 +08:00
|
|
|
updateDimensions,
|
|
|
|
|
delay,
|
|
|
|
|
]);
|
|
|
|
|
|
2024-09-03 18:43:59 -07:00
|
|
|
useResizeObserver(ref, fUpdateDimensions);
|
2024-08-23 15:18:49 +08:00
|
|
|
|
|
|
|
|
return dimensions;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export { useDimensions };
|