Skip to content

Commit 3e7e8cf

Browse files
committed
Revert "fix: prevent overlay dismiss during in-flight RHP transitions"
This reverts commit a05cfb6.
1 parent a05cfb6 commit 3e7e8cf

2 files changed

Lines changed: 8 additions & 57 deletions

File tree

src/libs/Navigation/AppNavigator/Navigators/Overlay/BaseOverlay.tsx

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {useCardAnimation} from '@react-navigation/stack';
2-
import React, {useCallback} from 'react';
2+
import React from 'react';
33
// eslint-disable-next-line no-restricted-imports
44
import {Animated, View} from 'react-native';
55
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
@@ -21,25 +21,14 @@ type BaseOverlayProps = {
2121

2222
/* Overlay position from the right edge of the container */
2323
positionRightValue?: number | Animated.Value | Animated.AnimatedAddition<number>;
24-
25-
/* When true, the overlay stays visible but swallows clicks without invoking onPress.
26-
Used to block dismiss while an RHP stack transition is in flight (see issue #87174). */
27-
disabled?: boolean;
2824
};
2925

3026
// The default value of positionLeftValue is equal to -2 * variables.sideBarWidth, because we need to stretch the overlay to cover the sidebar and the translate animation distance.
31-
function BaseOverlay({onPress, progress, positionLeftValue = -2 * variables.sideBarWidth, positionRightValue = 0, disabled = false}: BaseOverlayProps) {
27+
function BaseOverlay({onPress, progress, positionLeftValue = -2 * variables.sideBarWidth, positionRightValue = 0}: BaseOverlayProps) {
3228
const styles = useThemeStyles();
3329
const {current} = useCardAnimation();
3430
const {translate} = useLocalize();
3531

36-
const guardedPress = useCallback(() => {
37-
if (disabled) {
38-
return;
39-
}
40-
onPress?.();
41-
}, [disabled, onPress]);
42-
4332
return (
4433
<Animated.View
4534
id="BaseOverlay"
@@ -53,22 +42,20 @@ function BaseOverlay({onPress, progress, positionLeftValue = -2 * variables.side
5342
everything behaves normally like one big pressable */}
5443
<PressableWithoutFeedback
5544
style={[styles.draggableTopBar, styles.boxShadowNone, styles.cursorAuto]}
56-
onPress={guardedPress}
45+
onPress={onPress}
5746
accessibilityLabel={translate('common.close')}
5847
role={CONST.ROLE.BUTTON}
5948
id={CONST.OVERLAY.TOP_BUTTON_NATIVE_ID}
6049
tabIndex={-1}
61-
disabled={disabled}
6250
/>
6351
<PressableWithoutFeedback
6452
style={[styles.flex1, styles.boxShadowNone, styles.cursorAuto]}
65-
onPress={guardedPress}
53+
onPress={onPress}
6654
accessibilityLabel={translate('common.close')}
6755
role={CONST.ROLE.BUTTON}
6856
noDragArea
6957
id={CONST.OVERLAY.BOTTOM_BUTTON_NATIVE_ID}
7058
tabIndex={-1}
71-
disabled={disabled}
7259
/>
7360
</View>
7461
</Animated.View>

src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type {NavigatorScreenParams} from '@react-navigation/native';
22
import {useFocusEffect} from '@react-navigation/native';
3-
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
3+
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
44
// eslint-disable-next-line no-restricted-imports
55
import {Animated, DeviceEventEmitter, InteractionManager} from 'react-native';
66
import {DialogLabelProvider} from '@components/DialogLabelContext';
@@ -61,18 +61,13 @@ function MissingPersonalDetailsWithPINContext(props: Record<string, unknown>) {
6161
);
6262
}
6363

64-
type SecondaryOverlayProps = {
65-
disabled: boolean;
66-
};
67-
68-
function SecondaryOverlay({disabled}: SecondaryOverlayProps) {
64+
function SecondaryOverlay() {
6965
const {shouldRenderSecondaryOverlayForWideRHP, shouldRenderSecondaryOverlayForRHPOnWideRHP, shouldRenderSecondaryOverlayForRHPOnSuperWideRHP} = useWideRHPState();
7066
const {sidePanelOffset} = useSidePanelState();
7167

7268
if (shouldRenderSecondaryOverlayForWideRHP) {
7369
return (
7470
<Overlay
75-
disabled={disabled}
7671
progress={secondOverlayWideRHPProgress}
7772
positionRightValue={Animated.add(sidePanelOffset.current, animatedWideRHPWidth)}
7873
onPress={() => Navigation.closeRHPFlow()}
@@ -83,7 +78,6 @@ function SecondaryOverlay({disabled}: SecondaryOverlayProps) {
8378
if (shouldRenderSecondaryOverlayForRHPOnWideRHP) {
8479
return (
8580
<Overlay
86-
disabled={disabled}
8781
progress={secondOverlayRHPOnWideRHPProgress}
8882
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
8983
onPress={Navigation.dismissToPreviousRHP}
@@ -94,7 +88,6 @@ function SecondaryOverlay({disabled}: SecondaryOverlayProps) {
9488
if (shouldRenderSecondaryOverlayForRHPOnSuperWideRHP) {
9589
return (
9690
<Overlay
97-
disabled={disabled}
9891
progress={secondOverlayRHPOnSuperWideRHPProgress}
9992
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
10093
onPress={Navigation.dismissToSuperWideRHP}
@@ -114,14 +107,6 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
114107
const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
115108
const containerRef = useRef(null);
116109
const isExecutingRef = useRef<boolean>(false);
117-
// Tracks whether the inner RHP stack is currently running a non-closing push/pop animation.
118-
// Clicking the overlay mid-push leaves stale animation state (see issue #87174), so we
119-
// ignore the dismiss press until the in-flight transition finishes. The ref gates the
120-
// synchronous dispatchers; the state mirror drives the `disabled` prop on the overlays so
121-
// the Pressable itself no-ops (defense in depth against cases where the dispatcher path
122-
// bypasses the ref guard, e.g. inline Navigation.dismissToPreviousRHP).
123-
const isOverlayDismissEnabledRef = useRef<boolean>(true);
124-
const [isOverlayDismissEnabled, setIsOverlayDismissEnabled] = useState<boolean>(true);
125110
const screenOptions = useRHPScreenOptions();
126111
const {superWideRHPRouteKeys, shouldRenderTertiaryOverlay} = useWideRHPState();
127112
const {clearWideRHPKeys, syncRHPKeys} = useWideRHPActions();
@@ -180,31 +165,12 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
180165
abandonReviewDuplicateTransactions();
181166
});
182167
},
183-
transitionStart: (event: {data?: {closing?: boolean}}) => {
184-
// Only disable dismiss when a screen is starting to open. A starting close is
185-
// either the user's own dismiss (benign) or a cancellation of an in-flight open
186-
// (handled by transitionEnd below).
187-
if (event.data?.closing) {
188-
return;
189-
}
190-
isOverlayDismissEnabledRef.current = false;
191-
setIsOverlayDismissEnabled(false);
192-
},
193-
transitionEnd: () => {
194-
// Re-enable on ANY transitionEnd (opening or closing). If an opening transition
195-
// is interrupted by a pop, React Navigation cancels the open and only emits
196-
// transitionEnd with closing: true for the popped route — the opening's own
197-
// closing: false end never fires. Ignoring closing: true here would leave the
198-
// gate stuck false forever and swallow subsequent overlay dismiss clicks.
199-
isOverlayDismissEnabledRef.current = true;
200-
setIsOverlayDismissEnabled(true);
201-
},
202168
}),
203169
[navigation, route.params?.screen],
204170
);
205171

206172
const handleOverlayPress = useCallback(() => {
207-
if (isExecutingRef.current || !isOverlayDismissEnabledRef.current) {
173+
if (isExecutingRef.current) {
208174
return;
209175
}
210176
isExecutingRef.current = true;
@@ -249,7 +215,6 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
249215
<NoDropZone>
250216
{!shouldUseNarrowLayout && (
251217
<Overlay
252-
disabled={!isOverlayDismissEnabled}
253218
positionLeftValue={overlayPositionLeft}
254219
onPress={handleOverlayPress}
255220
/>
@@ -501,10 +466,9 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
501466
{/* The third and second overlays are displayed here to cover RHP screens wider than the currently focused screen. */}
502467
{/* Clicking on these overlays redirects you to the RHP screen below them. */}
503468
{/* The width of these overlays is equal to the width of the screen minus the width of the currently focused RHP screen (positionRightValue) */}
504-
{!shouldUseNarrowLayout && <SecondaryOverlay disabled={!isOverlayDismissEnabled} />}
469+
{!shouldUseNarrowLayout && <SecondaryOverlay />}
505470
{!shouldUseNarrowLayout && shouldRenderTertiaryOverlay && (
506471
<Overlay
507-
disabled={!isOverlayDismissEnabled}
508472
progress={thirdOverlayProgress}
509473
positionRightValue={Animated.add(sidePanelOffset.current, variables.sideBarWidth)}
510474
onPress={Navigation.dismissToPreviousRHP}

0 commit comments

Comments
 (0)