UNPKG

beautiful-react-hooks

Version:

A collection of beautiful (and hopefully useful) React hooks to speed-up your components and hooks development

132 lines (131 loc) 5.08 kB
import { useEffect, useRef, useState } from 'react'; import createHandlerSetter from './factory/createHandlerSetter'; import useMouseEvents from './useMouseEvents'; import useTouchEvents from './useTouchEvents'; import { getDirection, getPointerCoordinates } from './shared/swipeUtils'; const defaultOptions = { threshold: 15, preventDefault: true, }; /* eslint-disable @typescript-eslint/default-param-last */ /** * Very similar to useSwipe but doesn't cause re-rendering during swipe */ const useSilentSwipeState = (targetRef = null, options = defaultOptions, onSwipeStart, onSwipeMove, onSwipeEnd) => { const startingPointRef = useRef([-1, -1]); const directionRef = useRef(null); const isDraggingRef = useRef(false); const alphaRef = useRef([]); const opts = Object.assign(Object.assign({}, defaultOptions), (options || {})); const { onMouseDown, onMouseMove, onMouseLeave, onMouseUp } = useMouseEvents(targetRef); const { onTouchStart, onTouchMove, onTouchEnd, onTouchCancel } = useTouchEvents(targetRef); const [state, setState] = useState(); const startSwipe = (event) => { const [clientX, clientY] = getPointerCoordinates(event); startingPointRef.current = [clientX, clientY]; directionRef.current = null; if (onSwipeStart) { onSwipeStart({ clientX, clientY }); } if (opts.preventDefault) { event.preventDefault(); event.stopPropagation(); } }; const continueSwipe = (event) => { const [clientX, clientY] = getPointerCoordinates(event); if (opts.preventDefault) { event.preventDefault(); event.stopPropagation(); } if (startingPointRef.current[0] !== -1 && startingPointRef.current[1] !== -1) { const alpha = [startingPointRef.current[0] - clientX, startingPointRef.current[1] - clientY]; if (Math.abs(alpha[0]) > opts.threshold || Math.abs(alpha[1]) > opts.threshold) { isDraggingRef.current = true; directionRef.current = getDirection([clientX, clientY], startingPointRef.current, alpha); alphaRef.current = alpha; if (onSwipeMove) { onSwipeMove({ clientX, clientY, direction: directionRef.current, alphaX: alphaRef.current[0], alphaY: alphaRef.current[1], }); } } } }; const endSwipe = (event) => { if (isDraggingRef.current && directionRef.current) { if (opts.preventDefault) { event.preventDefault(); event.stopPropagation(); } setState({ direction: directionRef.current, alphaX: alphaRef.current[0], alphaY: alphaRef.current[1], }); if (onSwipeEnd) { onSwipeEnd({ direction: directionRef.current, alphaX: alphaRef.current[0], alphaY: alphaRef.current[1], }); } } startingPointRef.current = [-1, -1]; isDraggingRef.current = false; directionRef.current = null; }; onMouseDown(startSwipe); onTouchStart(startSwipe); onMouseMove(continueSwipe); onTouchMove(continueSwipe); onMouseUp(endSwipe); onTouchEnd(endSwipe); onMouseLeave(endSwipe); onTouchCancel(endSwipe); return state; }; /** * useSwipeEvents * @param ref * @param options */ const useSwipeEvents = (ref = null, options = defaultOptions) => { const opts = Object.assign(Object.assign({}, defaultOptions), (options || {})); const [onSwipeLeft, setOnSwipeLeft] = createHandlerSetter(); const [onSwipeRight, setOnSwipeRight] = createHandlerSetter(); const [onSwipeUp, setOnSwipeUp] = createHandlerSetter(); const [onSwipeDown, setOnSwipeDown] = createHandlerSetter(); const [onSwipeStart, setOnSwipeStart] = createHandlerSetter(); const [onSwipeMove, setOnSwipeMove] = createHandlerSetter(); const [onSwipeEnd, setOnSwipeEnd] = createHandlerSetter(); const state = useSilentSwipeState(ref, opts, onSwipeStart.current, onSwipeMove.current, onSwipeEnd.current); const fnMap = { right: onSwipeRight, left: onSwipeLeft, up: onSwipeUp, down: onSwipeDown, }; useEffect(() => { if (state && state.direction) { const cb = fnMap[state.direction].current; if (cb && typeof cb === 'function') { cb(state); } } }, [state]); return Object.freeze({ onSwipeLeft: setOnSwipeLeft, onSwipeRight: setOnSwipeRight, onSwipeUp: setOnSwipeUp, onSwipeDown: setOnSwipeDown, onSwipeMove: setOnSwipeMove, onSwipeStart: setOnSwipeStart, onSwipeEnd: setOnSwipeEnd, }); }; export default useSwipeEvents;