Files
backspace/packages/web/src/hooks/useSwipeGesture.ts
T
Jannis Braun ed70099963 fix(mobile): resolve all TypeScript errors from integration
- Fix voiceStore method names (toggleMic, leaveVoice, setCurrentVoiceChannel)
- Fix MemberWithUser nested user property access
- Pass required channelId props to MessageList, TypingIndicator, MessageInput
- Fix ConfirmDialog props (isOpen, description, variant, onClose)
- Add mobileStyle prop to Modal component (fullscreen + sheet modes)
- Fix fromId/isAdmin camelCase property names
- Guard possibly undefined touch events and array accesses
- Fix notification channelId resolution
2026-03-17 15:54:39 +01:00

71 lines
2.3 KiB
TypeScript

import { useRef, useCallback, useEffect } from 'react';
interface SwipeGestureOptions {
onSwipeRight?: () => void;
edgeThreshold?: number; // px from left edge to start detection (default: 20)
swipeThreshold?: number; // px of horizontal movement to trigger (default: 50)
enabled?: boolean;
}
export function useSwipeGesture({
onSwipeRight,
edgeThreshold = 20,
swipeThreshold = 50,
enabled = true,
}: SwipeGestureOptions) {
const touchStartRef = useRef<{ x: number; y: number } | null>(null);
const swipingRef = useRef(false);
const handleTouchStart = useCallback((e: TouchEvent) => {
if (!enabled) return;
const touch = e.touches[0];
if (!touch) return;
if (touch.clientX <= edgeThreshold) {
touchStartRef.current = { x: touch.clientX, y: touch.clientY };
swipingRef.current = false;
}
}, [enabled, edgeThreshold]);
const handleTouchMove = useCallback((e: TouchEvent) => {
if (!touchStartRef.current) return;
const touch = e.touches[0];
if (!touch) return;
const dx = touch.clientX - touchStartRef.current.x;
const dy = touch.clientY - touchStartRef.current.y;
// If vertical movement exceeds horizontal, cancel swipe detection
if (Math.abs(dy) > Math.abs(dx) && !swipingRef.current) {
touchStartRef.current = null;
return;
}
if (dx > swipeThreshold) {
swipingRef.current = true;
e.preventDefault();
}
}, [swipeThreshold]);
const handleTouchEnd = useCallback(() => {
if (swipingRef.current && onSwipeRight) {
onSwipeRight();
}
touchStartRef.current = null;
swipingRef.current = false;
}, [onSwipeRight]);
useEffect(() => {
if (!enabled) return;
document.addEventListener('touchstart', handleTouchStart, { passive: true });
document.addEventListener('touchmove', handleTouchMove, { passive: false });
document.addEventListener('touchend', handleTouchEnd);
document.addEventListener('touchcancel', handleTouchEnd);
return () => {
document.removeEventListener('touchstart', handleTouchStart);
document.removeEventListener('touchmove', handleTouchMove);
document.removeEventListener('touchend', handleTouchEnd);
document.removeEventListener('touchcancel', handleTouchEnd);
};
}, [enabled, handleTouchStart, handleTouchMove, handleTouchEnd]);
}