export type TouchPoint = { clientX: number; clientY: number; }; export type TouchDecisionState = { x: number; y: number; decided: boolean; }; type TouchLike = { clientX: number; clientY: number; }; type TouchEventLike = { touches: ArrayLike; changedTouches: ArrayLike; }; export function getTouchPoint(event: TouchEventLike): TouchPoint { const touch = event.touches[0] ?? event.changedTouches[0]; return { clientX: touch?.clientX ?? 0, clientY: touch?.clientY ?? 0, }; } export function resolveTouchDragDecision( state: TouchDecisionState, point: TouchPoint, thresholdPx = 8, ): { nextState: TouchDecisionState; shouldHandleDrag: boolean } { if (state.decided) { return { nextState: state, shouldHandleDrag: true }; } const dx = Math.abs(point.clientX - state.x); const dy = Math.abs(point.clientY - state.y); if (dx <= thresholdPx && dy <= thresholdPx) { return { nextState: state, shouldHandleDrag: false }; } const nextState = { ...state, decided: true }; return { nextState, shouldHandleDrag: dx >= dy, }; }