@coinmeca/ui
Version:
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
66 lines • 2.47 kB
JavaScript
'use client';
import { useState, useLayoutEffect } from 'react';
import { throttle } from '../lib/utils';
const emptyRect = () => ({
top: 0,
bottom: 0,
left: 0,
right: 0,
width: 0,
height: 0,
x: 0,
y: 0,
toJSON: () => undefined,
});
const sameRect = (left, right) => !!left &&
!!right &&
left.top === right.top &&
left.bottom === right.bottom &&
left.left === right.left &&
left.right === right.right &&
left.width === right.width &&
left.height === right.height &&
left.x === right.x &&
left.y === right.y;
// Utility function to find all scrollable parents
function getScrollableParents(element) {
const scrollableParents = [];
let parent = element?.parentElement;
while (parent) {
const overflowY = window.getComputedStyle(parent).overflowY;
if (overflowY === 'scroll' || overflowY === 'auto') {
scrollableParents.push(parent);
}
parent = parent.parentElement;
}
return scrollableParents;
}
export default function usePositionTracker(ref, throttleTime = 0.1) {
const [position, setPosition] = useState(ref?.current?.getBoundingClientRect() || emptyRect());
useLayoutEffect(() => {
const element = ref.current;
if (!element)
return;
const scrollableParents = getScrollableParents(element);
const interval = throttleTime < 1 ? throttleTime * 1000 : throttleTime;
const update = throttle(() => {
const next = element.getBoundingClientRect();
setPosition((current) => (sameRect(current, next) ? current : next));
}, interval);
scrollableParents.forEach((parent) => parent.addEventListener('scroll', update));
window.addEventListener('resize', update);
window.addEventListener('scroll', update);
window.addEventListener('orientationchange', update);
document.addEventListener('visibilitychange', update);
update();
return () => {
scrollableParents.forEach((parent) => parent.removeEventListener('scroll', update));
window.removeEventListener('resize', update);
window.removeEventListener('scroll', update);
window.removeEventListener('orientationchange', update);
document.removeEventListener('visibilitychange', update);
};
}, [ref, throttleTime]);
return position;
}
//# sourceMappingURL=usePositionTracker.js.map