Skip to content

chore(runway): cherry-pick fix: conditionally apply onPress for Accessibility mode for Android TouchableOpacity cp-7.57.0#21221

Merged
Cal-L merged 1 commit into
release/7.57.0from
runway-cherry-pick-7.57.0-1760554032
Oct 15, 2025
Merged

chore(runway): cherry-pick fix: conditionally apply onPress for Accessibility mode for Android TouchableOpacity cp-7.57.0#21221
Cal-L merged 1 commit into
release/7.57.0from
runway-cherry-pick-7.57.0-1760554032

Conversation

@runway-github

@runway-github runway-github Bot commented Oct 15, 2025

Copy link
Copy Markdown
Contributor

Description

This PR fixes critical button responsiveness issues in ScrollView and
BottomSheet contexts by refactoring gesture handling and removing
deprecated press coordination logic across the component library.

Problem:

  • Buttons were unresponsive in ScrollView contexts on Android due to
    TouchableOpacity conflicts
  • Buttons in BottomSheet components (like "Got it", "Add funds",
    "Withdraw") had gesture handler conflicts with BottomSheet pan gestures
  • The existing useCoordinatedPress hook was causing double-firing
    issues and race conditions with accessibility features

Solution:

  1. Gesture priority management: Implemented
    requireExternalGestureToFail() with tight constraints (300ms max
    duration, 20px max delta) to allow buttons to work alongside BottomSheet
    gestures
  2. Accessibility-aware handling: Implemented exclusive gesture
    handling - use gesture handler when accessibility is OFF,
    TouchableOpacity when accessibility is ON/UNKNOWN to prevent race
    conditions
  3. Simplified coordination: Removed deprecated useCoordinatedPress
    hook and related timestamp-based coordination logic
  4. Test environment safety: Added fallback to standard
    RNTouchableOpacity in test environments

Changelog

CHANGELOG entry: Fixed button responsiveness issues in ScrollView and
BottomSheet contexts

Related issues

Fixes: #18704

Manual testing steps

Feature: Button responsiveness in various contexts

  Scenario: user taps buttons in ScrollView contexts
    Given user is viewing buttons within a ScrollView on Android
    When user taps any button
    Then button should respond immediately without delay
    
  Scenario: user taps buttons in BottomSheet modals
    Given user sees a BottomSheet modal with action buttons
    When user taps action buttons (e.g., "Got it", "Add funds")
    Then buttons should respond without conflicting with sheet gestures
    
  Scenario: accessibility users interact with buttons
    Given screen reader is enabled
    When user taps any button
    Then button should respond using TouchableOpacity onPress (not gesture handler)
    And should not experience double-firing or race conditions
    
  Scenario: gesture handling in test environments
    Given app is running in test environment
    When tests interact with buttons
    Then buttons should use standard RNTouchableOpacity behavior

Screenshots/Recordings

Before

After

Technical Changes

Core Components Updated:

  • ButtonBase.tsx - Added gesture handler with
    requireExternalGestureToFail() and tight constraints, accessibility
    state tracking to prevent double-firing
  • ListItemSelect.tsx - Same gesture priority fix and accessibility
    handling
  • ListItemMultiSelect.tsx - Updated gesture handling while preserving
    iOS checkbox coordination
  • PressablePerpsComponent.tsx - Removed useCoordinatedPress hook
    (already compatible)

Perps Components Updated:

  • PerpsTabView.tsx - Removed useCoordinatedPress usage, direct
    onPress calls
  • PerpsCard.tsx - Removed useCoordinatedPress usage, simplified
    press handling

Key Technical Improvements:

  1. Gesture Conflict Resolution: requireExternalGestureToFail()
    allows BottomSheet pan gestures to take priority when needed, while
    still detecting taps within tight constraints
  2. Accessibility Race Condition Fix: Use null initial state for
    isAccessibilityEnabled to handle async updates safely; exclusive
    handling prevents double-firing
  3. Test Environment Compatibility: Conditional fallback to standard
    TouchableOpacity in tests
  4. Performance: Removed unnecessary coordination wrapper and
    timestamp tracking

