fix(mobile): long-pressing a thread row no longer navigates into the thread - #5901
Conversation
…thread On iOS the long-press context menu rows are a plain Pressable wrapped in the patched MenuView: the native button is touch-transparent so the row keeps handling taps, and the UIContextMenuInteraction lives on the host component view. RN's Fabric touch handler refuses to be prevented by recognizers inside the RN view tree (RCTSurfaceTouchHandler canBePreventedByGestureRecognizer), so the touch is never cancelled when the menu opens - on finger-up Pressability fired onPress and navigated with the menu already showing. Releasing just under the ~500ms menu threshold navigated too, since a Pressable without onLongPress fires onPress after any hold duration. Mirror the Android branch in ControlPillMenu: in long-press mode, clone the child with a no-op onLongPress and delayLongPress of 350ms. Once onLongPress dispatches, Pressability swallows the release, so holds past 350ms can only open the menu, never tap through. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Approved 7ad735a Straightforward bug fix for a mobile touch interaction issue. The change is self-contained in ControlPillMenu, only affects long-press behavior, and preserves existing handlers. Well-commented and authored by the file's primary maintainer. You can customize Macroscope's approvability policy. Learn more. |
## What's Changed * fix(web): thread title button no longer eats the drag area by @nathangerday in pingdotgg/t3code#5857 * fix(web): unify usage page chrome by @t3-code[bot] in pingdotgg/t3code#5823 * fix(shell): add ~/.local/bin to the Windows CLI resolver so native-installed providers are found by @arhxam in pingdotgg/t3code#5074 * fix(web): match settings search shortcut styling to command palette's by @UtkarshUsername in pingdotgg/t3code#5841 * fix(mobile): long-pressing a thread row no longer navigates into the thread by @juliusmarminge in pingdotgg/t3code#5901 * fix(server): usage no longer double-counts forked Codex sessions by @t3dotgg in pingdotgg/t3code#5887 * fix(server): sandbox user-provided SVGs by @t3dotgg in pingdotgg/t3code#5916 * fix(web): match usage titlebar text styling by @t3-code[bot] in pingdotgg/t3code#5897 ## New Contributors * @nathangerday made their first contribution in pingdotgg/t3code#5857 **Full Changelog**: pingdotgg/t3code@v0.0.33-nightly.20260809.1047...v0.0.33-nightly.20260810.1054 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.33-nightly.20260810.1054
Fixes the bug phil5034 reported on Discord: long-pressing a thread row in the overview to open the context menu could also navigate into the thread. Long press now only opens the menu; taps still navigate.
Why it happened
Two stacked issues, both iOS-only in our setup (Android already injects a guard):
A
Pressablewith onlyonPressfires on finger-up after any hold duration. The thread-row pressables have noonLongPresson iOS, so a long press released just under the ~500 ms native context-menu threshold read as a tap and navigated. Same class of bug as react-native-context-menu-view#60.The real double-fire: RN's Fabric touch handler is never cancelled when the menu opens. Our
@react-native-menu/menupatch makes the native button touch-transparent (so row taps reach thePressable) and hosts theUIContextMenuInteractionon the host component view — i.e. inside the RN view tree.RCTSurfaceTouchHandler.canBePreventedByGestureRecognizer:returnsNOfor any recognizer attached inside the RN hierarchy, andcancelsTouchesInViewonly cancels view-level delivery, not un-prevented gesture recognizers. So RN kept tracking the touch after the menu appeared; on finger-up Pressability firedonPressand navigated with the menu already showing. Documented ecosystem-wide in zeego#145.The fix
Mirror the Android branch of
ControlPillMenuon iOS: inshouldOpenOnLongPressmode, clone the child with a no-oponLongPressanddelayLongPress: 350(below the ~500 ms menu threshold). OnceonLongPressdispatches, Pressability suppressesonPresson release (isPressCanceledByLongPress), which closes both holes — short taps still navigate, holds past 350 ms can only open the menu. A child's ownonLongPress/delayLongPressare preserved if ever passed. Covers all four long-press menu call sites (v1 + v2 thread rows, both pending-task rows), which all pass aPressableas the direct child.Verification
Verified in the dev client on an iPhone 17 Pro simulator against a seeded showcase environment, driving real touch events:
Typecheck and lint pass.
🤖 Generated with Claude Code
Note
Low Risk
Small, localized touch-handling change on iOS menu wrappers; behavior aligns with the existing Android branch and only affects long-press menu rows.
Overview
Fixes an iOS-only bug where long-pressing a thread row to open the context menu could also fire the row’s
onPressand navigate into the thread.ControlPillMenu(iOS) now mirrors the existing Android long-press path: whenshouldOpenOnLongPressis set, it clones the direct childPressablewith a no-oponLongPressanddelayLongPress: 350(under the ~500ms native menu threshold). That lets React Native’s Pressability cancelonPresson finger-up after a hold, so opens the menu without tap-through. Short taps still navigate; existing childonLongPress/delayLongPressprops are left unchanged if present.Applies to all long-press menu usages (v1/v2 thread rows and pending-task rows) without changing those call sites.
Reviewed by Cursor Bugbot for commit 7ad735a. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix long-press on thread rows to prevent navigation on iOS
In ControlPill.tsx, when
shouldOpenOnLongPressis enabled on iOS, the wrapped child is cloned to inject a no-oponLongPresshandler and a 350msdelayLongPressif neither is already set. This prevents the child's tap/navigation from firing after a long-press that opens the menu.Macroscope summarized 7ad735a.