Skip to content

fix: Add swipe to dismiss for DS Legacy toast - #33598

Merged
amandaye0h merged 6 commits into
mainfrom
toast/swipe-to-dismiss
Jul 28, 2026
Merged

fix: Add swipe to dismiss for DS Legacy toast#33598
amandaye0h merged 6 commits into
mainfrom
toast/swipe-to-dismiss

Conversation

@amandaye0h

@amandaye0h amandaye0h commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Description

Adds swipe-to-dismiss to the legacy DS Toast component.

Users can swipe a top toast upward to dismiss it (by distance or quick flick). Incomplete swipes spring back and resume auto-dismiss timing. Manual close and tap handlers are unchanged.

Changelog

CHANGELOG entry: Added swipe-to-dismiss for in-app toasts

Related issues

Refs: #33600

Manual testing steps

Feature: Toast swipe to dismiss

  Scenario: user dismisses a toast by swiping up
    Given a Toast is visible at the top of the screen
    When the user swipes the toast upward past the dismiss threshold
    Then the toast animates out and is dismissed

  Scenario: user cancels a dismiss swipe
    Given a Toast is visible at the top of the screen
    When the user swipes the toast upward a short distance and releases
    Then the toast springs back into place
    And auto-dismiss continues as expected
Field Value
Source branch toast/swipe-to-dismiss
Build name main-rc
Build commit SHA 3a546d4
Build version 8.5.0
Build number 6146
TestFlight group MetaMask BETA & Release Candidates
Workflow branch ref main

Screenshots/Recordings

Before

Toast can't be swiped

ScreenRecording_07-22-2026.00-21-44_1.MP4

After

Toast can be swiped

ScreenRecording_07-21-2026.22-51-17_1.MP4

Pre-merge author checklist

Performance checks (if applicable)

  • I've tested on Android
    • Ideally on a mid-range device; emulator is acceptable
  • I've tested with a power user scenario
    • Use these power-user SRPs to import wallets with many accounts and tokens
  • I've instrumented key operations with Sentry traces for production performance metrics

For performance guidelines and tooling, see the Performance Guide.

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

Medium Risk
Touches shared in-app toast animation/gesture and timer logic with several race-edge fixes; scope is UI-only but behavior is user-visible app-wide.

Overview
Adds swipe-up to dismiss on the legacy design-system Toast, using a vertical pan gesture with tuned distance/velocity thresholds and offsets so taps and horizontal scrolls are not stolen.

Auto-dismiss no longer uses Reanimated withDelay; it uses a JS setTimeout that is cleared during pans, dismiss, remeasure, and toast replacement (so an old timed toast cannot dismiss a newly shown persistent toast). Incomplete swipes spring back and resume the remaining auto-dismiss time, with guards for interrupted entrance, mid-closeToast dismiss, and stale spring-back after showToast replaces content.

Tests mock react-native-gesture-handler and cover dismiss thresholds, incomplete swipes, replacement, and dismiss-in-progress edge cases.

Reviewed by Cursor Bugbot for commit 9f99e0f. Bugbot is set up for automated code reviews on this repo. Configure here.

@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.

@github-actions github-actions Bot added the pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. label Jul 21, 2026
@metamask-ci metamask-ci Bot added the team-design-system All issues relating to design system in Mobile label Jul 21, 2026
@amandaye0h
amandaye0h marked this pull request as ready for review July 21, 2026 14:00
@amandaye0h
amandaye0h requested a review from a team as a code owner July 21, 2026 14:00
Comment thread app/component-library/components/Toast/Toast.tsx
Comment thread app/component-library/components/Toast/Toast.tsx
@github-actions github-actions Bot added the risk:high AI analysis: high risk label Jul 21, 2026
Ignore pans while a dismiss animation is in progress, and restart
auto-dismiss when entrance is interrupted by an incomplete swipe.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread app/component-library/components/Toast/Toast.tsx Outdated
Comment thread app/component-library/components/Toast/Toast.tsx Outdated
@github-actions github-actions Bot added risk:medium AI analysis: medium risk and removed risk:high AI analysis: high risk labels Jul 21, 2026
Prevent a timed toast's auto-dismiss from dismissing a persistent replacement, and only resume auto-dismiss after an incomplete swipe when the spring-back finishes.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added risk:high AI analysis: high risk and removed risk:medium AI analysis: medium risk labels Jul 21, 2026
@amandaye0h amandaye0h removed the pr-not-ready-for-e2e Skip E2E and block merging. Remove this label once the PR is ready to run the E2E tests. label Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

🧪 Flaky unit test detection

✅ All previously detected unit test flakiness issues in this PR have been fixed.

View recent run history

This check is informational only and does not block merging.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b5e58cc. Configure here.

Comment thread app/component-library/components/Toast/Toast.tsx
Start auto-dismiss from incomplete-swipe onEnd instead of spring-back completion so a queued resume cannot schedule dismiss after showToast clears the previous toast.

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions github-actions Bot added size-L and removed size-M labels Jul 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smart E2E Test Selection

  • Selected E2E tags: SmokeWalletPlatform, SmokeSwap, SmokeConfirmations, SmokeStake, SmokeMoney
  • Selected Performance tags: None (no tests recommended)
  • Risk Level: medium
  • AI Confidence: 72%
click to see 🤖 AI reasoning details