Implementation Details:

  • Gesture handler only fires when isAccessibilityEnabled === false
    (known OFF state)
  • TouchableOpacity onPress only fires when isAccessibilityEnabled !== false (ON or UNKNOWN state)
  • Tight gesture constraints: 300ms max duration, 20px max delta, single
    pointer only
  • onEnd lifecycle used (not onStart) to ensure complete gesture
    detection

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the
    app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described
    in the ticket it closes and includes the necessary testing evidence such
    as recordings and or screenshots.

Note

Adds accessibility-aware tap handling and removes timestamp-based press coordination to fix unresponsive/double-fired presses on Android across ButtonBase, list items, and Perps UI.

  • Component Library:
    • ButtonBase: Adds gesture handler (Tap with tight constraints and requireExternalGestureToFail) and AccessibilityInfo-based press routing; uses RNTouchableOpacity in tests; simplifies onPress (removes timestamp coordination).
    • List Items: Update ListItemSelect and ListItemMultiSelect to match the new gesture/accessibility model; keep iOS checkbox coordination; provide platform-aware onPress delegation.
  • Perps UI:
    • Remove useCoordinatedPress hook and its usage in PerpsTabView and PerpsCard; press now calls handlers directly.
    • TouchablePerpsComponent remains as Android wrapper, with deprecated coordination hook removed.
  • Tests:
    • Update snapshots to reflect new press handlers and test-environment behavior.

Written by Cursor Bugbot for commit da8ff6d. This will update automatically on new commits. Configure here.

--- 1d32de9

