Description
On Android, the "arrow and box" (expand/open) icon at the top right corner of task/tool items in the chat transcript does not respond to touch. Tapping it rarely or never triggers the expected action (opening/expanding the tool content).
Root Cause
The icon is rendered as a TouchableOpacity (secondaryAction) in ToolView.tsx with a tiny 18px touch target and no hitSlop. Combined with gesture hierarchy interference from parent components, touches fail to reach the button.
Touch Handling Chain
MessageView.tsx → AgentTextBlock
└── Pressable (agentMessageContainer) ← intercepts touches
└── ToolView
└── Header
└── TouchableOpacity (secondaryAction) ← tiny target, no hitSlop
└── Ionicons "open-outline" ← what user taps
Three Contributing Factors
-
Tiny touch target with no hitSlop (ToolView.tsx, secondaryAction style ~line 491)
- The icon button has only
marginLeft: 0 — no hitSlop defined
- The icon is 18px, well below Android's recommended 48dp minimum touch target
- For comparison,
CopyMessageButton in MessageView.tsx already uses hitSlop={8}
-
Parent Pressable intercepting touches (MessageView.tsx ~line 274)
AgentTextBlock wraps content in a <Pressable> for web hover effects
- Even without an
onPress handler, Pressable participates in Android's touch responder system and can steal touches from small child targets
-
GestureDetector LongPress consuming touches (MarkdownView.tsx ~lines 84-99)
Gesture.LongPress() wraps all markdown content and can intercept taps before they propagate to nested TouchableOpacity buttons
Why Android-Specific
iOS has better gesture disambiguation that can resolve competing gesture handlers in favor of small nested targets. Android's touch system is stricter about hit testing with small targets and competing responders.
Suggested Fix
- Add
hitSlop={10} (or similar) to the secondaryAction TouchableOpacity in ToolView.tsx
- Add
pointerEvents="box-none" to the agentMessageContainer Pressable in MessageView.tsx so it doesn't capture touches meant for children
- Consider configuring the
GestureDetector in MarkdownView.tsx with waitFor or simultaneousWithExternalGesture to allow nested buttons to function independently
Related
Description
On Android, the "arrow and box" (expand/open) icon at the top right corner of task/tool items in the chat transcript does not respond to touch. Tapping it rarely or never triggers the expected action (opening/expanding the tool content).
Root Cause
The icon is rendered as a
TouchableOpacity(secondaryAction) inToolView.tsxwith a tiny 18px touch target and nohitSlop. Combined with gesture hierarchy interference from parent components, touches fail to reach the button.Touch Handling Chain
Three Contributing Factors
Tiny touch target with no hitSlop (
ToolView.tsx,secondaryActionstyle ~line 491)marginLeft: 0— nohitSlopdefinedCopyMessageButtoninMessageView.tsxalready useshitSlop={8}Parent Pressable intercepting touches (
MessageView.tsx~line 274)AgentTextBlockwraps content in a<Pressable>for web hover effectsonPresshandler,Pressableparticipates in Android's touch responder system and can steal touches from small child targetsGestureDetector LongPress consuming touches (
MarkdownView.tsx~lines 84-99)Gesture.LongPress()wraps all markdown content and can intercept taps before they propagate to nestedTouchableOpacitybuttonsWhy Android-Specific
iOS has better gesture disambiguation that can resolve competing gesture handlers in favor of small nested targets. Android's touch system is stricter about hit testing with small targets and competing responders.
Suggested Fix
hitSlop={10}(or similar) to thesecondaryActionTouchableOpacityinToolView.tsxpointerEvents="box-none"to theagentMessageContainerPressableinMessageView.tsxso it doesn't capture touches meant for childrenGestureDetectorinMarkdownView.tsxwithwaitFororsimultaneousWithExternalGestureto allow nested buttons to function independentlyRelated
Pressable+GestureDetectorinterference pattern