phanpy/src/utils/useScroll.js

56 lines
1.7 KiB
JavaScript
Raw Normal View History

import { useEffect, useState } from 'preact/hooks';
export default function useScroll({
scrollableElement = window,
distanceFromTop = 0,
distanceFromBottom = 0,
2023-01-07 06:45:04 +00:00
scrollThresholdUp = 10,
scrollThresholdDown = 10,
} = {}) {
const [scrollDirection, setScrollDirection] = useState(null);
const [reachTop, setReachTop] = useState(false);
const [nearReachTop, setNearReachTop] = useState(false);
const [nearReachBottom, setNearReachBottom] = useState(false);
useEffect(() => {
let previousScrollTop = scrollableElement.scrollTop;
function onScroll() {
const { scrollTop, scrollHeight, clientHeight } = scrollableElement;
const scrollDistance = Math.abs(scrollTop - previousScrollTop);
const distanceFromTopPx =
scrollHeight * Math.min(1, Math.max(0, distanceFromTop));
const distanceFromBottomPx =
scrollHeight * Math.min(1, Math.max(0, distanceFromBottom));
2023-01-07 06:45:04 +00:00
if (
scrollDistance >=
(previousScrollTop < scrollTop
? scrollThresholdDown
: scrollThresholdUp)
) {
setScrollDirection(previousScrollTop < scrollTop ? 'down' : 'up');
previousScrollTop = scrollTop;
}
setReachTop(scrollTop === 0);
setNearReachTop(scrollTop <= distanceFromTopPx);
setNearReachBottom(
scrollTop + clientHeight >= scrollHeight - distanceFromBottomPx,
);
}
scrollableElement.addEventListener('scroll', onScroll, { passive: true });
return () => scrollableElement.removeEventListener('scroll', onScroll);
2023-01-07 06:45:04 +00:00
}, [
scrollableElement,
distanceFromTop,
distanceFromBottom,
scrollThresholdUp,
scrollThresholdDown,
]);
return { scrollDirection, reachTop, nearReachTop, nearReachBottom };
}