…sibility mode for Android TouchableOpacity cp-7.57.0 (#21146)

## **Description**

This PR fixes critical button responsiveness issues in ScrollView and
BottomSheet contexts by refactoring gesture handling and removing
deprecated press coordination logic across the component library.

**Problem:** 
- Buttons were unresponsive in ScrollView contexts on Android due to
TouchableOpacity conflicts
- Buttons in BottomSheet components (like "Got it", "Add funds",
"Withdraw") had gesture handler conflicts with BottomSheet pan gestures
- The existing `useCoordinatedPress` hook was causing double-firing
issues and race conditions with accessibility features

**Solution:**
1. **Gesture priority management**: Implemented
`requireExternalGestureToFail()` with tight constraints (300ms max
duration, 20px max delta) to allow buttons to work alongside BottomSheet
gestures
2. **Accessibility-aware handling**: Implemented exclusive gesture
handling - use gesture handler when accessibility is OFF,
TouchableOpacity when accessibility is ON/UNKNOWN to prevent race
conditions
3. **Simplified coordination**: Removed deprecated `useCoordinatedPress`
hook and related timestamp-based coordination logic
4. **Test environment safety**: Added fallback to standard
`RNTouchableOpacity` in test environments

## **Changelog**

CHANGELOG entry: Fixed button responsiveness issues in ScrollView and
BottomSheet contexts

## **Related issues**

Fixes: #18704

## **Manual testing steps**

```gherkin
Feature: Button responsiveness in various contexts

  Scenario: user taps buttons in ScrollView contexts
    Given user is viewing buttons within a ScrollView on Android
    When user taps any button
    Then button should respond immediately without delay
    
  Scenario: user taps buttons in BottomSheet modals
    Given user sees a BottomSheet modal with action buttons
    When user taps action buttons (e.g., "Got it", "Add funds")
    Then buttons should respond without conflicting with sheet gestures
    
  Scenario: accessibility users interact with buttons
    Given screen reader is enabled
    When user taps any button
    Then button should respond using TouchableOpacity onPress (not gesture handler)
    And should not experience double-firing or race conditions
    
  Scenario: gesture handling in test environments
    Given app is running in test environment
    When tests interact with buttons
    Then buttons should use standard RNTouchableOpacity behavior
```

## **Screenshots/Recordings**

### **Before**

### **After**

## **Technical Changes**

### **Core Components Updated:**
- `ButtonBase.tsx` - Added gesture handler with
`requireExternalGestureToFail()` and tight constraints, accessibility
state tracking to prevent double-firing
- `ListItemSelect.tsx` - Same gesture priority fix and accessibility
handling
- `ListItemMultiSelect.tsx` - Updated gesture handling while preserving
iOS checkbox coordination
- `PressablePerpsComponent.tsx` - Removed `useCoordinatedPress` hook
(already compatible)

### **Perps Components Updated:**
- `PerpsTabView.tsx` - Removed `useCoordinatedPress` usage, direct
`onPress` calls
- `PerpsCard.tsx` - Removed `useCoordinatedPress` usage, simplified
press handling

### **Key Technical Improvements:**
1. **Gesture Conflict Resolution**: `requireExternalGestureToFail()`
allows BottomSheet pan gestures to take priority when needed, while
still detecting taps within tight constraints
2. **Accessibility Race Condition Fix**: Use `null` initial state for
`isAccessibilityEnabled` to handle async updates safely; exclusive
handling prevents double-firing
3. **Test Environment Compatibility**: Conditional fallback to standard
TouchableOpacity in tests
4. **Performance**: Removed unnecessary coordination wrapper and
timestamp tracking

### **Implementation Details:**
- Gesture handler only fires when `isAccessibilityEnabled === false`
(known OFF state)
- TouchableOpacity `onPress` only fires when `isAccessibilityEnabled !==
false` (ON or UNKNOWN state)
- Tight gesture constraints: 300ms max duration, 20px max delta, single
pointer only
- `onEnd` lifecycle used (not `onStart`) to ensure complete gesture
detection

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Makes Android touchables accessibility-aware with gesture priority
management to avoid ScrollView and BottomSheet conflicts, removes press
coordination logic, and simplifies Perps press handling with test-safe
fallbacks.
> 
> - **Component Library**:
> - **`Buttons/Button/foundation/ButtonBase`**: Adds
`AccessibilityInfo`-aware tap handling (gesture only when screen reader
is off), `requireExternalGestureToFail()` with tight constraints (300ms,
20px delta), test-mode fallback to `RNTouchableOpacity`; implements
exclusive `onPress` handling to prevent double-firing.
> - **`ListItemSelect` / `ListItemMultiSelect`**: Mirrors
accessibility-aware gesture handling with priority management; refactors
iOS checkbox coordination; provides test-mode fallback and conditional
`onPress` wiring.
> - **Perps**:
> - **`PressablePerpsComponent`**: Keeps platform-specific touchable;
removes `useCoordinatedPress` hook.
> - **`PerpsTabView` / `PerpsCard`**: Drops `useCoordinatedPress` usage;
invoke handlers directly.
> - **Tests**:
> - Snapshot updates reflecting conditional `onPress` and test-mode
behavior (`[MockFunction]`), across various UI snapshots.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot). This will update
automatically on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---
@runway-github runway-github Bot requested review from a team as code owners October 15, 2025 18:47
@github-actions

Copy link
Copy Markdown
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@metamaskbot metamaskbot added the team-runway-bot-deprecated DEPRECATED: please use "team-bots" instead label Oct 15, 2025
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
31.1% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@Cal-L Cal-L added the skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. label Oct 15, 2025

@Cal-L Cal-L left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Cal-L Cal-L merged commit 948b3ce into release/7.57.0 Oct 15, 2025
110 of 117 checks passed
@Cal-L Cal-L deleted the runway-cherry-pick-7.57.0-1760554032 branch October 15, 2025 20:13
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 15, 2025
@metamaskbot metamaskbot added the release-7.57.0 Issue or pull request that will be included in release 7.57.0 label Oct 15, 2025
@metamaskbot

Copy link
Copy Markdown
Collaborator

No release label on PR. Adding release label release-7.57.0 on PR, as PR was cherry-picked in branch 7.57.0.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-7.57.0 Issue or pull request that will be included in release 7.57.0 size-L skip-sonar-cloud Only used for bypassing sonar cloud when failures are not relevant to the changes. team-runway-bot-deprecated DEPRECATED: please use "team-bots" instead

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants