UNPKG

beautiful-react-hooks

Version:

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

136 lines (135 loc) 5.27 kB
import { useEffect, useRef, useState } from 'react'; import isFunction from './shared/isFunction'; import useMouseEvents from './useMouseEvents'; import useTouchEvents from './useTouchEvents'; import createHandlerSetter from './factory/createHandlerSetter'; import { getDirection, getPointerCoordinates } from './shared/swipeUtils'; const defaultOptions = { threshold: 15, preventDefault: true, passive: undefined }; /* eslint-disable @typescript-eslint/default-param-last */ /** * Very similar to useSwipe but doesn't cause re-rendering during swipe. * Internal usage only. */ const useSwipeStateInternal = (targetRef = undefined, 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, opts.passive); const { onTouchStart, onTouchMove, onTouchEnd, onTouchCancel } = useTouchEvents(targetRef, opts.passive); 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 */ // eslint-disable-next-line max-len const useSwipeEvents = (ref = undefined, 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 = useSwipeStateInternal(ref, opts, onSwipeStart.current, onSwipeMove.current, onSwipeEnd.current); const fnMap = { right: onSwipeRight, left: onSwipeLeft, up: onSwipeUp, down: onSwipeDown }; useEffect(() => { if (state === null || state === void 0 ? void 0 : state.direction) { const cb = fnMap[state.direction].current; if (isFunction(cb)) { cb(state); } } }, [state]); return Object.freeze({ onSwipeLeft: setOnSwipeLeft, onSwipeRight: setOnSwipeRight, onSwipeUp: setOnSwipeUp, onSwipeDown: setOnSwipeDown, onSwipeMove: setOnSwipeMove, onSwipeStart: setOnSwipeStart, onSwipeEnd: setOnSwipeEnd }); }; export default useSwipeEvents;