| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667 |
- import { useRef, useCallback, MouseEvent } from 'react';
- const DRAG_THRESHOLD = 5;
- export default function useDragScroll<T extends HTMLElement = HTMLElement>() {
- const ref = useRef<T>(null);
- const isDragging = useRef(false);
- const hasMoved = useRef(false);
- const startX = useRef(0);
- const scrollLeft = useRef(0);
- const onMouseDown = useCallback((e: MouseEvent) => {
- const el = ref.current;
- if (!el) return;
- e.preventDefault();
- isDragging.current = true;
- hasMoved.current = false;
- startX.current = e.pageX - el.offsetLeft;
- scrollLeft.current = el.scrollLeft;
- el.style.cursor = 'grabbing';
- }, []);
- const onMouseMove = useCallback((e: MouseEvent) => {
- if (!isDragging.current) return;
- const el = ref.current;
- if (!el) return;
- const x = e.pageX - el.offsetLeft;
- const walk = x - startX.current;
- if (!hasMoved.current && Math.abs(walk) > DRAG_THRESHOLD) {
- hasMoved.current = true;
- el.style.pointerEvents = 'auto';
- for (const child of el.children) {
- (child as HTMLElement).style.pointerEvents = 'none';
- }
- }
- e.preventDefault();
- el.scrollLeft = scrollLeft.current - walk;
- }, []);
- const resetState = useCallback(() => {
- isDragging.current = false;
- const el = ref.current;
- if (!el) return;
- el.style.cursor = 'grab';
- if (hasMoved.current) {
- for (const child of el.children) {
- (child as HTMLElement).style.pointerEvents = '';
- }
- }
- hasMoved.current = false;
- }, []);
- const onMouseUp = useCallback(() => resetState(), [resetState]);
- const onMouseLeave = useCallback(() => resetState(), [resetState]);
- return {
- ref,
- onMouseDown,
- onMouseMove,
- onMouseUp,
- onMouseLeave,
- };
- }
|