Files
luminance/src/hooks/scroll.ts
T

87 lines
2.1 KiB
TypeScript

import { useCallback, useEffect, useRef, useState } from "react";
import type { RefObject } from "react";
export function handleScroll(
prevLength: number,
scrollDelta: number,
handleIncrement: () => void,
handleDecrement: () => void,
): number {
const newLength = prevLength + scrollDelta;
if (Math.abs(newLength) > 50) {
if (newLength > 0) {
handleIncrement();
} else if (newLength < 0) {
handleDecrement();
}
return 0;
}
return newLength;
}
type ScrollHandler = () => void;
export function useScroll<T extends HTMLElement>({
targetRef,
onScrollUp,
onScrollDown,
deltaYMultiplier: deltaYMultiplier = 1,
}: {
targetRef: RefObject<T | null>;
onScrollUp: ScrollHandler;
onScrollDown: ScrollHandler;
deltaYMultiplier?: number;
}) {
const scrollLength = useRef(0);
const onScrollUpRef = useRef(onScrollUp);
const onScrollDownRef = useRef(onScrollDown);
const deltaYMultiplierRef = useRef(deltaYMultiplier);
useEffect(() => {
onScrollUpRef.current = onScrollUp;
onScrollDownRef.current = onScrollDown;
deltaYMultiplierRef.current = deltaYMultiplier;
}, [onScrollUp, onScrollDown, deltaYMultiplier]);
const handleWheelEvent = useCallback((event: WheelEvent) => {
event.preventDefault();
const newScrollLength = handleScroll(
scrollLength.current,
event.deltaY * deltaYMultiplierRef.current,
onScrollDownRef.current,
onScrollUpRef.current,
);
scrollLength.current = newScrollLength;
}, []);
const addScrollListener = useCallback(() => {
const currentRef = targetRef.current;
if (currentRef) {
currentRef.addEventListener("wheel", handleWheelEvent);
}
}, [handleWheelEvent, targetRef]);
const removeScrollListener = useCallback(() => {
const currentRef = targetRef.current;
if (currentRef) {
currentRef.removeEventListener("wheel", handleWheelEvent);
}
}, [handleWheelEvent, targetRef]);
useEffect(() => {
return () => {
removeScrollListener();
};
}, [removeScrollListener]);
return {
addScrollListener,
removeScrollListener,
};
}