/** * The time in milleseconds we wait after * a scroll event to determine that a sequence * of scroll events has ended. */ const DETECT_SCROLL_END_BUFFER_TIME = 125; export const onScrollEnd = (element: HTMLElement, callback: () => void) => { element.addEventListener( "scroll", (e) => { // @ts-ignore const elementScrollTimeout = parseInt(element.dataset.scrollTimeout, 10); if (elementScrollTimeout) { clearTimeout(elementScrollTimeout); } element.dataset.scrollTimeout = `${setTimeout(callback, DETECT_SCROLL_END_BUFFER_TIME)}`; }, { passive: true, } ); }; /** * Certain elements need to always take scroll priority. * This is particularly noticable for the Gallery. This seems * to be a bug in webkit. We can work around this by tricking the * browsering into thinking an element is always scrolling. */ export const provideBounce = (element: HTMLElement) => { if (!element) { return; } const addBounceIfNeeded = () => { if (element.scrollTop === 0) { // If the element is currently at the top, provide buffer element.scrollTop = element.scrollTop + 1; } else if (element.scrollTop === element.scrollHeight - element.clientHeight) { // If the element is scrolled all the way to the bottom, provide buffer element.scrollTop = element.scrollTop - 1; } }; // Call immediately addBounceIfNeeded(); // When scrolling ends, check to add bounce if needed onScrollEnd(element, () => { addBounceIfNeeded(); }); };