Skip to content

fix: page once per trackpad swipe, and again for the next swipe - #77

Merged
tim-soft merged 2 commits into
masterfrom
claude/one-swipe-one-page
Nov 9, 2026
Merged

tim-soft merged 2 commits into
masterfrom
claude/one-swipe-one-page

Conversation

@tim-soft

@tim-soft tim-soft commented Nov 7, 2026 •

Copy link
Copy Markdown
Owner

Why

One trackpad swipe should page one image. A trackpad sends wheel events for about a second after the fingers lift, and the pager paged on every one faster than 1.1px/ms. In jsdom, 10 recorded trackpad swipes each called onNext or onPrev 22 to 63 times, on 1.9.0 and on #76 alike. This PR pages once per swipe, and still pages for a second swipe that starts before the first one's scroll ends.

This is stacked on #76, so it targets that PR's branch.

What changed

  • onWheel in ImagePager keeps a "can page" flag in @use-gesture's memo, which resets when a wheel gesture starts. A wheel gesture ends 140ms after its last event. The first event faster than 1.1px/ms pages and clears the flag. A later event slower than 0.2px/ms sets it again, because fingers landing for another swipe stop the scroll. Events that don't move are still skipped, so the empty wheel event that Chrome sends when fingers lift from a Windows touchpad doesn't re-arm paging.
  • New unit tests cover a swipe that keeps scrolling after the fingers lift, a Windows touchpad swipe, a swipe that slows down and speeds up without stopping, a second swipe the same way and back, and a quick mouse wheel spin. The test.fails and test.fail for this bug are now plain tests that pass.
  • Two new Playwright tests send a swipe and a double swipe to Chromium with DevTools timestamps.

Scope

Blast Radius

Only wheel paging changes. Drags, touch swipes, pinches, and ctrl + wheel zoom don't reach the changed code. A consumer test that sends several quick wheel events and expects several pages now sees one. The changeset's upgrade note covers that.

Verification

  • 20 recorded wheel streams from the wheel-gestures project (MIT) were replayed with their own timing. They cover trackpads in Safari and Chrome on macOS, a touchpad in Chrome on Windows, a Magic Mouse in Firefox, and mouse wheels in six browsers.
    • In jsdom, through the real component: before the fix, each stream paged 3 to 158 times, identically on 1.9.0's react-use-gesture 9 and on fix: replace the deprecated react-use-gesture with @use-gesture/react #76. After it, each single swipe, slow drag, and mouse wheel scroll pages once. The recorded double swipe pages twice, and a square traced on the trackpad pages once each way.
    • In Chromium, through the e2e harness: the same counts after the fix. Before it, every trackpad swipe ran the 5-image gallery to its end.
    • In the Next.js demo app: one recorded swipe moved from image 1 to 2, and the recorded double swipe moved from 2 to 4.
  • Five mutations of the rule each fail at least one new unit test. They re-arm under 0.04px/ms or 0.6px/ms, never re-arm, never latch, or let empty events re-arm.
  • npm test (100% lines, functions, and statements) and npm run lint pass. The unit tests and Chromium Playwright tests pass on React 18.3.1. The wheel Playwright tests pass in Chromium, Firefox, and WebKit. Locally, WebKit also fails 11 mouse drag, keyboard, and arrow button tests in e2e/paging.spec.ts, and each of them fails on fix: replace the deprecated react-use-gesture with @use-gesture/react #76's branch too.
  • The maintainer tried the demo app by hand on a Mac trackpad, and paging felt right. A physical mouse and a Windows touchpad weren't tried by hand.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Trackpad swipes now advance one image, even when momentum scrolling continues or the scroll speed changes.
    • A new swipe can advance another image before the previous scroll finishes, including when paging backward.
    • Fast-spun mouse wheels no longer skip multiple images from a single gesture.
    • Tests expecting quick wheel events to page multiple times may need to wait between events or use slower scrolling.

@coderabbitai

coderabbitai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Explain Change →

Walkthrough

The wheel handler now limits paging during trackpad momentum. Unit and browser tests cover a single swipe, continued momentum, subsequent swipes, and mouse-wheel input. The changeset documents the paging behavior and updated test guidance.

Changes: Trackpad wheel paging

Layer / File(s) Summary
Limit paging during wheel momentum
src/components/ImageStage/components/ImagePager/index.tsx
The wheel handler checks the canPage memo and velocity before paging. It returns whether the gesture can continue.
Test trackpad and mouse-wheel paging
src/__tests__/devices.ts, src/__tests__/paging.test.tsx, e2e/paging.spec.ts, .changeset/one-swipe-one-page.md
Tests cover momentum, follow-up and reverse swipes, and mouse-wheel events. Browser tests check page callbacks and displayed images. The changeset documents the behavior and test guidance.

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Bug fix

Possibly related PRs

Merge Risk: Minimal · up to ac4cd

The documented wheel behavior and test guidance present no established issue requiring a fix before merge.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly summarizes the main change: paging once per trackpad swipe and allowing the next swipe to page again.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 4 files. (1 skipped: 1 unsupported.)

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@tim-soft
tim-soft changed the base branch from claude/migrate-react-use-gesture-50dac8 to master November 9, 2026 17:42
tim-soft and others added 2 commits November 9, 2026 10:42
A trackpad sends wheel events for about a second after the fingers lift,
and the pager paged on each one faster than 1.1px/ms, so one recorded
swipe paged 22 to 63 times. Each wheel gesture now pages once. Fingers
landing for another swipe stop the scroll, so the next swipe can page
once the scroll is under 0.2px/ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainer tried the demo app on a Mac trackpad, and paging felt
right. The changeset still said that no physical trackpad was tried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tim-soft
tim-soft force-pushed the claude/one-swipe-one-page branch from 856b81c to ac4cd73 Compare November 9, 2026 17:42
@codecov

codecov Bot commented Nov 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional comments: 1

src/components/ImageStage/components/ImagePager/index.tsx-188-189: 1

188-189: Minor · Functional Correctness · Quick win

Unverified finding
Verification ran but could not confirm this finding. It is shown for review, not as a verified issue.

Allow a fast reversal to page back.

After a page change, wheel events in the opposite direction are also blocked until a slow event or a 140 ms pause occurs. (raw.githubusercontent.com) For example, opposite mouse-wheel notches 50 ms apart can leave the user scrolling without paging back. Track the paging direction and allow a fast reversal to page. Add a test without an intermediate slow event.

Review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a93f7175-36d9-4050-a31b-928cdd340962
Commits

Reviewing files that changed from the base of the PR and between ed76418 and ac4cd73.

Files selected for processing: 5

  • .changeset/one-swipe-one-page.md
  • e2e/paging.spec.ts
  • src/__tests__/devices.ts
  • src/__tests__/paging.test.tsx
  • src/components/ImageStage/components/ImagePager/index.tsx

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

@tim-soft
tim-soft merged commit 21ebe89 into master Nov 9, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant