unified-video-framework
Version:
Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more
58 lines (50 loc) • 1.8 kB
text/typescript
import { useRef, useCallback } from 'react';
interface GestureHandlers {
onSingleTap: () => void;
onDoubleTap: (x: number, y: number) => void;
}
export function usePortraitGestures(
containerRef: React.RefObject<HTMLElement>,
handlers: GestureHandlers
) {
const tapTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const lastTapTimeRef = useRef(0);
const DOUBLE_TAP_DELAY = 280;
const handleTap = useCallback((e: React.MouseEvent | React.TouchEvent) => {
// Ignore taps on interactive elements
const target = e.target as HTMLElement;
if (target.closest('button, a, input, [data-interactive]')) return;
const now = Date.now();
const rect = containerRef.current?.getBoundingClientRect();
if (!rect) return;
let clientX: number;
let clientY: number;
if ('touches' in e) {
const touch = (e as React.TouchEvent).changedTouches[0];
clientX = touch.clientX;
clientY = touch.clientY;
} else {
clientX = (e as React.MouseEvent).clientX;
clientY = (e as React.MouseEvent).clientY;
}
const relX = clientX - rect.left;
const relY = clientY - rect.top;
if (now - lastTapTimeRef.current < DOUBLE_TAP_DELAY) {
// Double tap
if (tapTimerRef.current) {
clearTimeout(tapTimerRef.current);
tapTimerRef.current = null;
}
lastTapTimeRef.current = 0;
handlers.onDoubleTap(relX, relY);
} else {
// Potential single tap — wait to see if double
lastTapTimeRef.current = now;
tapTimerRef.current = setTimeout(() => {
tapTimerRef.current = null;
handlers.onSingleTap();
}, DOUBLE_TAP_DELAY);
}
}, [containerRef, handlers]);
return { handleTap };
}