From 13a7adb853b115f22b860697350f70da8eeb2462 Mon Sep 17 00:00:00 2001 From: yoavpagir Date: Wed, 29 Jul 2026 14:07:58 +0300 Subject: [PATCH 1/4] fix: Dialog - prevent open animation interruption by residual touch on Android (minDistance) A bottom Dialog/ActionSheet opened from a gesture-driven trigger (e.g. List.Item's TapGestureHandler firing onPress on END) can rest part-way open on Android: the residual touch leaks into the Dialog's own panGesture and drives `visibility` mid-open, interrupting the open spring. Adding a minDistance activation threshold to the pan prevents a near-static residual touch from engaging it, while drag-to-dismiss keeps working. Co-Authored-By: Claude Opus 4.8 --- .../react-native-ui-lib/src/components/dialog/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/react-native-ui-lib/src/components/dialog/index.tsx b/packages/react-native-ui-lib/src/components/dialog/index.tsx index 0e943f33cb..3293b99d9d 100644 --- a/packages/react-native-ui-lib/src/components/dialog/index.tsx +++ b/packages/react-native-ui-lib/src/components/dialog/index.tsx @@ -190,6 +190,12 @@ const Dialog = (props: DialogProps, ref: ForwardedRef) }; const panGesture = Gesture.Pan() + // MOBAPP-2994: require a deliberate drag before the pan engages. Without this, on Android/Fabric + // the residual touch stream from a gesture-handler trigger (e.g. List.Item's TapGestureHandler, + // which fires onPress on END while the touch is still settling) leaks into this freshly-mounted + // pan and drives `visibility` mid-open, interrupting the open spring so the sheet rests part-way. + // A plain touchable trigger (Button) lifts cleanly before the modal mounts and is unaffected. + .minDistance(10) .onStart(event => { initialTranslation.value = getTranslationReverseInterpolation(isVertical ? event.translationY : event.translationX) - visibility.value; From f4ccfb7da463c33d809cf48086f3ad02717799a0 Mon Sep 17 00:00:00 2001 From: yoavpagir Date: Sun, 2 Aug 2026 10:52:24 +0300 Subject: [PATCH 2/4] ci: trigger snapshot build From 7c1cfc36039ad65c7eaf5f4c955c732eefb977a7 Mon Sep 17 00:00:00 2001 From: yoavpagir Date: Sun, 2 Aug 2026 11:00:03 +0300 Subject: [PATCH 3/4] fix: clarify minDistance rationale (MOBAPP-2994) --- packages/react-native-ui-lib/src/components/dialog/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-ui-lib/src/components/dialog/index.tsx b/packages/react-native-ui-lib/src/components/dialog/index.tsx index 3293b99d9d..61fb23d615 100644 --- a/packages/react-native-ui-lib/src/components/dialog/index.tsx +++ b/packages/react-native-ui-lib/src/components/dialog/index.tsx @@ -195,6 +195,7 @@ const Dialog = (props: DialogProps, ref: ForwardedRef) // which fires onPress on END while the touch is still settling) leaks into this freshly-mounted // pan and drives `visibility` mid-open, interrupting the open spring so the sheet rests part-way. // A plain touchable trigger (Button) lifts cleanly before the modal mounts and is unaffected. + // 10dp is small enough to keep drag-to-dismiss responsive while ignoring near-static residual touches. .minDistance(10) .onStart(event => { initialTranslation.value = From 6fbd291f59f0fae75f9c3aa3ca8c79cb76026c64 Mon Sep 17 00:00:00 2001 From: yoavpagir Date: Sun, 2 Aug 2026 14:29:04 +0300 Subject: [PATCH 4/4] test: add minDistance to Pan gesture jest mock (MOBAPP-2994) --- packages/react-native-ui-lib/jestSetup/jest-setup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-native-ui-lib/jestSetup/jest-setup.js b/packages/react-native-ui-lib/jestSetup/jest-setup.js index 992dbe430d..57bae298da 100644 --- a/packages/react-native-ui-lib/jestSetup/jest-setup.js +++ b/packages/react-native-ui-lib/jestSetup/jest-setup.js @@ -79,6 +79,7 @@ jest.mock('react-native-gesture-handler', PanMock.onFinalize = getDefaultMockedHandler('onFinalize'); PanMock.activateAfterLongPress = getDefaultMockedHandler('activateAfterLongPress'); PanMock.enabled = getDefaultMockedHandler('enabled'); + PanMock.minDistance = getDefaultMockedHandler('minDistance'); PanMock.hitSlop = getDefaultMockedHandler('hitSlop'); PanMock.onTouchesMove = getDefaultMockedHandler('onTouchesMove'); PanMock.prepare = jest.fn();