Skip to content

TokenPicker uses SwipeDismissHandle primitive (polish wave C.1)#33

Closed
epicexcelsior wants to merge 2 commits into
anonmesh:v3from
epicexcelsior:epic/swipe-to-dismiss-primitive
Closed

TokenPicker uses SwipeDismissHandle primitive (polish wave C.1)#33
epicexcelsior wants to merge 2 commits into
anonmesh:v3from
epicexcelsior:epic/swipe-to-dismiss-primitive

Conversation

@epicexcelsior
Copy link
Copy Markdown
Collaborator

Summary

`POLISH_PLAN.md` Wave C.1 called for extracting an inline pan-to-dismiss gesture from `TokenPicker.tsx` into a reusable primitive at `components/primitives/SwipeToDismiss.tsx`. Audit found the primitive already exists as `components/primitives/SwipeDismissHandle.tsx` — exported from the index, but never used anywhere. `TokenPicker` carried an inline duplicate of the same logic.

This PR refactors `TokenPicker` to consume the existing primitive. No new file, no architecture change — just dedupe.

What changed

  • `mobile_app/components/send/TokenPicker.tsx` — drops the local `panGesture` / `dismiss` callback / `Gesture` + `runOnJS` + `withSpring` imports / `DISMISS_DISTANCE` + `DISMISS_VELOCITY` constants. Imports `SwipeDismissHandle` from `@/components/primitives`. The handle component renders its own grab indicator + gesture-capture area, so the in-line decorative grab bar at the top of the sheet was also dropped (replaced by the handle render).
  • 33 LOC removed net (160 deletions − 127 insertions).

Architecture note worth surfacing

The pre-existing `SwipeDismissHandle` captures pan on the handle area only, not the whole sheet. Per its own docstring:

Using a dedicated handle avoids the scroll-conflict issue of wrapping full screen content in a Pan gesture — only the handle itself captures the gesture; child scrollviews + pressables work normally.

The previous `TokenPicker` implementation wrapped the entire sheet in `GestureDetector` — fine for that screen since it has no `ScrollView`, but the wrong template for the audit. Modals with internal scrollables (`TxDetailModal`, `ExportWalletModal`, recovery key reveal, receive QR) can adopt this same pattern cleanly post-merge.

Drive-by

Carries the same `fix(nodes): drop stale H_PAD reference` cherry-pick the other open wallet-lane PRs do — `tsc --noEmit` errors out on `upstream/v3` without it. No-ops on whichever PR merges first.

Validation

  • `npx tsc --noEmit` clean
  • `npm run lint` clean
  • `npm run validate:tier0:services` pass
  • `node ./scripts/validate-tier0-config.mjs` pass

Test plan

  • Send flow on Seeker: open `/send/recipient` → tap token chip → TokenPicker sheet slides up
  • Pan down on the handle area → sheet follows finger
  • Release past threshold (120pt or velocity > 800) → sheet dismisses
  • Release short → sheet springs back
  • Tap a token → selection works (haptic + sheet dismiss)
  • Tap close icon → sheet dismisses
  • Tap backdrop → sheet dismisses

Future work (not this PR)

Apply `SwipeDismissHandle` to:

PR anonmesh#29 removed the H_PAD constant when moving PendingCosigns into
WalletScreen's grid (parent now owns horizontal padding) but left one
reference at line 57. Result: upstream/v3 fails tsc on a fresh clone.

Drop the stale paddingHorizontal entry from the wrap View style array
and consolidate the two duplicate @expo/vector-icons imports while in
the file.
POLISH_PLAN Wave C.1 called for extracting an inline pan-to-dismiss
gesture from TokenPicker into a reusable primitive. Audit found
SwipeDismissHandle already exists in components/primitives/, exported
from the index, but never used anywhere. TokenPicker carried the
inline duplicate of the same logic (Gesture.Pan + activeOffsetY 8 +
failOffsetY -10 + dismiss thresholds 120/800 + spring damping 18/220).

Refactored TokenPicker to consume the existing primitive. Drops local
panGesture/dismiss/Gesture imports/DISMISS_* constants. The handle
component renders its own grab indicator + capture area, so the
in-line decorative bar at the top of the sheet is also dropped.

Architecture difference worth noting: SwipeDismissHandle captures pan
on the handle area only (per its own docstring, this avoids the
scroll-conflict issue of wrapping full screen content in a Pan
gesture). Future modals with internal ScrollView (TxDetailModal,
recovery export, etc.) can adopt the same pattern cleanly.
@epicexcelsior
Copy link
Copy Markdown
Collaborator Author

Superseded by upcoming PR — proper @gorhom/bottom-sheet primitive replaces SwipeDismissHandle and migrates TokenPicker + receive screen as a single product truth. The H_PAD cherry-pick lives on PR #30 / #31 anyway.

@epicexcelsior epicexcelsior deleted the epic/swipe-to-dismiss-primitive branch May 15, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant