Make the mobile nav sheet swipe-to-close instead of fighting pull-to-refresh #13

Merged
kyuno merged 1 commit from fix/mobile-nav-swipe-close into master 2026-09-16 18:29:20 +02:00
Owner

Summary

  • touch-action: none on .mobileNavScrim and the new .sheetGrabberHandle - stops the browser's own default touch handling (pull-to-refresh included) from claiming a downward drag that starts on either.
  • overscroll-behavior: contain on .mobileNavSheet - stops a drag that hits the sheet's own scroll boundary (its library grid can be taller than the 75vh cap) from chaining to the page underneath instead.
  • The grabber (.sheetGrabber) is now a real drag handle, not just a visual hint: #sheetGrabberHandle wraps the small 36x4px pill in a proper touch target and drives the sheet with pointerdown/move/up(/cancel) - 1:1 tracking while dragging, snap back under a 90px threshold, close past it (reusing the exact same closeMobileNav() the scrim tap already calls).

Context

Reported directly against a real phone: the scrim tap was the only way to close the sheet, and the instinctive swipe-it-down gesture fell straight through to the browser's own pull-to-refresh instead. Deliberately scoped the drag gesture to the grabber handle alone, not the whole sheet - the sheet's own content (the library grid, the logout row) needs its normal taps/scroll to keep working, which a whole-sheet drag-to-close would fight.

Verification

  • Full typecheck/build (client only).
  • touch-action/overscroll-behavior confirmed applied via getComputedStyle against the real compiled app.css.
  • The drag logic itself confirmed with dispatched PointerEvents (real clientY/pointerId) against the real handlers copied from Shell.ts: a 40px drag snaps back (stays open), a 120px drag closes, and the live transform mid-drag tracks the pointer 1:1 at an intermediate point (not just start/end).
  • Re-confirmed unchanged in the same pass: scrim-tap-to-close still works.
  • Not verified: actual touch input on a real phone (as opposed to a mouse or a dispatched PointerEvent) - no device reachable from this sandbox, same standing gap as this project's other touch-drag work (the video/music seek bars).

Test plan

  • On a real phone, open the mobile menu and swipe the grabber down partway, confirm it snaps back open
  • Swipe it down further, confirm it closes instead of triggering the browser's pull-to-refresh
  • Confirm scrolling the library grid inside the sheet still works normally
  • Confirm tapping the scrim still closes it too

🤖 Generated with Claude Code

## Summary - `touch-action: none` on `.mobileNavScrim` and the new `.sheetGrabberHandle` - stops the browser's own default touch handling (pull-to-refresh included) from claiming a downward drag that starts on either. - `overscroll-behavior: contain` on `.mobileNavSheet` - stops a drag that hits the sheet's own scroll boundary (its library grid can be taller than the `75vh` cap) from chaining to the page underneath instead. - The grabber (`.sheetGrabber`) is now a real drag handle, not just a visual hint: `#sheetGrabberHandle` wraps the small 36x4px pill in a proper touch target and drives the sheet with pointerdown/move/up(/cancel) - 1:1 tracking while dragging, snap back under a 90px threshold, close past it (reusing the exact same `closeMobileNav()` the scrim tap already calls). ## Context Reported directly against a real phone: the scrim tap was the *only* way to close the sheet, and the instinctive swipe-it-down gesture fell straight through to the browser's own pull-to-refresh instead. Deliberately scoped the drag gesture to the grabber handle alone, not the whole sheet - the sheet's own content (the library grid, the logout row) needs its normal taps/scroll to keep working, which a whole-sheet drag-to-close would fight. ## Verification - Full `typecheck`/`build` (client only). - `touch-action`/`overscroll-behavior` confirmed applied via `getComputedStyle` against the real compiled `app.css`. - The drag logic itself confirmed with dispatched `PointerEvent`s (real `clientY`/`pointerId`) against the real handlers copied from `Shell.ts`: a 40px drag snaps back (stays open), a 120px drag closes, and the live `transform` mid-drag tracks the pointer 1:1 at an intermediate point (not just start/end). - Re-confirmed unchanged in the same pass: scrim-tap-to-close still works. - **Not verified**: actual touch input on a real phone (as opposed to a mouse or a dispatched `PointerEvent`) - no device reachable from this sandbox, same standing gap as this project's other touch-drag work (the video/music seek bars). ## Test plan - [ ] On a real phone, open the mobile menu and swipe the grabber down partway, confirm it snaps back open - [ ] Swipe it down further, confirm it closes instead of triggering the browser's pull-to-refresh - [ ] Confirm scrolling the library grid inside the sheet still works normally - [ ] Confirm tapping the scrim still closes it too 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kyuno added 1 commit 2026-09-16 17:59:24 +02:00
Make the mobile nav sheet swipe-to-close instead of fighting pull-to-refresh
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
afae977b49
Reported directly: the only way to close the bottom sheet was tapping
the scrim, and the instinctive swipe-it-down gesture fell straight
through to the browser's own pull-to-refresh instead - nothing was
telling the browser this app's own code owned that gesture.

touch-action: none on the scrim and the (now real, not just visual)
grabber handle stops the browser's default touch handling from
kicking in there at all; overscroll-behavior: contain on the sheet
itself stops a drag that hits its own scroll boundary (the library
grid can run taller than the sheet's 75vh cap) from chaining to the
page underneath. The grabber's small 36x4px pill now sits inside a
much bigger invisible touch target that actually drags the sheet
(pointerdown/move/up, 1:1 tracking, snap back under 90px or close past
it) - scoped to the grabber alone, not the whole sheet, so the
library grid's own taps/scroll keep working untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
kyuno merged commit d10a35e541 into master 2026-09-16 18:29:20 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: kyuno/watchparty#13
No description provided.