UNPKG

@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
'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