import { useEffect, useRef } from 'react'; const UPPER_THRESHOLD = 1 / 4; const LOWER_THRESHOLD = 3 / 4; /** * Automatically scroll to a child element, by selector. * Whenever the selector changes, it tries to detect if the selector is out of view. * If it is, it will scroll to the closest upper or lower bound within the ref's scroll area. */ export function useAutoScrollTo(selector: string) { const ref = useRef(null); useEffect( function onMaybeScroll() { if (!selector || !ref.current) return; const target = ref.current.querySelector(selector); if (target) { const bounds = ref.current.getBoundingClientRect(); const position = ref.current.scrollTop; const targetPosition = target.offsetTop; const upperThreshold = bounds.height * UPPER_THRESHOLD; const lowerThreshold = bounds.height * LOWER_THRESHOLD; if (targetPosition < position + upperThreshold) { ref.current.scrollTo({ top: Math.max(0, targetPosition - upperThreshold) }); } else if (targetPosition > position + lowerThreshold) { ref.current.scrollTo({ top: targetPosition - lowerThreshold }); } } }, [ref.current, selector] ); return { ref }; }