import * as React from 'react';
/**
* @alpha
*/
export type UseSwipeOptions = {
minSwipeDistance?: number;
onLeftSwipe?: () => void;
onRightSwipe?: () => void;
};
/**
* Simple implementation to detect horizontal swipe actions.
* Accepts callbacks for on right and left swipes.
* @example
* ```tsx
*
* ```
* @alpha
*/
export function useSwipe(element: React.RefObject, options: UseSwipeOptions = {}) {
const touchStart = React.useRef(null);
const touchEnd = React.useRef(null);
// The required distance between touchStart and touchEnd to be detected as a swipe.
const minSwipeDistance = options.minSwipeDistance ?? 50;
const onTouchStart = (event: TouchEvent) => {
touchEnd.current = null; // Otherwise the swipe is fired even with usual touch events.
touchStart.current = event.targetTouches[0].clientX;
};
const onTouchMove = (event: TouchEvent) => {
touchEnd.current = event.targetTouches[0].clientX;
};
const onTouchEnd = React.useCallback(() => {
if (!touchStart.current || !touchEnd.current) {
return;
}
const distance = touchStart.current - touchEnd.current;
const isLeftSwipe = distance > minSwipeDistance;
const isRightSwipe = distance < -minSwipeDistance;
if (isLeftSwipe && options.onLeftSwipe) options.onLeftSwipe();
if (isRightSwipe && options.onRightSwipe) options.onRightSwipe();
}, [minSwipeDistance, options]);
React.useEffect(() => {
const elementCopy = element.current;
if (elementCopy) {
elementCopy.addEventListener('touchstart', onTouchStart, { passive: true });
elementCopy.addEventListener('touchmove', onTouchMove, { passive: true });
elementCopy.addEventListener('touchend', onTouchEnd, { passive: true });
}
return () => {
if (elementCopy) {
elementCopy.removeEventListener('touchstart', onTouchStart);
elementCopy.removeEventListener('touchmove', onTouchMove);
elementCopy.removeEventListener('touchend', onTouchEnd);
}
};
}, [element, onTouchEnd]);
}