Fix swipe eating scroll gestures on the detail page

onSwipe judged horizontal-vs-vertical from a single touchmove sample
compared against the start point. A fast scroll flick's first sample is
often slightly diagonal (thumb motion), so it could get claimed as a
page-swipe and every subsequent touchmove got preventDefault()'d — the
rest of the scroll silently died, so trying to reach off-screen content
in About/Stats/Evolution/etc. would instead flip to the next Pokémon.

Now vertical intent wins by default (bails, permanently, as soon as the
drag is even mildly more vertical than horizontal) and a horizontal
page-swipe only gets claimed once the drag is unambiguous
(dx > 20 && dx > 2*dy). Deliberate left/right swipes still work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
This commit is contained in:
chris 2026-09-04 11:35:03 -04:00
parent c7a2a821fa
commit fc2128dabe

View File

@ -32,11 +32,19 @@ export function onSwipe(target, { onLeft, onRight, threshold = 60 } = {}) {
const dx = e.touches[0].clientX - x0;
const dy = e.touches[0].clientY - y0;
if (!claimed) {
if (Math.abs(dy) > 12 && Math.abs(dy) > Math.abs(dx)) {
active = false; // it's a vertical scroll — let it be
const adx = Math.abs(dx);
const ady = Math.abs(dy);
// Scroll is the default: bail out — permanently — at the first sign of
// vertical intent, even a mildly diagonal one. A page full of scrolling
// content (tab panels, lists) means a fast flick's first sample is
// often diagonal; without this bias it gets misread as a page-swipe
// and the rest of the scroll gets eaten by preventDefault().
if (ady > 10 && ady > adx * 0.7) {
active = false;
return;
}
if (Math.abs(dx) > 10 && Math.abs(dx) > Math.abs(dy)) claimed = true;
// Only claim a horizontal page-swipe once the drag is unambiguous.
if (adx > 20 && adx > ady * 2) claimed = true;
}
if (claimed) e.preventDefault();
};