fix(web): self-heal leaked drawer/sheet touch sequences (mobile nav freeze) #174
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab!174
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "lab/20260718-0240"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #173
On mobile, the navbar sometimes went permanently dead — swipe-to-open never worked again (and after a mid-drag leak, an invisible full-viewport scrim ate every tap) until the PWA was killed.
Root cause: touch events dispatch at the element the finger went down on. An SSE-driven re-render detaching that node mid-touch means the sequence's touchend/touchcancel fire on the detached node and never bubble to AppShell's window-level gesture listeners, so
activeTouchId(and, mid-drag,dragging+ the scrim) pinned forever. iOS never reuses touch identifiers, so a home-screen PWA never recovered.Fix:
onTouchStartself-heals: a tracked id gone frome.touches, or re-appearing ine.changedTouches(a finger cannot go down twice — identifier reuse proves the old sequence ended unheard), settles the orphan viagesture.cancel()before the new touch starts.visibilitychange→hidden settles any in-flight drag (iOS can background the PWA mid-touch without a touchcancel).Tests: new
AppShell.test.tsxexercises the window binding seam with jsdom-fabricated touches — control swipe, both leak phases (tracking + claimed/pinned-scrim), Android identifier reuse, visibility reset — plus a ToolPanel recovery case. All 5 recovery tests fail on the unfixed sources; full web suite (843 tests), tsc, eslint, prettier green.Note: recovery is lazy by design — the stuck state clears on the next touch anywhere (or on backgrounding), so the first tap after a leak may still land on the pinned scrim; everything works from the second touch on.
🤖 Generated with Claude Code