UNPKG

use-swipe-to-dismiss

Version:

A simple React hook to dismiss an element by swiping

75 lines (74 loc) 2.92 kB
import React, { useCallback, useEffect, useState } from 'react'; const defaultOptions = { dismissThreshold: '50%', snapbackDuration: 0.1, snapbackEasing: 'ease-out', }; /** Custom hook useSwipeToDismiss.js to manage long press. */ const useSwipeToDismiss = (options = {}) => { // initialize default options const { dismissThreshold, onDismiss, onDismissEnd, snapbackDuration, snapbackEasing } = Object.assign(Object.assign({}, defaultOptions), options); // set dismiss threshold based on height const [height, setHeight] = useState(0); // track y position at start of drag const [y0, setY0] = useState(0); // track change in y position during drag const [dy, setDY] = useState(0); // enable animation during snapback const [animate, setAnimate] = useState(false); // calculate height on mount const ref = React.createRef(); useEffect(() => { if (!ref.current) return; setHeight(ref.current.offsetHeight); }, []); const start = useCallback((e) => { var _a; // do not animate during drag so that element tracks touch exactly setAnimate(false); setY0((_a = e.touches) === null || _a === void 0 ? void 0 : _a[0].pageY); }, []); const stop = useCallback((e) => { // animate on release for snapback animation setAnimate(true); // check for dismiss threshold // if specified as a percentage of height, use percentage of element height const isPercentageOfHeight = typeof dismissThreshold === 'string' && dismissThreshold.endsWith('%'); const dismissThresholdPx = isPercentageOfHeight ? -parseFloat(dismissThreshold) * height / 100 : -parseFloat(dismissThreshold); if (dy < dismissThresholdPx) { setDY(-height * 2); onDismiss === null || onDismiss === void 0 ? void 0 : onDismiss(); setTimeout(() => { onDismissEnd === null || onDismissEnd === void 0 ? void 0 : onDismissEnd(); }, snapbackDuration * 1000); } else { setDY(0); } }, [dy, height]); const move = useCallback((e) => { var _a; // move element to track touch const y = (_a = e.touches) === null || _a === void 0 ? void 0 : _a[0].pageY; const dy = y - y0; // resist dragging down by taking the square root of positive dy const dyResistant = dy < 0 ? dy : Math.sqrt(dy); setDY(dyResistant); }, [y0]); return { onTouchStart: start, onTouchEnd: stop, onTouchMove: move, onTouchCancel: stop, ref, style: { transform: `translateY(${dy}px)`, transition: animate ? `transform ${snapbackDuration}s ${snapbackEasing}` : '', touchAction: 'none', } }; }; export default useSwipeToDismiss;