E2E Test Selection:
The PR modifies the Toast component — a shared UI component used across many features in the app. Key changes include:

  1. Swipe-to-dismiss gesture: Added GestureDetector + Gesture.Pan() from react-native-gesture-handler. This wraps the entire Toast view and could potentially conflict with existing gesture handlers in screens that display toasts.

  2. Auto-dismiss timer refactoring: Changed from withDelay (Reanimated animation-based delay) to setTimeout-based scheduling. This is a behavioral change in timing that could affect how toasts appear/disappear in existing flows.

  3. New shared values and state: Added visibleTranslateY, gestureStartY, toastHeight, isDismissing shared values and autoDismissTimeoutRef, hasNoTimeoutRef refs — more complex state management.

Toast usage across features:

  • useEarnToasts → used in Earn/Stake flows → SmokeStake
  • HwQrScanner → hardware wallet swaps → SmokeSwap + SmokeConfirmations
  • useMoneyToasts → Money/Card flows → SmokeMoney
  • TokenDetailsList → token details in wallet → SmokeWalletPlatform
  • CollectibleDetectionModal → NFT detection → SmokeWalletPlatform

SmokeConfirmations is included because SmokeSwap and SmokeMoney flows involve confirmations, and the Toast component is used during transaction flows.

Performance tests: Not selected — the Toast changes are UI/gesture behavioral changes that don't affect the performance-measured scenarios (app launch, login, onboarding, asset loading, swaps execution timing). The gesture handler addition is lightweight and not in a performance-critical path.

Performance Test Selection:
The Toast changes add swipe gesture support and refactor auto-dismiss timing. These are UI interaction changes that don't affect the performance-measured scenarios (app launch cold/warm start, login unlock time, onboarding flow, asset loading, swap execution timing). The GestureDetector wrapper is lightweight and not in any performance-critical rendering path.

View GitHub Actions results

@sonarqubecloud

Copy link
Copy Markdown

@georgewrmarshall georgewrmarshall 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! Two non-blocking follow ups below.

const closeToast = () => {
visibleAtRef.current = null;
startDismissAnimation();
};

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.

non-blocking: The four separate useRef objects + four one-liner wrapper functions is quite verbose for what it's doing. A single stable-ref object would be easier to follow:

const swipeCallbacks = useRef({ closeToast, ensureAutoDismissAfterIncompleteSwipe, resumeAutoDismissAfterSwipe, clearScheduledAutoDismiss });
swipeCallbacks.current = { closeToast, ensureAutoDismissAfterIncompleteSwipe, resumeAutoDismissAfterSwipe, clearScheduledAutoDismiss };

Then in the memoized gesture: runOnJS(() => swipeCallbacks.current.closeToast())(). Reduces 24 lines to ~2 while keeping the same semantics.

return;
}
const { translationY, velocityY } = event;
const dismissDistance = Math.max(

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.

non-blocking: The 24 minimum dismiss distance is a magic number. Worth extracting to a named constant in Toast.constants.ts alongside the other gesture thresholds, e.g. TOAST_DISMISS_MINIMUM_PX = 24.

@amandaye0h
amandaye0h added this pull request to the merge queue Jul 28, 2026
amandaye0h added a commit to MetaMask/metamask-design-system that referenced this pull request Jul 28, 2026
## **Description**

Adds swipe-to-dismiss to the React Native `Toaster` (top-anchored
Toast), porting the same behavior from metamask-mobile.

1. **What is the reason for the change?**
- Toast covers navigation elements when it appears from the top. This
prevents users from accessing back buttons.
- Mobile already supports swipe-to-dismiss on legacy Toast and
BaseNotification. The design-system `Toaster` should match so consumers
get the same interaction without reimplementing it.
2. **What is the improvement/solution?** Users can swipe a toast upward
to dismiss it (by distance or quick flick). Incomplete swipes spring
back and resume the auto-dismiss timer. Auto-dismiss uses an
interruptible `setTimeout` instead of Reanimated `withDelay`, so pans
and toast replacement can pause/clear the timer correctly. Manual close
and action handlers are unchanged.

Gesture thresholds match mobile (`0.35` height / `800` px/s / `-8`
active offset Y / `20` fail offset X). Package adaptations:
`scheduleOnRN` + explicit `'worklet'` directives for the prebuilt dist.

## **Related issues**

Related:
- MetaMask/metamask-mobile#33598
- MetaMask/metamask-mobile#33600

## **Manual testing steps**

1. Run `yarn storybook:ios` (or `yarn storybook:android`)
2. Open `Components/Toast` (or Toaster) and show a timed toast
3. Swipe the toast upward past ~35% of its height — it should animate
out and dismiss
4. Show another toast and flick upward quickly — it should dismiss via
velocity
5. Show a toast, swipe a short distance up, and release — it should
spring back and still auto-dismiss on schedule
6. Show a persistent toast (`hasNoTimeout`) and swipe to dismiss — it
should dismiss; taps/buttons should still work without accidental
dismiss
7. Replace a timed toast with a persistent one — the new toast should
stay visible (old timer must not fire)

## **Screenshots/Recordings**

### **Before**

<!-- Toast cannot be swiped away; only auto-dismiss / close -->

### **After**

<!-- Toast can be swiped up to dismiss; incomplete swipe springs back
-->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs)
- [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

## **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]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit bab6450. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Merged via the queue into main with commit a3ca1a6 Jul 28, 2026
295 of 297 checks passed
@amandaye0h
amandaye0h deleted the toast/swipe-to-dismiss branch July 28, 2026 06:57
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 28, 2026
@metamask-ci metamask-ci Bot added the release-8.6.0 Issue or pull request that will be included in release 8.6.0 label Jul 28, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release-8.6.0 Issue or pull request that will be included in release 8.6.0 risk:high AI analysis: high risk size-L team-design-system All issues relating to design system in Mobile

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants