Background
PR #1165 migrated BottomSheetDialog from the RNGH v1 PanGestureHandler / useAnimatedGestureHandler API to the RNGH v2 GestureDetector / Gesture.Pan() API, required by the upgrade to react-native-reanimated ~4.1.1 and react-native-gesture-handler ~2.28.0.
As part of that migration, panGestureHandlerProps was removed as a breaking change. It was a passthrough shim that gave consumers access to the full PanGestureHandler configuration surface — things like simultaneousHandlers, activeOffsetY, failOffsetX, hitSlop, minDist. The prop was never called in MetaMask Mobile or Extension consumer code, and the simultaneousHandlers use case (the only real one in the codebase) was already silently broken because applyPanGestureProps never mapped it to gesture.simultaneousWithExternalGesture().
See MIGRATION.md for the breaking change documentation.
The problem this creates
Without panGestureHandlerProps, consumers have no escape hatch to configure the underlying pan gesture. The most immediately impacted case is scrollable content inside a BottomSheet on Android — without gesture coordination, the bottom sheet's pan gesture intercepts scroll attempts and dismisses the sheet instead of scrolling the list.
The ScrollableList Storybook story demonstrates this: it still passes a ref to the ScrollView but that ref is now disconnected — there is nothing coordinating the scroll and dismiss gestures.
Options explored
Option A: Expose individual first-class props
Add explicit props for common configurations (activeOffsetY, simultaneousWithRef, etc.). Clean public API but the component becomes the gatekeeper — if a consumer needs something not exposed, they're stuck.
Option B: gestureModifier callback
Give consumers a function that receives the base Gesture.Pan() object and returns it configured:
<BottomSheet
gestureModifier={(gesture) =>
gesture
.activeOffsetY([-5, 5])
.simultaneousWithExternalGesture(scrollRef)
}
>
This is the v2-idiomatic equivalent of panGestureHandlerProps — same full-surface access, type-safe, consumer owns any configuration layered on top of the component's core behaviour. The component creates the base gesture with its internal onStart/onUpdate/onEnd logic and passes it to the modifier before using it.
Option C: Adopt @gorhom/bottom-sheet ← preferred direction
Replace the bespoke gesture management entirely. @gorhom/bottom-sheet v5 handles simultaneous gesture coordination with scroll views, keyboard avoidance, and sheet snapping as first-class concerns. The consumer never needs to think about gesture configuration.
@gorhom/bottom-sheet is already present as a devDependency in apps/storybook-react-native. The current BottomSheetDialog implementation is ~300 lines managing concerns that @gorhom/bottom-sheet handles out of the box.
Primary goal: verify compatibility with MetaMask Mobile
Before committing to Option C, confirm that @gorhom/bottom-sheet v5 is compatible with the MetaMask Mobile stack:
Intermediate path (if Option C is blocked)
If @gorhom/bottom-sheet adoption needs more time, implement Option B (gestureModifier callback) as a non-breaking addition to restore the escape hatch:
export type BottomSheetDialogProps = {
// ...existing props
gestureModifier?: (
gesture: ReturnType<typeof Gesture.Pan>,
) => ReturnType<typeof Gesture.Pan>;
};
This unblocks the simultaneousHandlers scroll use case without re-introducing the v1 prop surface.
Related
Background
PR #1165 migrated
BottomSheetDialogfrom the RNGH v1PanGestureHandler/useAnimatedGestureHandlerAPI to the RNGH v2GestureDetector/Gesture.Pan()API, required by the upgrade toreact-native-reanimated ~4.1.1andreact-native-gesture-handler ~2.28.0.As part of that migration,
panGestureHandlerPropswas removed as a breaking change. It was a passthrough shim that gave consumers access to the fullPanGestureHandlerconfiguration surface — things likesimultaneousHandlers,activeOffsetY,failOffsetX,hitSlop,minDist. The prop was never called in MetaMask Mobile or Extension consumer code, and thesimultaneousHandlersuse case (the only real one in the codebase) was already silently broken becauseapplyPanGesturePropsnever mapped it togesture.simultaneousWithExternalGesture().See MIGRATION.md for the breaking change documentation.
The problem this creates
Without
panGestureHandlerProps, consumers have no escape hatch to configure the underlying pan gesture. The most immediately impacted case is scrollable content inside a BottomSheet on Android — without gesture coordination, the bottom sheet's pan gesture intercepts scroll attempts and dismisses the sheet instead of scrolling the list.The
ScrollableListStorybook story demonstrates this: it still passes arefto theScrollViewbut that ref is now disconnected — there is nothing coordinating the scroll and dismiss gestures.Options explored
Option A: Expose individual first-class props
Add explicit props for common configurations (
activeOffsetY,simultaneousWithRef, etc.). Clean public API but the component becomes the gatekeeper — if a consumer needs something not exposed, they're stuck.Option B:
gestureModifiercallbackGive consumers a function that receives the base
Gesture.Pan()object and returns it configured:This is the v2-idiomatic equivalent of
panGestureHandlerProps— same full-surface access, type-safe, consumer owns any configuration layered on top of the component's core behaviour. The component creates the base gesture with its internalonStart/onUpdate/onEndlogic and passes it to the modifier before using it.Option C: Adopt
@gorhom/bottom-sheet← preferred directionReplace the bespoke gesture management entirely.
@gorhom/bottom-sheetv5 handles simultaneous gesture coordination with scroll views, keyboard avoidance, and sheet snapping as first-class concerns. The consumer never needs to think about gesture configuration.@gorhom/bottom-sheetis already present as a devDependency inapps/storybook-react-native. The currentBottomSheetDialogimplementation is ~300 lines managing concerns that@gorhom/bottom-sheethandles out of the box.Primary goal: verify compatibility with MetaMask Mobile
Before committing to Option C, confirm that
@gorhom/bottom-sheetv5 is compatible with the MetaMask Mobile stack:@gorhom/bottom-sheetanywhere — if so, which version@gorhom/bottom-sheetv5 requiresreact-native-reanimated >= 3andreact-native-gesture-handler >= 2(both satisfied on our current stack)BottomSheet/BottomSheetDialogpublic API surface against@gorhom/bottom-sheet's API — identify what maps cleanly and what would be a breaking change for consumersBottomSheetfrom this design system or its own copy inapp/component-library/Intermediate path (if Option C is blocked)
If
@gorhom/bottom-sheetadoption needs more time, implement Option B (gestureModifiercallback) as a non-breaking addition to restore the escape hatch:This unblocks the
simultaneousHandlersscroll use case without re-introducing the v1 prop surface.Related
panGestureHandlerProps, documents breaking change in MIGRATION.mdcombinedSheetStyledep array)