Skip to content

fix(desktop): lock horizontal webview pan (Magic Mouse side-scroll)#1480

Merged
thomaspblock merged 7 commits into
mainfrom
brain/overscroll-boundary-lock
Jul 3, 2026
Merged

fix(desktop): lock horizontal webview pan (Magic Mouse side-scroll)#1480
thomaspblock merged 7 commits into
mainfrom
brain/overscroll-boundary-lock

Conversation

@thomaspblock

Copy link
Copy Markdown
Collaborator

Summary

  • The earlier overscroll fix (useWebviewScrollBoundaryLock) only inspected deltaY, so Magic Mouse / trackpad horizontal pans still rubber-banded the entire WKWebView canvas — in the inbox, channels, everywhere.
  • The wheel boundary lock now checks both axes: a gesture only passes through if a container under the pointer can actually scroll in that direction (isScrollableX/canScrollX mirror the Y logic). Horizontal boundaries are always locked; the conversation-scroller elastic exception applies only to predominantly vertical gestures. Legitimate horizontal scrollers (code blocks, tables) still work since they consume the delta.
  • Added a CSS backstop on html, body: overflow: hidden + overscroll-behavior: none so document-level scroll chaining can't pan the viewport on either axis.

Test plan

  • overscroll-boundary.spec.ts extended with a horizontal test: both pan directions locked over top chrome, sidebar header, chat title, and the message timeline; a mostly-vertical gesture with slight horizontal drift still reaches the conversation scroller.
  • Both smoke tests pass locally.
  • Manual check in the Tauri app with a Magic Mouse side-scroll.

@thomaspblock

Copy link
Copy Markdown
Collaborator Author
pull-fix.mp4

@wesbillman

Copy link
Copy Markdown
Collaborator

Review by Brain (Buzz agent, posted via Wes's account)

Reviewed head 9c28753c — all 3 files (+128/−22). Verdict: approve — correct, minimal, well-tested. This is the right shape of fix: it mirrors the existing Y-axis boundary logic onto X rather than inventing a new mechanism.

What was verified

Hook logic (useWebviewScrollBoundaryLock.ts):

  • isScrollableX / canScrollX are exact mirrors of the Y versions, including the document-element exclusion, overflow-x computed-style gate (Tailwind overflow-x-autoauto → passes), and the ±1px epsilon.
  • The loop change is sound: each axis is only consulted when its delta is non-zero, and a gesture passes through iff some container under the pointer can actually move in an active axis. Legitimate horizontal scrollers (code blocks, MarkdownTable, attachment strips — all use overflow-x-auto) keep working because they consume the delta.
  • The conversation-scroller elastic exception is correctly gated to predominantly-vertical gestures (|deltaY| >= |deltaX|). Hand-traced: pure horizontal over the timeline → prevented; vertical-with-drift (−120/−10) → passes through to the scroller. Both match the tests.
  • Dropping the old deltaY === 0 early-return is exactly what lets pure-horizontal events reach the lock — that was the escape hatch the Magic Mouse pan used.

CSS backstop (theme.css): overflow: hidden + overscroll-behavior: none on html, body. Nothing in desktop/src scrolls the document (window.scrollTo / scrollingElement: zero hits) and the shell is already fixed-height. This backstop also covers the one hole the hook can't: a diagonal gesture over an X-scrollable code block returns early (X can move), and the unconsumed Y component could previously chain to the viewport — overscroll-behavior: none on the document now stops that chain. The two layers genuinely complement each other.

Tests: overscroll-boundary.spec.ts runs in the smoke project; all 4 Desktop Smoke E2E shards + both Integration shards are green on the head SHA. The 9 skipped checks are correctly path-filtered (no Rust touched).

Non-blocking nits

  1. theme.css now has two adjacent html, body blocks (heights vs. overflow) — merging would be tidier; keeping them separate for the comment is defensible.
  2. Synthetic WheelEvents in Playwright/Chromium can't capture real WKWebView momentum-pan behavior. The unticked manual item in the test plan — Magic Mouse side-scroll in the actual Tauri app — is the one gap that matters; worth doing before merge since the whole PR exists for that gesture.

@thomaspblock thomaspblock merged commit 5d4edf1 into main Jul 3, 2026
25 checks passed
@thomaspblock thomaspblock deleted the brain/overscroll-boundary-lock branch July 3, 2026 02:31
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.

2 participants