1*adfb0600SCedric van Puttenimport { useEffect, useRef } from 'react'; 2*adfb0600SCedric van Putten 3*adfb0600SCedric van Puttenconst UPPER_THRESHOLD = 1 / 4; 4*adfb0600SCedric van Puttenconst LOWER_THRESHOLD = 3 / 4; 5*adfb0600SCedric van Putten 6*adfb0600SCedric van Putten/** 7*adfb0600SCedric van Putten * Automatically scroll to a child element, by selector. 8*adfb0600SCedric van Putten * Whenever the selector changes, it tries to detect if the selector is out of view. 9*adfb0600SCedric van Putten * If it is, it will scroll to the closest upper or lower bound within the ref's scroll area. 10*adfb0600SCedric van Putten */ 11*adfb0600SCedric van Puttenexport function useAutoScrollTo<T extends HTMLElement = HTMLDivElement>(selector: string) { 12*adfb0600SCedric van Putten const ref = useRef<T>(null); 13*adfb0600SCedric van Putten 14*adfb0600SCedric van Putten useEffect( 15*adfb0600SCedric van Putten function onMaybeScroll() { 16*adfb0600SCedric van Putten if (!selector || !ref.current) return; 17*adfb0600SCedric van Putten const target = ref.current.querySelector<HTMLElement>(selector); 18*adfb0600SCedric van Putten if (target) { 19*adfb0600SCedric van Putten const bounds = ref.current.getBoundingClientRect(); 20*adfb0600SCedric van Putten const position = ref.current.scrollTop; 21*adfb0600SCedric van Putten const targetPosition = target.offsetTop; 22*adfb0600SCedric van Putten const upperThreshold = bounds.height * UPPER_THRESHOLD; 23*adfb0600SCedric van Putten const lowerThreshold = bounds.height * LOWER_THRESHOLD; 24*adfb0600SCedric van Putten 25*adfb0600SCedric van Putten if (targetPosition < position + upperThreshold) { 26*adfb0600SCedric van Putten ref.current.scrollTo({ top: Math.max(0, targetPosition - upperThreshold) }); 27*adfb0600SCedric van Putten } else if (targetPosition > position + lowerThreshold) { 28*adfb0600SCedric van Putten ref.current.scrollTo({ top: targetPosition - lowerThreshold }); 29*adfb0600SCedric van Putten } 30*adfb0600SCedric van Putten } 31*adfb0600SCedric van Putten }, 32*adfb0600SCedric van Putten [ref.current, selector] 33*adfb0600SCedric van Putten ); 34*adfb0600SCedric van Putten 35*adfb0600SCedric van Putten return { ref }; 36*adfb0600SCedric van Putten} 37