diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 75126afbd407..610524fb130f 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -7,6 +7,7 @@
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 01aefab63378..9f12be234ac5 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -3305,6 +3305,6 @@ SPEC CHECKSUMS:
VisionCamera: c6c8aa4b028501fc87644550fbc35a537d4da3fb
Yoga: a1d7895431387402a674fd0d1c04ec85e87909b8
-PODFILE CHECKSUM: 15e2f095b9c80d658459723edf84005a6867debf
+PODFILE CHECKSUM: bf538ad3cea170c0bde913f0530618bf7f098f99
COCOAPODS: 1.15.2
diff --git a/patches/react-native-keyboard-controller+1.14.1+001+disable-android.patch b/patches/react-native-keyboard-controller+1.14.1+001+disable-android.patch
deleted file mode 100644
index 6bb62155a98c..000000000000
--- a/patches/react-native-keyboard-controller+1.14.1+001+disable-android.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-diff --git a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
-index 7ef8b36..f4d44ff 100644
---- a/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
-+++ b/node_modules/react-native-keyboard-controller/android/src/main/java/com/reactnativekeyboardcontroller/views/EdgeToEdgeReactViewGroup.kt
-@@ -74,7 +74,7 @@ class EdgeToEdgeReactViewGroup(
- }
-
- override fun onConfigurationChanged(newConfig: Configuration?) {
-- this.reApplyWindowInsets()
-+ // this.reApplyWindowInsets()
- }
- // endregion
-
-@@ -124,12 +124,12 @@ class EdgeToEdgeReactViewGroup(
- }
-
- private fun goToEdgeToEdge(edgeToEdge: Boolean) {
-- reactContext.currentActivity?.let {
-- WindowCompat.setDecorFitsSystemWindows(
-- it.window,
-- !edgeToEdge,
-- )
-- }
-+ // reactContext.currentActivity?.let {
-+ // WindowCompat.setDecorFitsSystemWindows(
-+ // it.window,
-+ // !edgeToEdge,
-+ // )
-+ // }
- }
-
- private fun setupKeyboardCallbacks() {
-@@ -182,16 +182,16 @@ class EdgeToEdgeReactViewGroup(
- // region State managers
- private fun enable() {
- this.goToEdgeToEdge(true)
-- this.setupWindowInsets()
-+ // this.setupWindowInsets()
- this.setupKeyboardCallbacks()
-- modalAttachedWatcher.enable()
-+ // modalAttachedWatcher.enable()
- }
-
- private fun disable() {
- this.goToEdgeToEdge(false)
-- this.setupWindowInsets()
-+ // this.setupWindowInsets()
- this.removeKeyboardCallbacks()
-- modalAttachedWatcher.disable()
-+ // modalAttachedWatcher.disable()
- }
- // endregion
-
-@@ -219,7 +219,7 @@ class EdgeToEdgeReactViewGroup(
- fun forceStatusBarTranslucent(isStatusBarTranslucent: Boolean) {
- if (active && this.isStatusBarTranslucent != isStatusBarTranslucent) {
- this.isStatusBarTranslucent = isStatusBarTranslucent
-- this.reApplyWindowInsets()
-+ // this.reApplyWindowInsets()
- }
- }
- // endregion
diff --git a/patches/react-native-pager-view+6.4.1+001+native-stack-recycle-crash.patch b/patches/react-native-pager-view+6.4.1+001+native-stack-recycle-crash.patch
new file mode 100644
index 000000000000..da849c43bb32
--- /dev/null
+++ b/patches/react-native-pager-view+6.4.1+001+native-stack-recycle-crash.patch
@@ -0,0 +1,29 @@
+diff --git a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/PagerViewViewManagerImpl.kt b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/PagerViewViewManagerImpl.kt
+index 0abf668..0bfca0a 100644
+--- a/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/PagerViewViewManagerImpl.kt
++++ b/node_modules/react-native-pager-view/android/src/main/java/com/reactnativepagerview/PagerViewViewManagerImpl.kt
+@@ -151,10 +151,20 @@ object PagerViewViewManagerImpl {
+
+ private fun refreshViewChildrenLayout(view: View) {
+ view.post {
+- view.measure(
++ try {
++ view.measure(
+ View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY),
+- View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY))
+- view.layout(view.left, view.top, view.right, view.bottom)
++ View.MeasureSpec.makeMeasureSpec(view.height, View.MeasureSpec.EXACTLY)
++ )
++ view.layout(view.left, view.top, view.right, view.bottom)
++ } catch (e: Exception) {
++ // no-op
++ // fixes a crash: java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled. isScrap:false isAttached:true
++ // It looks like we can not force layout on a recycled views. The safer solution would be simply call .requestLayout(), but I believe that
++ // force layouting was added intentionally and fixes some issues, so we simply wrap the operation with try/catch to not crash the app
++ // patch can be removed when https://github.com/callstack/react-native-pager-view/issues/882 or https://github.com/callstack/react-native-pager-view/issues/859
++ // will be fixed
++ }
+ }
+ }
+ }
+\ No newline at end of file
diff --git a/patches/react-native-screens+3.34.0+003+fabric-flat-list-fix.patch b/patches/react-native-screens+3.34.0+003+fabric-flat-list-fix.patch
new file mode 100644
index 000000000000..3327ed477893
--- /dev/null
+++ b/patches/react-native-screens+3.34.0+003+fabric-flat-list-fix.patch
@@ -0,0 +1,57 @@
+diff --git a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/Screen.kt b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/Screen.kt
+index 9d08d39..146b9c2 100644
+--- a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/Screen.kt
++++ b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/Screen.kt
+@@ -18,6 +18,7 @@ import com.facebook.react.uimanager.PixelUtil
+ import com.facebook.react.uimanager.UIManagerHelper
+ import com.facebook.react.uimanager.UIManagerModule
+ import com.swmansion.rnscreens.events.HeaderHeightChangeEvent
++import com.swmansion.rnscreens.ext.isInsideScrollViewWithRemoveClippedSubviews
+
+ @SuppressLint("ViewConstructor") // Only we construct this view, it is never inflated.
+ class Screen(
+@@ -310,6 +311,16 @@ class Screen(
+ startTransitionRecursive(child.toolbar)
+ }
+ if (child is ViewGroup) {
++ // a combination of https://github.com/software-mansion/react-native-screens/pull/2307/files and https://github.com/software-mansion/react-native-screens/pull/2383/files
++ // The children are miscounted when there's a FlatList with
++ // removeClippedSubviews set to true (default).
++ // We add a simple view for each item in the list to make it work as expected.
++ // See https://github.com/software-mansion/react-native-screens/issues/2282
++ if (child.isInsideScrollViewWithRemoveClippedSubviews()) {
++ for (j in 0 until child.childCount) {
++ child.addView(View(context))
++ }
++ }
+ startTransitionRecursive(child)
+ }
+ }
+diff --git a/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ext/ViewExt.kt b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ext/ViewExt.kt
+new file mode 100644
+index 0000000..9d9fbfd
+--- /dev/null
++++ b/node_modules/react-native-screens/android/src/main/java/com/swmansion/rnscreens/ext/ViewExt.kt
+@@ -0,0 +1,21 @@
++package com.swmansion.rnscreens.ext
++
++import android.view.View
++import android.view.ViewGroup
++import com.facebook.react.views.scroll.ReactHorizontalScrollView
++import com.facebook.react.views.scroll.ReactScrollView
++import com.swmansion.rnscreens.ScreenStack
++
++internal fun View.isInsideScrollViewWithRemoveClippedSubviews(): Boolean {
++ if (this is ReactHorizontalScrollView || this is ReactScrollView) {
++ return false
++ }
++ var parentView = this.parent
++ while (parentView is ViewGroup && parentView !is ScreenStack) {
++ if (parentView is ReactScrollView) {
++ return parentView.removeClippedSubviews
++ }
++ parentView = parentView.parent
++ }
++ return false
++}
+\ No newline at end of file
diff --git a/patches/react-native-screens+3.34.0+004+ios-custom-animations-native-transitions.patch b/patches/react-native-screens+3.34.0+004+ios-custom-animations-native-transitions.patch
new file mode 100644
index 000000000000..62cbf68f458d
--- /dev/null
+++ b/patches/react-native-screens+3.34.0+004+ios-custom-animations-native-transitions.patch
@@ -0,0 +1,156 @@
+diff --git a/node_modules/react-native-screens/ios/RNSScreenStackAnimator.mm b/node_modules/react-native-screens/ios/RNSScreenStackAnimator.mm
+index abb2cf6..fb81d52 100644
+--- a/node_modules/react-native-screens/ios/RNSScreenStackAnimator.mm
++++ b/node_modules/react-native-screens/ios/RNSScreenStackAnimator.mm
+@@ -5,13 +5,14 @@
+
+ // proportions to default transition duration
+ static const float RNSSlideOpenTransitionDurationProportion = 1;
+-static const float RNSFadeOpenTransitionDurationProportion = 0.2 / 0.35;
+-static const float RNSSlideCloseTransitionDurationProportion = 0.25 / 0.35;
+-static const float RNSFadeCloseTransitionDurationProportion = 0.15 / 0.35;
+-static const float RNSFadeCloseDelayTransitionDurationProportion = 0.1 / 0.35;
++static const float RNSFadeOpenTransitionDurationProportion = 0.2 / 0.5;
++static const float RNSSlideCloseTransitionDurationProportion = 0.25 / 0.5;
++static const float RNSFadeCloseTransitionDurationProportion = 0.15 / 0.5;
++static const float RNSFadeCloseDelayTransitionDurationProportion = 0.1 / 0.5;
+ // same value is used in other projects using similar approach for transistions
+ // and it looks the most similar to the value used by Apple
+ static constexpr float RNSShadowViewMaxAlpha = 0.1;
++static const int UIViewAnimationOptionCurveDefaultTransition = 7 << 16;
+
+ @implementation RNSScreenStackAnimator {
+ UINavigationControllerOperation _operation;
+@@ -22,7 +23,7 @@ - (instancetype)initWithOperation:(UINavigationControllerOperation)operation
+ {
+ if (self = [super init]) {
+ _operation = operation;
+- _transitionDuration = 0.35; // default duration in seconds
++ _transitionDuration = 0.5; // default duration in seconds
+ }
+ return self;
+ }
+@@ -129,6 +130,8 @@ - (void)animateSimplePushWithShadowEnabled:(BOOL)shadowEnabled
+ }
+
+ [UIView animateWithDuration:[self transitionDuration:transitionContext]
++ delay:0
++ options:UIViewAnimationOptionCurveDefaultTransition
+ animations:^{
+ fromViewController.view.transform = leftTransform;
+ toViewController.view.transform = CGAffineTransformIdentity;
+@@ -170,6 +173,8 @@ - (void)animateSimplePushWithShadowEnabled:(BOOL)shadowEnabled
+
+ if (!transitionContext.isInteractive) {
+ [UIView animateWithDuration:[self transitionDuration:transitionContext]
++ delay:0
++ options:UIViewAnimationOptionCurveDefaultTransition
+ animations:animationBlock
+ completion:completionBlock];
+ } else {
+@@ -203,6 +208,8 @@ - (void)animateSlideFromLeftWithTransitionContext:(id;
+ stackAnimation?: WithDefault;
+- transitionDuration?: WithDefault;
++ transitionDuration?: WithDefault;
+ replaceAnimation?: WithDefault;
+ swipeDirection?: WithDefault;
+ hideKeyboardOnSwipe?: boolean;
+diff --git a/node_modules/react-native-screens/lib/typescript/fabric/ScreenNativeComponent.d.ts b/node_modules/react-native-screens/lib/typescript/fabric/ScreenNativeComponent.d.ts
+index 11ed190..f676e08 100644
+--- a/node_modules/react-native-screens/lib/typescript/fabric/ScreenNativeComponent.d.ts
++++ b/node_modules/react-native-screens/lib/typescript/fabric/ScreenNativeComponent.d.ts
+@@ -55,7 +55,7 @@ export interface NativeProps extends ViewProps {
+ gestureResponseDistance?: GestureResponseDistanceType;
+ stackPresentation?: WithDefault;
+ stackAnimation?: WithDefault;
+- transitionDuration?: WithDefault;
++ transitionDuration?: WithDefault;
+ replaceAnimation?: WithDefault;
+ swipeDirection?: WithDefault;
+ hideKeyboardOnSwipe?: boolean;
+diff --git a/node_modules/react-native-screens/src/fabric/ModalScreenNativeComponent.ts b/node_modules/react-native-screens/src/fabric/ModalScreenNativeComponent.ts
+index bb59c4c..d4c14ee 100644
+--- a/node_modules/react-native-screens/src/fabric/ModalScreenNativeComponent.ts
++++ b/node_modules/react-native-screens/src/fabric/ModalScreenNativeComponent.ts
+@@ -90,7 +90,7 @@ export interface NativeProps extends ViewProps {
+ gestureResponseDistance?: GestureResponseDistanceType;
+ stackPresentation?: WithDefault;
+ stackAnimation?: WithDefault;
+- transitionDuration?: WithDefault;
++ transitionDuration?: WithDefault;
+ replaceAnimation?: WithDefault;
+ swipeDirection?: WithDefault;
+ hideKeyboardOnSwipe?: boolean;
+diff --git a/node_modules/react-native-screens/src/fabric/ScreenNativeComponent.ts b/node_modules/react-native-screens/src/fabric/ScreenNativeComponent.ts
+index 4e39336..ab0b313 100644
+--- a/node_modules/react-native-screens/src/fabric/ScreenNativeComponent.ts
++++ b/node_modules/react-native-screens/src/fabric/ScreenNativeComponent.ts
+@@ -92,7 +92,7 @@ export interface NativeProps extends ViewProps {
+ gestureResponseDistance?: GestureResponseDistanceType;
+ stackPresentation?: WithDefault;
+ stackAnimation?: WithDefault;
+- transitionDuration?: WithDefault;
++ transitionDuration?: WithDefault;
+ replaceAnimation?: WithDefault;
+ swipeDirection?: WithDefault;
+ hideKeyboardOnSwipe?: boolean;
\ No newline at end of file
diff --git a/patches/react-native-screens+3.34.0+005+fix-screen-flicker-on-modal-unmount.patch b/patches/react-native-screens+3.34.0+005+fix-screen-flicker-on-modal-unmount.patch
new file mode 100644
index 000000000000..bbeedbc57873
--- /dev/null
+++ b/patches/react-native-screens+3.34.0+005+fix-screen-flicker-on-modal-unmount.patch
@@ -0,0 +1,22 @@
+diff --git a/node_modules/react-native-screens/ios/RNSScreenStack.mm b/node_modules/react-native-screens/ios/RNSScreenStack.mm
+index ea27b03..8f1d005 100644
+--- a/node_modules/react-native-screens/ios/RNSScreenStack.mm
++++ b/node_modules/react-native-screens/ios/RNSScreenStack.mm
+@@ -1121,16 +1121,7 @@ - (void)mountChildComponentView:(UIView *)childCompone
+ - (void)unmountChildComponentView:(UIView *)childComponentView index:(NSInteger)index
+ {
+ RNSScreenView *screenChildComponent = (RNSScreenView *)childComponentView;
+-
+- // We should only do a snapshot of a screen that is on the top.
+- // We also check `_presentedModals` since if you push 2 modals, second one is not a "child" of _controller.
+- // Also, when dissmised with a gesture, the screen already is not under the window, so we don't need to apply
+- // snapshot.
+- if (screenChildComponent.window != nil &&
+- ((screenChildComponent == _controller.visibleViewController.view && _presentedModals.count < 2) ||
+- screenChildComponent == [_presentedModals.lastObject view])) {
+- [screenChildComponent.controller setViewToSnapshot];
+- }
++ [screenChildComponent.controller setViewToSnapshot];
+
+ RCTAssert(
+ screenChildComponent.reactSuperview == self,
diff --git a/src/App.tsx b/src/App.tsx
index 643e2146e501..52904e0a06c4 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -2,7 +2,6 @@ import {PortalProvider} from '@gorhom/portal';
import React from 'react';
import {LogBox} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
-import {KeyboardProvider} from 'react-native-keyboard-controller';
import {PickerStateProvider} from 'react-native-picker-select';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import '../wdyr';
@@ -15,6 +14,7 @@ import CustomStatusBarAndBackgroundContextProvider from './components/CustomStat
import ErrorBoundary from './components/ErrorBoundary';
import HTMLEngineProvider from './components/HTMLEngineProvider';
import InitialURLContextProvider from './components/InitialURLContextProvider';
+import KeyboardProvider from './components/KeyboardProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
import OnyxProvider from './components/OnyxProvider';
import PopoverContextProvider from './components/PopoverProvider';
diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx
index 207f3eed6f8c..592db299e3e5 100644
--- a/src/components/AttachmentModal.tsx
+++ b/src/components/AttachmentModal.tsx
@@ -491,7 +491,6 @@ function AttachmentModal({
<>
{
diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx
index fd2013c6bde7..637a514b53f3 100755
--- a/src/components/ConfirmModal.tsx
+++ b/src/components/ConfirmModal.tsx
@@ -143,7 +143,6 @@ function ConfirmModal({
return (
{
+ const {reanimated} = useKeyboardContext();
+
+ // calculate it only once on mount, to avoid `SharedValue` reads during a render
+ const [initialHeight] = useState(() => -reanimated.height.value);
+ const [initialProgress] = useState(() => reanimated.progress.value);
+
+ const heightWhenOpened = useSharedValue(initialHeight);
+ const height = useSharedValue(initialHeight);
+ const progress = useSharedValue(initialProgress);
+ const isClosed = useSharedValue(initialProgress === 0);
+
+ useKeyboardHandler(
+ {
+ onStart: (e) => {
+ 'worklet';
+
+ progress.value = e.progress;
+ height.value = e.height;
+
+ if (e.height > 0) {
+ // eslint-disable-next-line react-compiler/react-compiler
+ isClosed.value = false;
+ heightWhenOpened.value = e.height;
+ }
+ },
+ onEnd: (e) => {
+ 'worklet';
+
+ isClosed.value = e.height === 0;
+
+ height.value = e.height;
+ progress.value = e.progress;
+ },
+ },
+ [],
+ );
+
+ return {height, progress, heightWhenOpened, isClosed};
+};
+
+const defaultLayout: LayoutRectangle = {
+ x: 0,
+ y: 0,
+ width: 0,
+ height: 0,
+};
+
+/**
+ * View that moves out of the way when the keyboard appears by automatically
+ * adjusting its height, position, or bottom padding.
+ *
+ * This `KeyboardAvoidingView` acts as a backward compatible layer for the previous Android behavior (prior to edge-to-edge mode).
+ * We can use `KeyboardAvoidingView` directly from the `react-native-keyboard-controller` package, but in this case animations are stuttering and it's better to handle as a separate task.
+ */
+const KeyboardAvoidingView = forwardRef>(
+ ({behavior, children, contentContainerStyle, enabled = true, keyboardVerticalOffset = 0, style, onLayout: onLayoutProps, ...props}, ref) => {
+ const initialFrame = useSharedValue(null);
+ const frame = useDerivedValue(() => initialFrame.value ?? defaultLayout);
+
+ const keyboard = useKeyboardAnimation();
+ const {height: screenHeight} = useSafeAreaFrame();
+
+ const relativeKeyboardHeight = useCallback(() => {
+ 'worklet';
+
+ const keyboardY = screenHeight - keyboard.heightWhenOpened.value - keyboardVerticalOffset;
+
+ return Math.max(frame.value.y + frame.value.height - keyboardY, 0);
+ }, [screenHeight, keyboardVerticalOffset]);
+
+ const onLayoutWorklet = useCallback((layout: LayoutRectangle) => {
+ 'worklet';
+
+ if (keyboard.isClosed.value || initialFrame.value === null) {
+ // eslint-disable-next-line react-compiler/react-compiler
+ initialFrame.value = layout;
+ }
+ }, []);
+ const onLayout = useCallback>(
+ (e) => {
+ runOnUI(onLayoutWorklet)(e.nativeEvent.layout);
+ onLayoutProps?.(e);
+ },
+ [onLayoutProps],
+ );
+
+ const animatedStyle = useAnimatedStyle(() => {
+ const bottom = interpolate(keyboard.progress.value, [0, 1], [0, relativeKeyboardHeight()]);
+ const bottomHeight = enabled ? bottom : 0;
+
+ switch (behavior) {
+ case 'height':
+ if (!keyboard.isClosed.value) {
+ return {
+ height: frame.value.height - bottomHeight,
+ flex: 0,
+ };
+ }
+
+ return {};
+
+ case 'padding':
+ return {paddingBottom: bottomHeight};
+
+ default:
+ return {};
+ }
+ }, [behavior, enabled, relativeKeyboardHeight]);
+ const combinedStyles = useMemo(() => [style, animatedStyle], [style, animatedStyle]);
+
+ return (
+
+ {children}
+
+ );
+ },
+);
+
+export default KeyboardAvoidingView;
diff --git a/src/components/KeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/index.tsx
index c0882ae1e9cc..4a24d6cab618 100644
--- a/src/components/KeyboardAvoidingView/index.tsx
+++ b/src/components/KeyboardAvoidingView/index.tsx
@@ -1,16 +1,10 @@
-/*
- * The KeyboardAvoidingView is only used on ios
- */
import React from 'react';
-import {View} from 'react-native';
+import {KeyboardAvoidingView as KeyboardAvoidingViewComponent} from 'react-native-keyboard-controller';
import type {KeyboardAvoidingViewProps} from './types';
function KeyboardAvoidingView(props: KeyboardAvoidingViewProps) {
- const {behavior, contentContainerStyle, enabled, keyboardVerticalOffset, ...rest} = props;
- return (
- // eslint-disable-next-line react/jsx-props-no-spreading
-
- );
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ return ;
}
KeyboardAvoidingView.displayName = 'KeyboardAvoidingView';
diff --git a/src/components/KeyboardProvider/index.tsx b/src/components/KeyboardProvider/index.tsx
new file mode 100644
index 000000000000..bf2b003abea3
--- /dev/null
+++ b/src/components/KeyboardProvider/index.tsx
@@ -0,0 +1,15 @@
+import type {PropsWithChildren} from 'react';
+import {KeyboardProvider} from 'react-native-keyboard-controller';
+
+function KeyboardProviderWrapper({children}: PropsWithChildren>) {
+ return (
+
+ {children}
+
+ );
+}
+
+export default KeyboardProviderWrapper;
diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts
index 6ced829e93d6..36bcf17fe3fa 100644
--- a/src/components/Modal/types.ts
+++ b/src/components/Modal/types.ts
@@ -36,9 +36,6 @@ type BaseModalProps = Partial & {
/** State that determines whether to display the modal or not */
isVisible: boolean;
- /** Callback method fired when the user requests to submit the modal content. */
- onSubmit?: () => void;
-
/** Callback method fired when the modal is hidden */
onModalHide?: () => void;
diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
index 8d9def814549..62d4520dba7a 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
+++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
@@ -1,4 +1,3 @@
-import type {RouteProp} from '@react-navigation/native';
import {useRoute} from '@react-navigation/native';
import lodashSortBy from 'lodash/sortBy';
import truncate from 'lodash/truncate';
@@ -29,6 +28,7 @@ import * as CurrencyUtils from '@libs/CurrencyUtils';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {TransactionDuplicateNavigatorParamList} from '@libs/Navigation/types';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
@@ -71,7 +71,7 @@ function MoneyRequestPreviewContent({
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const {windowWidth} = useWindowDimensions();
- const route = useRoute>();
+ const route = useRoute>();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID || '-1'}`);
diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx
index c74ccf0470d0..ae582867e070 100644
--- a/src/components/ScreenWrapper.tsx
+++ b/src/components/ScreenWrapper.tsx
@@ -1,5 +1,4 @@
import {UNSTABLE_usePreventRemove, useIsFocused, useNavigation, useRoute} from '@react-navigation/native';
-import type {StackNavigationProp} from '@react-navigation/stack';
import type {ForwardedRef, ReactNode} from 'react';
import React, {createContext, forwardRef, useEffect, useMemo, useRef, useState} from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
@@ -15,6 +14,7 @@ import useTackInputFocus from '@hooks/useTackInputFocus';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
+import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList, RootStackParamList} from '@libs/Navigation/types';
import toggleTestToolsModal from '@userActions/TestTool';
import CONST from '@src/CONST';
@@ -96,7 +96,7 @@ type ScreenWrapperProps = {
*
* This is required because transitionEnd event doesn't trigger in the testing environment.
*/
- navigation?: StackNavigationProp | StackNavigationProp;
+ navigation?: PlatformStackNavigationProp | PlatformStackNavigationProp;
/** Whether to show offline indicator on wide screens */
shouldShowOfflineIndicatorInWideScreen?: boolean;
@@ -141,7 +141,7 @@ function ScreenWrapper(
* so in other places where ScreenWrapper is used, we need to
* fallback to useNavigation.
*/
- const navigationFallback = useNavigation>();
+ const navigationFallback = useNavigation>();
const navigation = navigationProp ?? navigationFallback;
const isFocused = useIsFocused();
const {windowHeight} = useWindowDimensions(shouldUseCachedViewportHeight);
diff --git a/src/components/ScrollOffsetContextProvider.tsx b/src/components/ScrollOffsetContextProvider.tsx
index d7815d7a65a0..78d8c5ed61fb 100644
--- a/src/components/ScrollOffsetContextProvider.tsx
+++ b/src/components/ScrollOffsetContextProvider.tsx
@@ -1,7 +1,8 @@
-import type {ParamListBase, RouteProp} from '@react-navigation/native';
+import type {ParamListBase} from '@react-navigation/native';
import React, {createContext, useCallback, useEffect, useMemo, useRef} from 'react';
import {withOnyx} from 'react-native-onyx';
import usePrevious from '@hooks/usePrevious';
+import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {NavigationPartialRoute, State} from '@libs/Navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -10,10 +11,10 @@ import type {PriorityMode} from '@src/types/onyx';
type ScrollOffsetContextValue = {
/** Save scroll offset of flashlist on given screen */
- saveScrollOffset: (route: RouteProp, scrollOffset: number) => void;
+ saveScrollOffset: (route: PlatformStackRouteProp, scrollOffset: number) => void;
/** Get scroll offset value for given screen */
- getScrollOffset: (route: RouteProp) => number | undefined;
+ getScrollOffset: (route: PlatformStackRouteProp) => number | undefined;
/** Clean scroll offsets of screen that aren't anymore in the state */
cleanStaleScrollOffsets: (state: State) => void;
@@ -38,7 +39,7 @@ const defaultValue: ScrollOffsetContextValue = {
const ScrollOffsetContext = createContext(defaultValue);
/** This function is prepared to work with HOME screens. May need modification if we want to handle other types of screens. */
-function getKey(route: RouteProp | NavigationPartialRoute): string {
+function getKey(route: PlatformStackRouteProp | NavigationPartialRoute): string {
if (route.params && 'policyID' in route.params && typeof route.params.policyID === 'string') {
return `${route.name}-${route.params.policyID}`;
}
diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx
index f7ebeb6907fe..f0d694c3a3ff 100644
--- a/src/components/Search/index.tsx
+++ b/src/components/Search/index.tsx
@@ -1,5 +1,4 @@
import {useIsFocused, useNavigation} from '@react-navigation/native';
-import type {StackNavigationProp} from '@react-navigation/stack';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native';
@@ -21,6 +20,7 @@ import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Log from '@libs/Log';
import memoize from '@libs/memoize';
import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane';
+import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as SearchQueryUtils from '@libs/SearchQueryUtils';
import * as SearchUIUtils from '@libs/SearchUIUtils';
@@ -93,7 +93,7 @@ function Search({queryJSON, onSearchListScroll, isSearchScreenFocused, contentCo
// We need to use isSmallScreenWidth instead of shouldUseNarrowLayout for enabling the selection mode on small screens only
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout();
- const navigation = useNavigation>();
+ const navigation = useNavigation>();
const isFocused = useIsFocused();
const [lastNonEmptySearchResults, setLastNonEmptySearchResults] = useState(undefined);
const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading, lastSearchType, setLastSearchType} =
diff --git a/src/components/SelectionList/BaseSelectionList.tsx b/src/components/SelectionList/BaseSelectionList.tsx
index b7bef18896d1..eb8d082f2953 100644
--- a/src/components/SelectionList/BaseSelectionList.tsx
+++ b/src/components/SelectionList/BaseSelectionList.tsx
@@ -624,7 +624,7 @@ function BaseSelectionList(
if (shouldDelayFocus) {
focusTimeoutRef.current = setTimeout(focusTextInput, CONST.ANIMATED_TRANSITION);
} else {
- focusTextInput();
+ requestAnimationFrame(focusTextInput);
}
}
diff --git a/src/components/WorkspaceSwitcherButton.tsx b/src/components/WorkspaceSwitcherButton.tsx
index 9ad0ffefafa1..d47f243af736 100644
--- a/src/components/WorkspaceSwitcherButton.tsx
+++ b/src/components/WorkspaceSwitcherButton.tsx
@@ -18,9 +18,14 @@ type WorkspaceSwitcherButtonOnyxProps = {
policy: OnyxEntry;
};
-type WorkspaceSwitcherButtonProps = WorkspaceSwitcherButtonOnyxProps;
+type WorkspaceSwitcherButtonProps = WorkspaceSwitcherButtonOnyxProps & {
+ /**
+ * Callback used to keep track of the workspace switching process in the BaseSidebarScreen.
+ */
+ onSwitchWorkspace?: () => void;
+};
-function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) {
+function WorkspaceSwitcherButton({policy, onSwitchWorkspace}: WorkspaceSwitcherButtonProps) {
const {translate} = useLocalize();
const theme = useTheme();
@@ -48,6 +53,7 @@ function WorkspaceSwitcherButton({policy}: WorkspaceSwitcherButtonProps) {
accessibilityLabel={translate('common.workspaces')}
accessible
onPress={() => {
+ onSwitchWorkspace?.();
pressableRef?.current?.blur();
interceptAnonymousUser(() => {
Navigation.navigate(ROUTES.WORKSPACE_SWITCHER);
diff --git a/src/components/withNavigationTransitionEnd.tsx b/src/components/withNavigationTransitionEnd.tsx
index 83f14a1d58ef..69e04ff22e35 100644
--- a/src/components/withNavigationTransitionEnd.tsx
+++ b/src/components/withNavigationTransitionEnd.tsx
@@ -1,8 +1,8 @@
import {useNavigation} from '@react-navigation/native';
-import type {StackNavigationProp} from '@react-navigation/stack';
import type {ComponentType, ForwardedRef, RefAttributes} from 'react';
import React, {useEffect, useState} from 'react';
import getComponentDisplayName from '@libs/getComponentDisplayName';
+import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {RootStackParamList} from '@libs/Navigation/types';
type WithNavigationTransitionEndProps = {didScreenTransitionEnd: boolean};
@@ -10,7 +10,7 @@ type WithNavigationTransitionEndProps = {didScreenTransitionEnd: boolean};
export default function (WrappedComponent: ComponentType>): React.ComponentType> {
function WithNavigationTransitionEnd(props: TProps, ref: ForwardedRef) {
const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false);
- const navigation = useNavigation>();
+ const navigation = useNavigation>();
useEffect(() => {
const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', () => {
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
index 0923287d6cdb..953faa955e75 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx
@@ -1,4 +1,4 @@
-import React, {memo, useEffect, useMemo, useRef, useState} from 'react';
+import React, {memo, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx, {withOnyx} from 'react-native-onyx';
@@ -14,15 +14,14 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace';
import useOnboardingFlowRouter from '@hooks/useOnboardingFlow';
import usePermissions from '@hooks/usePermissions';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {READ_COMMANDS} from '@libs/API/types';
import HttpUtils from '@libs/HttpUtils';
import KeyboardShortcut from '@libs/KeyboardShortcut';
import Log from '@libs/Log';
import getCurrentUrl from '@libs/Navigation/currentUrl';
-import getOnboardingModalScreenOptions from '@libs/Navigation/getOnboardingModalScreenOptions';
import Navigation from '@libs/Navigation/Navigation';
+import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation';
import shouldOpenOnAdminRoom from '@libs/Navigation/shouldOpenOnAdminRoom';
import type {AuthScreensParamList, CentralPaneName, CentralPaneScreensParamList} from '@libs/Navigation/types';
import NetworkConnection from '@libs/NetworkConnection';
@@ -56,9 +55,9 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import beforeRemoveReportOpenedFromSearchRHP from './beforeRemoveReportOpenedFromSearchRHP';
import CENTRAL_PANE_SCREENS from './CENTRAL_PANE_SCREENS';
-import createCustomStackNavigator from './createCustomStackNavigator';
+import createResponsiveStackNavigator from './createResponsiveStackNavigator';
import defaultScreenOptions from './defaultScreenOptions';
-import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions';
+import hideKeyboardOnSwipe from './hideKeyboardOnSwipe';
import BottomTabNavigator from './Navigators/BottomTabNavigator';
import ExplanationModalNavigator from './Navigators/ExplanationModalNavigator';
import FeatureTrainingModalNavigator from './Navigators/FeatureTrainingModalNavigator';
@@ -67,6 +66,7 @@ import LeftModalNavigator from './Navigators/LeftModalNavigator';
import OnboardingModalNavigator from './Navigators/OnboardingModalNavigator';
import RightModalNavigator from './Navigators/RightModalNavigator';
import WelcomeVideoModalNavigator from './Navigators/WelcomeVideoModalNavigator';
+import useRootNavigatorOptions from './useRootNavigatorOptions';
type AuthScreensProps = {
/** Session of currently logged in user */
@@ -194,7 +194,7 @@ function handleNetworkReconnect() {
}
}
-const RootStack = createCustomStackNavigator();
+const RootStack = createResponsiveStackNavigator();
// We want to delay the re-rendering for components(e.g. ReportActionCompose)
// that depends on modal visibility until Modal is completely closed and its focused
// When modal screen is focused, update modal visibility in Onyx
@@ -224,20 +224,12 @@ const modalScreenListenersWithCancelSearch = {
function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDAppliedToClient}: AuthScreensProps) {
const styles = useThemeStyles();
- const StyleUtils = useStyleUtils();
- // We need to use isSmallScreenWidth for the root stack navigator
- // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
- const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, isSmallScreenWidth} = useResponsiveLayout();
- const screenOptions = getRootNavigatorScreenOptions(shouldUseNarrowLayout, styles, StyleUtils);
+ const {shouldUseNarrowLayout} = useResponsiveLayout();
+ const rootNavigatorOptions = useRootNavigatorOptions();
const {canUseDefaultRooms} = usePermissions();
const {activeWorkspaceID} = useActiveWorkspace();
const {toggleSearchRouter} = useSearchRouterContext();
- const onboardingModalScreenOptions = useMemo(() => screenOptions.onboardingModalNavigator(onboardingIsMediumOrLargerScreenWidth), [screenOptions, onboardingIsMediumOrLargerScreenWidth]);
- const onboardingScreenOptions = useMemo(
- () => getOnboardingModalScreenOptions(shouldUseNarrowLayout, styles, StyleUtils, onboardingIsMediumOrLargerScreenWidth),
- [StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles],
- );
const modal = useRef({});
const [didPusherInit, setDidPusherInit] = useState(false);
const {isOnboardingCompleted} = useOnboardingFlowRouter();
@@ -389,6 +381,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
}, []);
const CentralPaneScreenOptions = {
+ ...hideKeyboardOnSwipe,
headerShown: false,
title: 'New Expensify',
@@ -399,19 +392,16 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
return (
-
+
{isOnboardingCompleted === false && (
{
@@ -533,7 +524,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
name={SCREENS.WORKSPACE_JOIN_USER}
options={{
headerShown: false,
- presentation: 'transparentModal',
+ presentation: Presentation.TRANSPARENT_MODAL,
}}
listeners={modalScreenListeners}
getComponent={loadWorkspaceJoinUser}
@@ -542,14 +533,14 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
name={SCREENS.TRANSACTION_RECEIPT}
options={{
headerShown: false,
- presentation: 'transparentModal',
+ presentation: Presentation.TRANSPARENT_MODAL,
}}
getComponent={loadReceiptView}
listeners={modalScreenListeners}
/>
{Object.entries(CENTRAL_PANE_SCREENS).map(([screenName, componentGetter]) => {
diff --git a/src/libs/Navigation/AppNavigator/ModalNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/ModalNavigatorScreenOptions.ts
deleted file mode 100644
index 9dcbe8143b4a..000000000000
--- a/src/libs/Navigation/AppNavigator/ModalNavigatorScreenOptions.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import type {StackNavigationOptions} from '@react-navigation/stack';
-import {CardStyleInterpolators} from '@react-navigation/stack';
-import type {GestureDirection} from '@react-navigation/stack/lib/typescript/src/types';
-import type {ThemeStyles} from '@styles/index';
-
-/**
- * Modal stack navigator screen options generator function
- * @param themeStyles - The styles object
- * @returns The screen options object
- */
-const ModalNavigatorScreenOptions = (themeStyles: ThemeStyles, gestureDirection: GestureDirection = 'horizontal'): StackNavigationOptions => ({
- headerShown: false,
- animationEnabled: true,
- gestureDirection,
- cardStyle: themeStyles.navigationScreenCardStyle,
- cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
-});
-
-export default ModalNavigatorScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 8c0d45e8c313..341f4c6d327c 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -1,7 +1,6 @@
import type {ParamListBase} from '@react-navigation/routers';
-import type {StackNavigationOptions} from '@react-navigation/stack';
-import {createStackNavigator} from '@react-navigation/stack';
import React from 'react';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
import type {
AddPersonalBankAccountNavigatorParamList,
DebugParamList,
@@ -33,11 +32,11 @@ import type {
TravelNavigatorParamList,
WalletStatementNavigatorParamList,
} from '@navigation/types';
-import type {ThemeStyles} from '@styles/index';
import type {Screen} from '@src/SCREENS';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
-import useModalScreenOptions from './useModalScreenOptions';
+import type {GetModalStackScreenOptions} from './useModalStackScreenOptions';
+import useModalStackScreenOptions from './useModalStackScreenOptions';
type Screens = Partial React.ComponentType>>;
@@ -47,11 +46,11 @@ type Screens = Partial React.ComponentType>>;
* @param screens key/value pairs where the key is the name of the screen and the value is a functon that returns the lazy-loaded component
* @param getScreenOptions optional function that returns the screen options, override the default options
*/
-function createModalStackNavigator(screens: Screens, getScreenOptions?: (styles: ThemeStyles) => StackNavigationOptions): React.ComponentType {
- const ModalStackNavigator = createStackNavigator();
+function createModalStackNavigator(screens: Screens, getScreenOptions?: GetModalStackScreenOptions): React.ComponentType {
+ const ModalStackNavigator = createPlatformStackNavigator();
function ModalStack() {
- const screenOptions = useModalScreenOptions(getScreenOptions);
+ const screenOptions = useModalStackScreenOptions(getScreenOptions);
return (
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts
deleted file mode 100644
index 2193dcb2bf6b..000000000000
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalScreenOptions.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import type {StackCardInterpolationProps, StackNavigationOptions} from '@react-navigation/stack';
-import {CardStyleInterpolators} from '@react-navigation/stack';
-import {useMemo} from 'react';
-import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyleUtils from '@hooks/useStyleUtils';
-import useThemeStyles from '@hooks/useThemeStyles';
-import {isSafari} from '@libs/Browser';
-import createModalCardStyleInterpolator from '@navigation/AppNavigator/createModalCardStyleInterpolator';
-import type {ThemeStyles} from '@src/styles';
-
-function useModalScreenOptions(getScreenOptions?: (styles: ThemeStyles) => StackNavigationOptions) {
- const styles = useThemeStyles();
- const styleUtils = useStyleUtils();
- const {shouldUseNarrowLayout} = useResponsiveLayout();
-
- let cardStyleInterpolator = CardStyleInterpolators.forHorizontalIOS;
-
- if (isSafari()) {
- const customInterpolator = createModalCardStyleInterpolator(styleUtils);
- cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(shouldUseNarrowLayout, false, false, props);
- }
-
- const defaultSubRouteOptions = useMemo(
- (): StackNavigationOptions => ({
- cardStyle: styles.navigationScreenCardStyle,
- headerShown: false,
- cardStyleInterpolator,
- }),
- [styles, cardStyleInterpolator],
- );
-
- return getScreenOptions?.(styles) ?? defaultSubRouteOptions;
-}
-
-export default useModalScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalStackScreenOptions.ts b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalStackScreenOptions.ts
new file mode 100644
index 000000000000..3dc189cb8dcd
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/useModalStackScreenOptions.ts
@@ -0,0 +1,42 @@
+import type {StackCardInterpolationProps} from '@react-navigation/stack';
+import {CardStyleInterpolators} from '@react-navigation/stack';
+import {useMemo} from 'react';
+import useThemeStyles from '@hooks/useThemeStyles';
+import {isSafari} from '@libs/Browser';
+import hideKeyboardOnSwipe from '@libs/Navigation/AppNavigator/hideKeyboardOnSwipe';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import useModalCardStyleInterpolator from '@navigation/AppNavigator/useModalCardStyleInterpolator';
+import type {ThemeStyles} from '@src/styles';
+
+type GetModalStackScreenOptions = (styles: ThemeStyles) => PlatformStackNavigationOptions;
+
+function useModalStackScreenOptions(getScreenOptions?: GetModalStackScreenOptions) {
+ const styles = useThemeStyles();
+ const customInterpolator = useModalCardStyleInterpolator();
+
+ let cardStyleInterpolator = CardStyleInterpolators.forHorizontalIOS;
+
+ if (isSafari()) {
+ cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator({props});
+ }
+
+ const defaultSubRouteOptions = useMemo(
+ (): PlatformStackNavigationOptions => ({
+ ...hideKeyboardOnSwipe,
+ headerShown: false,
+ native: {
+ contentStyle: styles.navigationScreenCardStyle,
+ },
+ web: {
+ cardStyle: styles.navigationScreenCardStyle,
+ cardStyleInterpolator,
+ },
+ }),
+ [cardStyleInterpolator, styles.navigationScreenCardStyle],
+ );
+
+ return getScreenOptions?.(styles) ?? defaultSubRouteOptions;
+}
+
+export default useModalStackScreenOptions;
+export type {GetModalStackScreenOptions};
diff --git a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
index 30e8d4c668c6..62cceee9f400 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/BottomTabNavigator.tsx
@@ -1,8 +1,8 @@
import {useNavigationState} from '@react-navigation/native';
-import type {StackNavigationOptions} from '@react-navigation/stack';
import React from 'react';
import createCustomBottomTabNavigator from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator';
import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
import type {BottomTabNavigatorParamList, CentralPaneName, NavigationPartialRoute, RootStackParamList} from '@libs/Navigation/types';
import SidebarScreen from '@pages/home/sidebar/SidebarScreen';
import SearchPageBottomTab from '@pages/Search/SearchPageBottomTab';
@@ -13,9 +13,8 @@ import ActiveCentralPaneRouteContext from './ActiveCentralPaneRouteContext';
const loadInitialSettingsPage = () => require('../../../../pages/settings/InitialSettingsPage').default;
const Tab = createCustomBottomTabNavigator();
-const screenOptions: StackNavigationOptions = {
+const screenOptions: PlatformStackNavigationOptions = {
headerShown: false,
- animationEnabled: false,
};
function BottomTabNavigator() {
diff --git a/src/libs/Navigation/AppNavigator/Navigators/ExplanationModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/ExplanationModalNavigator.tsx
index f4136bb8783a..507abedf7102 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/ExplanationModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/ExplanationModalNavigator.tsx
@@ -1,18 +1,19 @@
-import {createStackNavigator} from '@react-navigation/stack';
import React from 'react';
import {View} from 'react-native';
import NoDropZone from '@components/DragAndDrop/NoDropZone';
import ExplanationModal from '@components/ExplanationModal';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
+import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
import type {ExplanationModalNavigatorParamList} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
-const Stack = createStackNavigator();
+const Stack = createPlatformStackNavigator();
function ExplanationModalNavigator() {
return (
-
+
();
+const Stack = createPlatformStackNavigator();
function FeatureTrainingModalNavigator() {
return (
-
+
-
+
{Object.entries(CENTRAL_PANE_WORKSPACE_SCREENS).map(([screenName, componentGetter]) => (
diff --git a/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx
index 50439c19845e..aaf40a62f99e 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/LeftModalNavigator.tsx
@@ -1,27 +1,27 @@
-import type {StackScreenProps} from '@react-navigation/stack';
-import {createStackNavigator} from '@react-navigation/stack';
-import React, {useMemo} from 'react';
+import React from 'react';
import {View} from 'react-native';
import NoDropZone from '@components/DragAndDrop/NoDropZone';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
-import ModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/ModalNavigatorScreenOptions';
+import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSideModalStackScreenOptions';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList, LeftModalNavigatorParamList} from '@libs/Navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import type ReactComponentModule from '@src/types/utils/ReactComponentModule';
import Overlay from './Overlay';
-type LeftModalNavigatorProps = StackScreenProps;
+type LeftModalNavigatorProps = PlatformStackScreenProps;
const loadWorkspaceSwitcherPage = () => require('../../../../pages/WorkspaceSwitcherPage').default;
-const Stack = createStackNavigator();
+const Stack = createPlatformStackNavigator();
function LeftModalNavigator({navigation}: LeftModalNavigatorProps) {
const styles = useThemeStyles();
const {shouldUseNarrowLayout} = useResponsiveLayout();
- const screenOptions = useMemo(() => ModalNavigatorScreenOptions(styles, 'horizontal-inverted'), [styles]);
+ const screenOptions = useSideModalStackScreenOptions('horizontal-inverted');
return (
diff --git a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
index 401e6b6ec809..21303b03a5df 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/OnboardingModalNavigator.tsx
@@ -1,4 +1,4 @@
-import {createStackNavigator} from '@react-navigation/stack';
+import {CardStyleInterpolators} from '@react-navigation/stack';
import React, {useCallback, useEffect} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -8,7 +8,8 @@ import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import GoogleTagManager from '@libs/GoogleTagManager';
-import OnboardingModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/OnboardingModalNavigatorScreenOptions';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types';
import OnboardingRefManager from '@libs/OnboardingRefManager';
import OnboardingAccounting from '@pages/OnboardingAccounting';
@@ -20,7 +21,14 @@ import ONYXKEYS from '@src/ONYXKEYS';
import SCREENS from '@src/SCREENS';
import Overlay from './Overlay';
-const Stack = createStackNavigator();
+const defaultScreenOptions: PlatformStackNavigationOptions = {
+ headerShown: false,
+ web: {
+ cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+ },
+};
+
+const Stack = createPlatformStackNavigator();
function OnboardingModalNavigator() {
const styles = useThemeStyles();
@@ -57,7 +65,7 @@ function OnboardingModalNavigator() {
onClick={(e) => e.stopPropagation()}
style={styles.OnboardingNavigatorInnerView(onboardingIsMediumOrLargerScreenWidth)}
>
-
+
) {
- return (
-
- );
+function Overlay() {
+ return null;
}
Overlay.displayName = 'Overlay';
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
index da1ce32bf747..c996f380e98c 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx
@@ -1,40 +1,47 @@
-import type {StackCardInterpolationProps, StackScreenProps} from '@react-navigation/stack';
-import {createStackNavigator} from '@react-navigation/stack';
+import type {StackCardInterpolationProps} from '@react-navigation/stack';
import React, {useMemo, useRef} from 'react';
import {InteractionManager, View} from 'react-native';
import NoDropZone from '@components/DragAndDrop/NoDropZone';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {abandonReviewDuplicateTransactions} from '@libs/actions/Transaction';
import {isSafari} from '@libs/Browser';
-import ModalNavigatorScreenOptions from '@libs/Navigation/AppNavigator/ModalNavigatorScreenOptions';
+import hideKeyboardOnSwipe from '@libs/Navigation/AppNavigator/hideKeyboardOnSwipe';
import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators';
-import createModalCardStyleInterpolator from '@navigation/AppNavigator/createModalCardStyleInterpolator';
+import useModalCardStyleInterpolator from '@libs/Navigation/AppNavigator/useModalCardStyleInterpolator';
+import useSideModalStackScreenOptions from '@libs/Navigation/AppNavigator/useSideModalStackScreenOptions';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList, RightModalNavigatorParamList} from '@navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import Overlay from './Overlay';
-type RightModalNavigatorProps = StackScreenProps;
+type RightModalNavigatorProps = PlatformStackScreenProps;
-const Stack = createStackNavigator();
+const Stack = createPlatformStackNavigator();
function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
const styles = useThemeStyles();
- const styleUtils = useStyleUtils();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const isExecutingRef = useRef(false);
+ const customInterpolator = useModalCardStyleInterpolator();
+ const modalNavigatorOptions = useSideModalStackScreenOptions();
+
const screenOptions = useMemo(() => {
- const options = ModalNavigatorScreenOptions(styles);
// The .forHorizontalIOS interpolator from `@react-navigation` is misbehaving on Safari, so we override it with Expensify custom interpolator
if (isSafari()) {
- const customInterpolator = createModalCardStyleInterpolator(styleUtils);
- options.cardStyleInterpolator = (props: StackCardInterpolationProps) => customInterpolator(shouldUseNarrowLayout, false, false, props);
+ return {
+ ...modalNavigatorOptions,
+ web: {
+ ...modalNavigatorOptions.web,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => customInterpolator({props}),
+ },
+ };
}
- return options;
- }, [shouldUseNarrowLayout, styleUtils, styles]);
+ return modalNavigatorOptions;
+ }, [customInterpolator, modalNavigatorOptions]);
return (
@@ -174,6 +181,7 @@ function RightModalNavigator({navigation, route}: RightModalNavigatorProps) {
();
+const Stack = createPlatformStackNavigator();
function WelcomeVideoModalNavigator() {
return (
-
+
({
- headerShown: false,
- animationEnabled: true,
- gestureDirection: 'horizontal',
- cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
- presentation: 'transparentModal',
-});
-
-export default OnboardingModalNavigatorScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.tsx b/src/libs/Navigation/AppNavigator/PublicScreens.tsx
index cfd41a4b1fa0..dbbb11c978d5 100644
--- a/src/libs/Navigation/AppNavigator/PublicScreens.tsx
+++ b/src/libs/Navigation/AppNavigator/PublicScreens.tsx
@@ -1,6 +1,6 @@
-import {createStackNavigator} from '@react-navigation/stack';
import React from 'react';
import {NativeModules} from 'react-native';
+import createPlatformStackNavigator from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigator';
import type {PublicScreensParamList} from '@navigation/types';
import ConnectionCompletePage from '@pages/ConnectionCompletePage';
import SessionExpiredPage from '@pages/ErrorPage/SessionExpiredPage';
@@ -15,20 +15,18 @@ import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
import defaultScreenOptions from './defaultScreenOptions';
-const RootStack = createStackNavigator();
+const RootStack = createPlatformStackNavigator();
function PublicScreens() {
return (
-
+
{/* The structure for the HOME route has to be the same in public and auth screens. That's why the name for SignInPage is BOTTOM_TAB_NAVIGATOR. */}
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/BottomTabNavigationContentWrapper.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx
similarity index 100%
rename from src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/BottomTabNavigationContentWrapper.tsx
rename to src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabNavigationContentWrapper.tsx
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
index eba7a7448ad0..01caa79692f1 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/TopBar.tsx
@@ -17,9 +17,20 @@ import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
-type TopBarProps = {breadcrumbLabel: string; activeWorkspaceID?: string; shouldDisplaySearch?: boolean; shouldDisplayCancelSearch?: boolean};
+type TopBarProps = {
+ breadcrumbLabel: string;
+ activeWorkspaceID?: string;
+ shouldDisplaySearch?: boolean;
+ shouldDisplayCancelSearch?: boolean;
-function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, shouldDisplayCancelSearch = false}: TopBarProps) {
+ /**
+ * Callback used to keep track of the workspace switching process in the BaseSidebarScreen.
+ * Passed to the WorkspaceSwitcherButton component.
+ */
+ onSwitchWorkspace?: () => void;
+};
+
+function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, shouldDisplayCancelSearch = false, onSwitchWorkspace}: TopBarProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const policy = usePolicy(activeWorkspaceID);
@@ -42,7 +53,10 @@ function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true,
dataSet={{dragArea: true}}
>
-
+
, StackNavigationOptions, StackNavigationEventMap> & {
- initialRouteName: string;
+const defaultScreenOptions: PlatformStackNavigationOptions = {
+ animation: 'none',
};
-function getStateToRender(state: StackNavigationState): StackNavigationState {
- const routesToRender = [state.routes.at(-1)] as NavigationStateRoute[];
-
- // We need to render at least one HOME screen to make sure everything load properly. This may be not necessary after changing how IS_SIDEBAR_LOADED is handled.
- // Currently this value will be switched only after the first HOME screen is rendered.
- if (routesToRender.at(0)?.name !== SCREENS.HOME) {
- const routeToRender = state.routes.find((route) => route.name === SCREENS.HOME);
- if (routeToRender) {
- routesToRender.unshift(routeToRender);
- }
- }
-
- return {...state, routes: routesToRender, index: routesToRender.length - 1};
+function ExtraContent({state}: ExtraContentProps) {
+ const selectedTab = state.routes.at(-1)?.name;
+ return ;
}
-function CustomBottomTabNavigator({initialRouteName, children, screenOptions, ...props}: CustomNavigatorProps) {
- const {state, navigation, descriptors, NavigationContent} = useNavigationBuilder<
- StackNavigationState,
- StackRouterOptions,
- StackActionHelpers,
- StackNavigationOptions,
- StackNavigationEventMap
- >(StackRouter, {
- children,
- screenOptions,
- initialRouteName,
- });
-
- const styles = useThemeStyles();
- const stateToRender = getStateToRender(state);
- const selectedTab = stateToRender.routes.at(-1)?.name;
-
- return (
-
-
-
-
-
-
-
-
- );
+const CustomBottomTabNavigatorComponent = createPlatformStackNavigatorComponent('CustomBottomTabNavigator', {
+ useCustomState,
+ defaultScreenOptions,
+ NavigationContentWrapper: BottomTabNavigationContentWrapper,
+ ExtraContent,
+});
+
+function createCustomBottomTabNavigator() {
+ return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomBottomTabNavigatorComponent>(
+ CustomBottomTabNavigatorComponent,
+ )();
}
-CustomBottomTabNavigator.displayName = 'CustomBottomTabNavigator';
-
-export default createNavigatorFactory(CustomBottomTabNavigator);
+export default createCustomBottomTabNavigator;
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/useCustomState/index.ts b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState/index.ts
similarity index 100%
rename from src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/useCustomState/index.ts
rename to src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/useCustomState/index.ts
diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx
index a5746f6f8e81..3c7b699c60ef 100644
--- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/CustomFullScreenRouter.tsx
@@ -1,13 +1,13 @@
-import type {ParamListBase, PartialState, RouterConfigOptions, StackNavigationState} from '@react-navigation/native';
+import type {ParamListBase, PartialState, Router, RouterConfigOptions} from '@react-navigation/native';
import {StackRouter} from '@react-navigation/native';
import Onyx from 'react-native-onyx';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
+import type {PlatformStackNavigationState, PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types';
import * as PolicyUtils from '@libs/PolicyUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import SCREENS from '@src/SCREENS';
-import type {FullScreenNavigatorRouterOptions} from './types';
-type StackState = StackNavigationState | PartialState>;
+type StackState = PlatformStackNavigationState | PartialState>;
const isAtLeastOneInState = (state: StackState, screenName: string): boolean => state.routes.some((route) => route.name === screenName);
@@ -69,8 +69,9 @@ function adaptStateIfNecessary(state: StackState) {
}
}
-function CustomFullScreenRouter(options: FullScreenNavigatorRouterOptions) {
- const stackRouter = StackRouter(options);
+function CustomFullScreenRouter(options: PlatformStackRouterOptions) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const stackRouter = StackRouter(options) as Router, any>;
return {
...stackRouter,
@@ -85,7 +86,7 @@ function CustomFullScreenRouter(options: FullScreenNavigatorRouterOptions) {
return initialState;
},
- getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState {
+ getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): PlatformStackNavigationState {
adaptStateIfNecessary(partialState);
const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList});
return state;
diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx
deleted file mode 100644
index 2f61f1519df0..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.native.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
-import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-import {StackView} from '@react-navigation/stack';
-import CustomFullScreenRouter from './CustomFullScreenRouter';
-import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types';
-
-function CustomFullScreenNavigator(props: FullScreenNavigatorProps) {
- const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
- StackNavigationState,
- FullScreenNavigatorRouterOptions,
- StackActionHelpers,
- StackNavigationOptions,
- StackNavigationEventMap
- >(CustomFullScreenRouter, {
- children: props.children,
- screenOptions: props.screenOptions,
- initialRouteName: props.initialRouteName,
- });
-
- return (
-
-
-
- );
-}
-
-CustomFullScreenNavigator.displayName = 'CustomFullScreenNavigator';
-
-export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof CustomFullScreenNavigator>(CustomFullScreenNavigator);
diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx
index ee8dd54c920d..f3d605e1824f 100644
--- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/index.tsx
@@ -1,50 +1,21 @@
-import type {ParamListBase, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
-import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-import {StackView} from '@react-navigation/stack';
-import React, {useEffect} from 'react';
-import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import navigationRef from '@libs/Navigation/navigationRef';
+import type {ParamListBase} from '@react-navigation/native';
+import {createNavigatorFactory} from '@react-navigation/native';
+import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange';
+import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent';
+import defaultPlatformStackScreenOptions from '@libs/Navigation/PlatformStackNavigation/defaultPlatformStackScreenOptions';
+import type {PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
import CustomFullScreenRouter from './CustomFullScreenRouter';
-import type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions} from './types';
-function CustomFullScreenNavigator(props: FullScreenNavigatorProps) {
- const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
- StackNavigationState,
- FullScreenNavigatorRouterOptions,
- StackActionHelpers,
- StackNavigationOptions,
- StackNavigationEventMap
- >(CustomFullScreenRouter, {
- children: props.children,
- screenOptions: props.screenOptions,
- initialRouteName: props.initialRouteName,
- });
+const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', {
+ createRouter: CustomFullScreenRouter,
+ useCustomEffects: useNavigationResetOnLayoutChange,
+ defaultScreenOptions: defaultPlatformStackScreenOptions,
+});
- const {shouldUseNarrowLayout} = useResponsiveLayout();
-
- useEffect(() => {
- if (!navigationRef.isReady()) {
- return;
- }
- // We need to separately reset state of this navigator to trigger getRehydratedState.
- navigation.reset(navigation.getState());
- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, [shouldUseNarrowLayout]);
-
- return (
-
-
-
- );
+function createCustomFullScreenNavigator() {
+ return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomFullScreenNavigatorComponent>(
+ CustomFullScreenNavigatorComponent,
+ )();
}
-CustomFullScreenNavigator.displayName = 'CustomFullScreenNavigator';
-
-export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof CustomFullScreenNavigator>(CustomFullScreenNavigator);
+export default createCustomFullScreenNavigator;
diff --git a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts b/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts
deleted file mode 100644
index 7e7808c003d7..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomFullScreenNavigator/types.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-
-type FullScreenNavigatorRouterOptions = StackRouterOptions;
-
-type FullScreenNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap>;
-
-export type {FullScreenNavigatorProps, FullScreenNavigatorRouterOptions};
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/BottomTabBar.tsx b/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/BottomTabBar.tsx
deleted file mode 100644
index 0c5e9bf20741..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/BottomTabBar.tsx
+++ /dev/null
@@ -1,219 +0,0 @@
-import {useNavigation} from '@react-navigation/native';
-import React, {memo, useCallback, useEffect, useState} from 'react';
-import {NativeModules, View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
-import Icon from '@components/Icon';
-import * as Expensicons from '@components/Icon/Expensicons';
-import {PressableWithFeedback} from '@components/Pressable';
-import type {SearchQueryString} from '@components/Search/types';
-import Tooltip from '@components/Tooltip';
-import useActiveWorkspace from '@hooks/useActiveWorkspace';
-import useCurrentReportID from '@hooks/useCurrentReportID';
-import useLocalize from '@hooks/useLocalize';
-import useTheme from '@hooks/useTheme';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as Session from '@libs/actions/Session';
-import interceptAnonymousUser from '@libs/interceptAnonymousUser';
-import DebugTabView from '@libs/Navigation/AppNavigator/createCustomBottomTabNavigator/DebugTabView';
-import Navigation from '@libs/Navigation/Navigation';
-import type {AuthScreensParamList} from '@libs/Navigation/types';
-import {isCentralPaneName} from '@libs/NavigationUtils';
-import * as PolicyUtils from '@libs/PolicyUtils';
-import * as SearchQueryUtils from '@libs/SearchQueryUtils';
-import type {BrickRoad} from '@libs/WorkspacesSettingsUtils';
-import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
-import navigationRef from '@navigation/navigationRef';
-import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar';
-import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton';
-import variables from '@styles/variables';
-import * as Welcome from '@userActions/Welcome';
-import * as OnboardingFlow from '@userActions/Welcome/OnboardingFlow';
-import CONST from '@src/CONST';
-import NAVIGATORS from '@src/NAVIGATORS';
-import ONYXKEYS from '@src/ONYXKEYS';
-import type {Route} from '@src/ROUTES';
-import ROUTES from '@src/ROUTES';
-import SCREENS from '@src/SCREENS';
-
-type BottomTabBarProps = {
- selectedTab: string | undefined;
-};
-
-/**
- * Returns SearchQueryString that has policyID correctly set.
- *
- * When we're coming back to Search Screen we might have pre-existing policyID inside SearchQuery.
- * There are 2 cases when we might want to remove this `policyID`:
- * - if Policy was removed in another screen
- * - if WorkspaceSwitcher was used to globally unset a policyID
- * Otherwise policyID will be inserted into query
- */
-function handleQueryWithPolicyID(query: SearchQueryString, activePolicyID?: string): SearchQueryString {
- const queryJSON = SearchQueryUtils.buildSearchQueryJSON(query);
- if (!queryJSON) {
- return query;
- }
-
- const policyID = activePolicyID ?? queryJSON.policyID;
- const policy = PolicyUtils.getPolicy(policyID);
-
- // In case policy is missing or there is no policy currently selected via WorkspaceSwitcher we remove it
- if (!activePolicyID || !policy) {
- delete queryJSON.policyID;
- } else {
- queryJSON.policyID = policyID;
- }
-
- return SearchQueryUtils.buildSearchQueryString(queryJSON);
-}
-
-function BottomTabBar({selectedTab}: BottomTabBarProps) {
- const theme = useTheme();
- const styles = useThemeStyles();
- const {translate} = useLocalize();
- const navigation = useNavigation();
- const {activeWorkspaceID} = useActiveWorkspace();
- const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
- const {currentReportID} = useCurrentReportID() ?? {currentReportID: null};
- const [user] = useOnyx(ONYXKEYS.USER);
- const [betas] = useOnyx(ONYXKEYS.BETAS);
- const [priorityMode] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE);
- const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
- const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
- const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS);
- const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
- const [chatTabBrickRoad, setChatTabBrickRoad] = useState(
- getChatTabBrickRoad(activeWorkspaceID, currentReportID, reports, betas, policies, priorityMode, transactionViolations),
- );
-
- useEffect(() => {
- setChatTabBrickRoad(getChatTabBrickRoad(activeWorkspaceID, currentReportID, reports, betas, policies, priorityMode, transactionViolations));
- // We need to get a new brick road state when report actions are updated, otherwise we'll be showing an outdated brick road.
- // That's why reportActions is added as a dependency here
- }, [activeWorkspaceID, transactionViolations, reports, reportActions, betas, policies, priorityMode, currentReportID]);
-
- useEffect(() => {
- const navigationState = navigation.getState();
- const routes = navigationState?.routes;
- const currentRoute = routes?.at(navigationState?.index ?? 0);
- // When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method.
- // To prevent this, the value of the bottomTabRoute?.name is checked here
- if (!!(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && !isCentralPaneName(currentRoute.name)) || Session.isAnonymousUser()) {
- return;
- }
-
- // HybridApp has own entry point when we decide whether to display onboarding and explanation modal.
- if (NativeModules.HybridAppModule) {
- return;
- }
-
- Welcome.isOnboardingFlowCompleted({
- onNotCompleted: () => OnboardingFlow.startOnboardingFlow(),
- });
-
- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, [isLoadingApp]);
-
- const navigateToChats = useCallback(() => {
- if (selectedTab === SCREENS.HOME) {
- return;
- }
- const route = activeWorkspaceID ? (`/w/${activeWorkspaceID}/${ROUTES.HOME}` as Route) : ROUTES.HOME;
- Navigation.navigate(route);
- }, [activeWorkspaceID, selectedTab]);
-
- const navigateToSearch = useCallback(() => {
- if (selectedTab === SCREENS.SEARCH.BOTTOM_TAB) {
- return;
- }
- interceptAnonymousUser(() => {
- const rootState = navigationRef.getRootState();
- const lastSearchRoute = rootState.routes.filter((route) => route.name === SCREENS.SEARCH.CENTRAL_PANE).at(-1);
-
- if (lastSearchRoute) {
- const {q, ...rest} = lastSearchRoute.params as AuthScreensParamList[typeof SCREENS.SEARCH.CENTRAL_PANE];
- const cleanedQuery = handleQueryWithPolicyID(q, activeWorkspaceID);
-
- Navigation.navigate(
- ROUTES.SEARCH_CENTRAL_PANE.getRoute({
- query: cleanedQuery,
- ...rest,
- }),
- );
- return;
- }
-
- const defaultCannedQuery = SearchQueryUtils.buildCannedSearchQuery();
- // when navigating to search we might have an activePolicyID set from workspace switcher
- const query = activeWorkspaceID ? `${defaultCannedQuery} ${CONST.SEARCH.SYNTAX_ROOT_KEYS.POLICY_ID}:${activeWorkspaceID}` : defaultCannedQuery;
- Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query}));
- });
- }, [activeWorkspaceID, selectedTab]);
-
- return (
- <>
- {!!user?.isDebugModeEnabled && (
-
- )}
-
-
-
-
-
- {!!chatTabBrickRoad && (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
-BottomTabBar.displayName = 'BottomTabBar';
-
-export default memo(BottomTabBar);
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/TopBar.tsx b/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/TopBar.tsx
deleted file mode 100644
index eba7a7448ad0..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/TopBar.tsx
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react';
-import {View} from 'react-native';
-import {useOnyx} from 'react-native-onyx';
-import Breadcrumbs from '@components/Breadcrumbs';
-import {PressableWithoutFeedback} from '@components/Pressable';
-import SearchButton from '@components/Search/SearchRouter/SearchButton';
-import Text from '@components/Text';
-import WorkspaceSwitcherButton from '@components/WorkspaceSwitcherButton';
-import useLocalize from '@hooks/useLocalize';
-import usePolicy from '@hooks/usePolicy';
-import useThemeStyles from '@hooks/useThemeStyles';
-import Navigation from '@libs/Navigation/Navigation';
-import * as SearchQueryUtils from '@libs/SearchQueryUtils';
-import SignInButton from '@pages/home/sidebar/SignInButton';
-import * as Session from '@userActions/Session';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-import ROUTES from '@src/ROUTES';
-
-type TopBarProps = {breadcrumbLabel: string; activeWorkspaceID?: string; shouldDisplaySearch?: boolean; shouldDisplayCancelSearch?: boolean};
-
-function TopBar({breadcrumbLabel, activeWorkspaceID, shouldDisplaySearch = true, shouldDisplayCancelSearch = false}: TopBarProps) {
- const styles = useThemeStyles();
- const {translate} = useLocalize();
- const policy = usePolicy(activeWorkspaceID);
- const [session] = useOnyx(ONYXKEYS.SESSION, {selector: (sessionValue) => sessionValue && {authTokenType: sessionValue.authTokenType}});
- const isAnonymousUser = Session.isAnonymousUser(session);
-
- const headerBreadcrumb = policy?.name
- ? {type: CONST.BREADCRUMB_TYPE.STRONG, text: policy.name}
- : {
- type: CONST.BREADCRUMB_TYPE.ROOT,
- };
-
- const displaySignIn = isAnonymousUser;
- const displaySearch = !isAnonymousUser && shouldDisplaySearch;
-
- return (
-
-
-
-
-
-
-
-
-
- {displaySignIn && }
- {shouldDisplayCancelSearch && (
- {
- Navigation.goBack(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: SearchQueryUtils.buildCannedSearchQuery()}));
- }}
- >
- {translate('common.cancel')}
-
- )}
- {displaySearch && }
-
-
- );
-}
-
-TopBar.displayName = 'TopBar';
-
-export default TopBar;
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/index.tsx
deleted file mode 100644
index 2461c542ec7d..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomPlatformStackBottomTabNavigator/index.tsx
+++ /dev/null
@@ -1,33 +0,0 @@
-import type {ParamListBase} from '@react-navigation/native';
-import {createNavigatorFactory} from '@react-navigation/native';
-import React from 'react';
-import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent';
-import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
-import type {ExtraContentProps, PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
-import BottomTabBar from './BottomTabBar';
-import BottomTabNavigationContentWrapper from './BottomTabNavigationContentWrapper';
-import useCustomState from './useCustomState';
-
-const defaultScreenOptions: PlatformStackNavigationOptions = {
- animation: Animations.NONE,
-};
-
-function ExtraContent({state}: ExtraContentProps) {
- const selectedTab = state.routes.at(-1)?.name;
- return ;
-}
-
-const CustomBottomTabNavigatorComponent = createPlatformStackNavigatorComponent('CustomBottomTabNavigator', {
- useCustomState,
- defaultScreenOptions,
- NavigationContentWrapper: BottomTabNavigationContentWrapper,
- ExtraContent,
-});
-
-function createCustomBottomTabNavigator() {
- return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomBottomTabNavigatorComponent>(
- CustomBottomTabNavigatorComponent,
- )();
-}
-
-export default createCustomBottomTabNavigator;
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/CustomFullScreenRouter.tsx b/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/CustomFullScreenRouter.tsx
deleted file mode 100644
index 5c837fc93a5b..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/CustomFullScreenRouter.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import type {ParamListBase, PartialState, Router, RouterConfigOptions} from '@react-navigation/native';
-import {StackRouter} from '@react-navigation/native';
-import getIsNarrowLayout from '@libs/getIsNarrowLayout';
-import type {PlatformStackNavigationState, PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-import SCREENS from '@src/SCREENS';
-
-type StackState = PlatformStackNavigationState | PartialState>;
-
-const isAtLeastOneInState = (state: StackState, screenName: string): boolean => state.routes.some((route) => route.name === screenName);
-
-function adaptStateIfNecessary(state: StackState) {
- const isNarrowLayout = getIsNarrowLayout();
- const workspaceCentralPane = state.routes.at(-1);
-
- // There should always be WORKSPACE.INITIAL screen in the state to make sure go back works properly if we deeplinkg to a subpage of settings.
- if (!isAtLeastOneInState(state, SCREENS.WORKSPACE.INITIAL)) {
- // @ts-expect-error Updating read only property
- // noinspection JSConstantReassignment
- state.stale = true; // eslint-disable-line
-
- // This is necessary for ts to narrow type down to PartialState.
- if (state.stale === true) {
- // Unshift the root screen to fill left pane.
- state.routes.unshift({
- name: SCREENS.WORKSPACE.INITIAL,
- params: workspaceCentralPane?.params,
- });
- }
- }
-
- // If the screen is wide, there should be at least two screens inside:
- // - WORKSPACE.INITIAL to cover left pane.
- // - WORKSPACE.PROFILE (first workspace settings screen) to cover central pane.
- if (!isNarrowLayout) {
- if (state.routes.length === 1 && state.routes.at(0)?.name === SCREENS.WORKSPACE.INITIAL) {
- // @ts-expect-error Updating read only property
- // noinspection JSConstantReassignment
- state.stale = true; // eslint-disable-line
- // Push the default settings central pane screen.
- if (state.stale === true) {
- state.routes.push({
- name: SCREENS.WORKSPACE.PROFILE,
- params: state.routes.at(0)?.params,
- });
- }
- }
- // eslint-disable-next-line no-param-reassign, @typescript-eslint/non-nullable-type-assertion-style
- (state.index as number) = state.routes.length - 1;
- }
-}
-
-function CustomFullScreenRouter(options: PlatformStackRouterOptions) {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- const stackRouter = StackRouter(options) as Router, any>;
-
- return {
- ...stackRouter,
- getInitialState({routeNames, routeParamList, routeGetIdList}: RouterConfigOptions) {
- const initialState = stackRouter.getInitialState({routeNames, routeParamList, routeGetIdList});
- adaptStateIfNecessary(initialState);
-
- // If we needed to modify the state we need to rehydrate it to get keys for new routes.
- if (initialState.stale) {
- return stackRouter.getRehydratedState(initialState, {routeNames, routeParamList, routeGetIdList});
- }
-
- return initialState;
- },
- getRehydratedState(partialState: StackState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): PlatformStackNavigationState {
- adaptStateIfNecessary(partialState);
- const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList});
- return state;
- },
- };
-}
-
-export default CustomFullScreenRouter;
diff --git a/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/index.tsx
deleted file mode 100644
index 204a9780e7d5..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomPlatformStackFullScreenNavigator/index.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import type {ParamListBase} from '@react-navigation/native';
-import {createNavigatorFactory} from '@react-navigation/native';
-import useNavigationResetOnLayoutChange from '@libs/Navigation/AppNavigator/useNavigationResetOnLayoutChange';
-import createPlatformStackNavigatorComponent from '@libs/Navigation/PlatformStackNavigation/createPlatformStackNavigatorComponent';
-import type {PlatformStackNavigationEventMap, PlatformStackNavigationOptions, PlatformStackNavigationState} from '@libs/Navigation/PlatformStackNavigation/types';
-import CustomFullScreenRouter from './CustomFullScreenRouter';
-
-const CustomFullScreenNavigatorComponent = createPlatformStackNavigatorComponent('CustomFullScreenNavigator', {
- createRouter: CustomFullScreenRouter,
- useCustomEffects: useNavigationResetOnLayoutChange,
-});
-
-function createCustomFullScreenNavigator() {
- return createNavigatorFactory, PlatformStackNavigationOptions, PlatformStackNavigationEventMap, typeof CustomFullScreenNavigatorComponent>(
- CustomFullScreenNavigatorComponent,
- )();
-}
-
-export default createCustomFullScreenNavigator;
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts
deleted file mode 100644
index 8156425fa904..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-import type {CommonActions, RouterConfigOptions, StackActionType, StackNavigationState} from '@react-navigation/native';
-import {findFocusedRoute, getPathFromState, StackRouter} from '@react-navigation/native';
-import type {ParamListBase} from '@react-navigation/routers';
-import getIsNarrowLayout from '@libs/getIsNarrowLayout';
-import * as Localize from '@libs/Localize';
-import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
-import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
-import linkingConfig from '@libs/Navigation/linkingConfig';
-import getAdaptedStateFromPath from '@libs/Navigation/linkingConfig/getAdaptedStateFromPath';
-import type {NavigationPartialRoute, RootStackParamList, State} from '@libs/Navigation/types';
-import {isCentralPaneName, isOnboardingFlowName} from '@libs/NavigationUtils';
-import * as Welcome from '@userActions/Welcome';
-import CONST from '@src/CONST';
-import NAVIGATORS from '@src/NAVIGATORS';
-import SCREENS from '@src/SCREENS';
-import syncBrowserHistory from './syncBrowserHistory';
-import type {ResponsiveStackNavigatorRouterOptions} from './types';
-
-function insertRootRoute(state: State, routeToInsert: NavigationPartialRoute) {
- const nonModalRoutes = state.routes.filter(
- (route) => route.name !== NAVIGATORS.RIGHT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.LEFT_MODAL_NAVIGATOR && route.name !== NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR,
- );
- const modalRoutes = state.routes.filter(
- (route) => route.name === NAVIGATORS.RIGHT_MODAL_NAVIGATOR || route.name === NAVIGATORS.LEFT_MODAL_NAVIGATOR || route.name === NAVIGATORS.ONBOARDING_MODAL_NAVIGATOR,
- );
-
- // It's safe to modify this state before returning in getRehydratedState.
-
- // @ts-expect-error Updating read only property
- // noinspection JSConstantReassignment
- state.routes = [...nonModalRoutes, routeToInsert, ...modalRoutes]; // eslint-disable-line
-
- // @ts-expect-error Updating read only property
- // noinspection JSConstantReassignment
- state.index = state.routes.length - 1; // eslint-disable-line
-
- // @ts-expect-error Updating read only property
- // noinspection JSConstantReassignment
- state.stale = true; // eslint-disable-line
-}
-
-function compareAndAdaptState(state: StackNavigationState) {
- // If the state of the last path is not defined the getPathFromState won't work correctly.
- if (!state?.routes.at(-1)?.state) {
- return;
- }
-
- // We need to be sure that the bottom tab state is defined.
- const topmostBottomTabRoute = getTopmostBottomTabRoute(state);
- const isNarrowLayout = getIsNarrowLayout();
-
- // This solutions is heuristics and will work for our cases. We may need to improve it in the future if we will have more cases to handle.
- if (topmostBottomTabRoute && !isNarrowLayout) {
- const fullScreenRoute = state.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR);
-
- // If there is fullScreenRoute we don't need to add anything.
- if (fullScreenRoute) {
- return;
- }
-
- // We will generate a template state and compare the current state with it.
- // If there is a difference in the screens that should be visible under the overlay, we will add the screen from templateState to the current state.
- const pathFromCurrentState = getPathFromState(state, linkingConfig.config);
- const {adaptedState: templateState} = getAdaptedStateFromPath(pathFromCurrentState, linkingConfig.config);
-
- if (!templateState) {
- return;
- }
-
- const templateFullScreenRoute = templateState.routes.find((route) => route.name === NAVIGATORS.FULL_SCREEN_NAVIGATOR);
-
- // If templateFullScreenRoute is defined, and full screen route is not in the state, we need to add it.
- if (templateFullScreenRoute) {
- insertRootRoute(state, templateFullScreenRoute);
- return;
- }
-
- const topmostCentralPaneRoute = state.routes.filter((route) => isCentralPaneName(route.name)).at(-1);
- const templateCentralPaneRoute = templateState.routes.find((route) => isCentralPaneName(route.name));
-
- const topmostCentralPaneRouteExtracted = getTopmostCentralPaneRoute(state);
- const templateCentralPaneRouteExtracted = getTopmostCentralPaneRoute(templateState as State);
-
- // If there is no templateCentralPaneRoute, we don't have anything to add.
- if (!templateCentralPaneRoute) {
- return;
- }
-
- // If there is no topmostCentralPaneRoute in the state and template state has one, we need to add it.
- if (!topmostCentralPaneRoute) {
- insertRootRoute(state, templateCentralPaneRoute);
- return;
- }
-
- // If there is central pane route in state and template state has one, we need to check if they are the same.
- if (topmostCentralPaneRouteExtracted && templateCentralPaneRouteExtracted && topmostCentralPaneRouteExtracted.name !== templateCentralPaneRouteExtracted.name) {
- // Not every RHP screen has matching central pane defined. In that case we use the REPORT screen as default for initial screen.
- // But we don't want to override the central pane for those screens as they may be opened with different central panes under the overlay.
- // e.g. i-know-a-teacher may be opened with different central panes under the overlay
- if (templateCentralPaneRouteExtracted.name === SCREENS.REPORT) {
- return;
- }
- insertRootRoute(state, templateCentralPaneRoute);
- }
- }
-}
-
-function shouldPreventReset(state: StackNavigationState, action: CommonActions.Action | StackActionType) {
- if (action.type !== CONST.NAVIGATION_ACTIONS.RESET || !action?.payload) {
- return false;
- }
- const currentFocusedRoute = findFocusedRoute(state);
- const targetFocusedRoute = findFocusedRoute(action?.payload);
-
- // We want to prevent the user from navigating back to a non-onboarding screen if they are currently on an onboarding screen
- if (isOnboardingFlowName(currentFocusedRoute?.name) && !isOnboardingFlowName(targetFocusedRoute?.name)) {
- Welcome.setOnboardingErrorMessage(Localize.translateLocal('onboarding.purpose.errorBackButton'));
- return true;
- }
-
- return false;
-}
-
-function CustomRouter(options: ResponsiveStackNavigatorRouterOptions) {
- const stackRouter = StackRouter(options);
-
- return {
- ...stackRouter,
- getRehydratedState(partialState: StackNavigationState, {routeNames, routeParamList, routeGetIdList}: RouterConfigOptions): StackNavigationState {
- compareAndAdaptState(partialState);
- const state = stackRouter.getRehydratedState(partialState, {routeNames, routeParamList, routeGetIdList});
- return state;
- },
- getStateForAction(state: StackNavigationState, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) {
- if (shouldPreventReset(state, action)) {
- syncBrowserHistory(state);
- return state;
- }
- return stackRouter.getStateForAction(state, action, configOptions);
- },
- };
-}
-
-export default CustomRouter;
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
deleted file mode 100644
index b6ecba936911..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.tsx
+++ /dev/null
@@ -1,122 +0,0 @@
-import type {ParamListBase, RouteProp, StackActionHelpers, StackNavigationState} from '@react-navigation/native';
-import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-import {StackView} from '@react-navigation/stack';
-import React, {useEffect, useMemo} from 'react';
-import {View} from 'react-native';
-import useResponsiveLayout from '@hooks/useResponsiveLayout';
-import useThemeStyles from '@hooks/useThemeStyles';
-import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
-import navigationRef from '@libs/Navigation/navigationRef';
-import type {RootStackParamList, State} from '@libs/Navigation/types';
-import {isCentralPaneName} from '@libs/NavigationUtils';
-import SCREENS from '@src/SCREENS';
-import CustomRouter from './CustomRouter';
-import type {ResponsiveStackNavigatorProps, ResponsiveStackNavigatorRouterOptions} from './types';
-
-type Routes = StackNavigationState['routes'];
-function reduceCentralPaneRoutes(routes: Routes): Routes {
- const result: Routes = [];
- let count = 0;
- const reverseRoutes = [...routes].reverse();
-
- reverseRoutes.forEach((route) => {
- if (isCentralPaneName(route.name)) {
- // Remove all central pane routes except the last 3. This will improve performance.
- if (count < 3) {
- result.push(route);
- count++;
- }
- } else {
- result.push(route);
- }
- });
-
- return result.reverse();
-}
-
-function ResponsiveStackNavigator(props: ResponsiveStackNavigatorProps) {
- const {shouldUseNarrowLayout} = useResponsiveLayout();
- const styles = useThemeStyles();
-
- const {navigation, state, descriptors, NavigationContent} = useNavigationBuilder<
- StackNavigationState,
- ResponsiveStackNavigatorRouterOptions,
- StackActionHelpers,
- StackNavigationOptions,
- StackNavigationEventMap
- >(CustomRouter, {
- children: props.children,
- screenOptions: props.screenOptions,
- initialRouteName: props.initialRouteName,
- });
-
- useEffect(() => {
- if (!navigationRef.isReady()) {
- return;
- }
- navigationRef.resetRoot(navigationRef.getRootState());
- }, [shouldUseNarrowLayout]);
-
- const {stateToRender, searchRoute} = useMemo(() => {
- const routes = reduceCentralPaneRoutes(state.routes);
-
- if (shouldUseNarrowLayout) {
- const isSearchCentralPane = (route: RouteProp) => getTopmostCentralPaneRoute({routes: [route]} as State)?.name === SCREENS.SEARCH.CENTRAL_PANE;
-
- const lastRoute = routes.at(-1);
- const lastSearchCentralPane = lastRoute && isSearchCentralPane(lastRoute) ? lastRoute : undefined;
- const filteredRoutes = routes.filter((route) => !isSearchCentralPane(route));
-
- // On narrow layout, if we are on /search route we want to hide all central pane routes and show only the bottom tab navigator.
- if (lastSearchCentralPane) {
- const filteredRoute = filteredRoutes.at(0);
- if (filteredRoute) {
- return {
- stateToRender: {
- ...state,
- index: 0,
- routes: [filteredRoute],
- },
- searchRoute: lastSearchCentralPane,
- };
- }
- }
-
- return {
- stateToRender: {
- ...state,
- index: filteredRoutes.length - 1,
- routes: filteredRoutes,
- },
- searchRoute: undefined,
- };
- }
-
- return {
- stateToRender: {
- ...state,
- index: routes.length - 1,
- routes: [...routes],
- },
- searchRoute: undefined,
- };
- }, [state, shouldUseNarrowLayout]);
-
- return (
-
-
- {!!searchRoute && {descriptors[searchRoute.key].render()}}
-
- );
-}
-
-ResponsiveStackNavigator.displayName = 'ResponsiveStackNavigator';
-
-export default createNavigatorFactory, StackNavigationOptions, StackNavigationEventMap, typeof ResponsiveStackNavigator>(ResponsiveStackNavigator);
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts
deleted file mode 100644
index 09d35e2a1680..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/types.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import type {DefaultNavigatorOptions, ParamListBase, StackNavigationState, StackRouterOptions} from '@react-navigation/native';
-import type {StackNavigationEventMap, StackNavigationOptions} from '@react-navigation/stack';
-
-type ResponsiveStackNavigatorConfig = {
- isSmallScreenWidth: boolean;
-};
-
-type ResponsiveStackNavigatorRouterOptions = StackRouterOptions;
-
-type ResponsiveStackNavigatorProps = DefaultNavigatorOptions, StackNavigationOptions, StackNavigationEventMap> &
- ResponsiveStackNavigatorConfig;
-
-export type {ResponsiveStackNavigatorRouterOptions, ResponsiveStackNavigatorProps, ResponsiveStackNavigatorConfig};
diff --git a/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts b/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts
deleted file mode 100644
index 21911ebb56e2..000000000000
--- a/src/libs/Navigation/AppNavigator/createModalCardStyleInterpolator.ts
+++ /dev/null
@@ -1,49 +0,0 @@
-import type {StackCardInterpolatedStyle, StackCardInterpolationProps} from '@react-navigation/stack';
-import {Animated} from 'react-native';
-import type {StyleUtilsType} from '@styles/utils';
-import variables from '@styles/variables';
-
-type ModalCardStyleInterpolator = (
- isSmallScreenWidth: boolean,
- isFullScreenModal: boolean,
- shouldUseNarrowLayout: boolean,
- stackCardInterpolationProps: StackCardInterpolationProps,
- outputRangeMultiplier?: number,
-) => StackCardInterpolatedStyle;
-type CreateModalCardStyleInterpolator = (StyleUtils: StyleUtilsType) => ModalCardStyleInterpolator;
-
-const createModalCardStyleInterpolator: CreateModalCardStyleInterpolator =
- (StyleUtils) =>
- (isSmallScreenWidth, isFullScreenModal, shouldUseNarrowLayout, {current: {progress}, inverted, layouts: {screen}}, outputRangeMultiplier = 1) => {
- if (shouldUseNarrowLayout) {
- return {
- cardStyle: {
- opacity: progress,
- },
- };
- }
-
- const translateX = Animated.multiply(
- progress.interpolate({
- inputRange: [0, 1],
- outputRange: [outputRangeMultiplier * (isSmallScreenWidth ? screen.width : variables.sideBarWidth), 0],
- extrapolate: 'clamp',
- }),
- inverted,
- );
-
- const cardStyle = StyleUtils.getCardStyles(screen.width);
-
- if (!isFullScreenModal || isSmallScreenWidth) {
- cardStyle.transform = [{translateX}];
- }
-
- return {
- containerStyle: {
- overflow: 'hidden',
- },
- cardStyle,
- };
- };
-
-export default createModalCardStyleInterpolator;
diff --git a/src/libs/Navigation/AppNavigator/defaultScreenOptions.ts b/src/libs/Navigation/AppNavigator/defaultScreenOptions.ts
index 4015c43c679e..8d941799a81a 100644
--- a/src/libs/Navigation/AppNavigator/defaultScreenOptions.ts
+++ b/src/libs/Navigation/AppNavigator/defaultScreenOptions.ts
@@ -1,12 +1,14 @@
-import type {StackNavigationOptions} from '@react-navigation/stack';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-const defaultScreenOptions: StackNavigationOptions = {
- cardStyle: {
- overflow: 'visible',
- flex: 1,
- },
+const defaultScreenOptions: PlatformStackNavigationOptions = {
headerShown: false,
animationTypeForReplace: 'push',
+ web: {
+ cardStyle: {
+ overflow: 'visible',
+ flex: 1,
+ },
+ },
};
export default defaultScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.android.ts b/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.android.ts
deleted file mode 100644
index ad498a36302e..000000000000
--- a/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.android.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-// a temporary workaround for the modals opening below the current screen on Android
-function getModalPresentationStyle(): 'modal' {
- return 'modal';
-}
-
-export default getModalPresentationStyle;
diff --git a/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.ts b/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.ts
deleted file mode 100644
index 830bf1e5b857..000000000000
--- a/src/libs/Navigation/AppNavigator/getModalPresentationStyle/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-function getModalPresentationStyle(): 'transparentModal' {
- return 'transparentModal';
-}
-
-export default getModalPresentationStyle;
diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
deleted file mode 100644
index e09f85936385..000000000000
--- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.ts
+++ /dev/null
@@ -1,141 +0,0 @@
-import type {StackCardInterpolationProps, StackNavigationOptions} from '@react-navigation/stack';
-import type {ThemeStyles} from '@styles/index';
-import type {StyleUtilsType} from '@styles/utils';
-import variables from '@styles/variables';
-import CONFIG from '@src/CONFIG';
-import createModalCardStyleInterpolator from './createModalCardStyleInterpolator';
-import getModalPresentationStyle from './getModalPresentationStyle';
-
-type GetOnboardingModalNavigatorOptions = (shouldUseNarrowLayout: boolean) => StackNavigationOptions;
-
-type ScreenOptions = {
- rightModalNavigator: StackNavigationOptions;
- onboardingModalNavigator: GetOnboardingModalNavigatorOptions;
- leftModalNavigator: StackNavigationOptions;
- homeScreen: StackNavigationOptions;
- fullScreen: StackNavigationOptions;
- centralPaneNavigator: StackNavigationOptions;
- bottomTab: StackNavigationOptions;
-};
-
-const commonScreenOptions: StackNavigationOptions = {
- headerShown: false,
- gestureDirection: 'horizontal',
- animationEnabled: true,
- cardOverlayEnabled: true,
- animationTypeForReplace: 'push',
-};
-
-type GetRootNavigatorScreenOptions = (isSmallScreenWidth: boolean, styles: ThemeStyles, StyleUtils: StyleUtilsType) => ScreenOptions;
-
-const getRootNavigatorScreenOptions: GetRootNavigatorScreenOptions = (isSmallScreenWidth, themeStyles, StyleUtils) => {
- const modalCardStyleInterpolator = createModalCardStyleInterpolator(StyleUtils);
-
- return {
- rightModalNavigator: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, false, props),
- presentation: getModalPresentationStyle(),
-
- // We want pop in RHP since there are some flows that would work weird otherwise
- animationTypeForReplace: 'pop',
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
-
- // This is necessary to cover translated sidebar with overlay.
- width: isSmallScreenWidth ? '100%' : '200%',
- // Excess space should be on the left so we need to position from right.
- right: 0,
- },
- },
- onboardingModalNavigator: (shouldUseNarrowLayout: boolean) => ({
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, shouldUseNarrowLayout, props),
- headerShown: false,
- animationEnabled: true,
- cardOverlayEnabled: false,
- presentation: 'transparentModal',
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
- backgroundColor: 'transparent',
- width: '100%',
- top: 0,
- left: 0,
- position: 'fixed',
- },
- }),
- leftModalNavigator: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props) => modalCardStyleInterpolator(isSmallScreenWidth, false, false, props),
- presentation: getModalPresentationStyle(),
- gestureDirection: 'horizontal-inverted',
-
- // We want pop in LHP since there are some flows that would work weird otherwise
- animationTypeForReplace: 'pop',
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
-
- // This is necessary to cover translated sidebar with overlay.
- width: isSmallScreenWidth ? '100%' : '200%',
-
- // LHP should be displayed in place of the sidebar
- left: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
- },
- },
- homeScreen: {
- title: CONFIG.SITE_TITLE,
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, false, props),
-
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
- width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
-
- // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
- marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
- ...(isSmallScreenWidth ? {} : themeStyles.borderRight),
- },
- },
-
- fullScreen: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, false, props),
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
-
- // This is necessary to cover whole screen. Including translated sidebar.
- marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
- },
-
- // We need to turn off animation for the full screen to avoid delay when closing screens.
- animationEnabled: isSmallScreenWidth,
- },
-
- centralPaneNavigator: {
- title: CONFIG.SITE_TITLE,
- ...commonScreenOptions,
- animationEnabled: isSmallScreenWidth,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, true, false, props),
-
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
- paddingRight: isSmallScreenWidth ? 0 : variables.sideBarWidth,
- },
- },
-
- bottomTab: {
- ...commonScreenOptions,
- cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator(isSmallScreenWidth, false, false, props),
-
- cardStyle: {
- ...StyleUtils.getNavigationModalCardStyle(),
- width: isSmallScreenWidth ? '100%' : variables.sideBarWidth,
-
- // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
- marginLeft: isSmallScreenWidth ? 0 : -variables.sideBarWidth,
- ...(isSmallScreenWidth ? {} : themeStyles.borderRight),
- },
- },
- };
-};
-
-export default getRootNavigatorScreenOptions;
diff --git a/src/libs/Navigation/AppNavigator/useModalCardStyleInterpolator.ts b/src/libs/Navigation/AppNavigator/useModalCardStyleInterpolator.ts
new file mode 100644
index 000000000000..f4f6179782cc
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/useModalCardStyleInterpolator.ts
@@ -0,0 +1,66 @@
+import type {StackCardInterpolatedStyle, StackCardInterpolationProps} from '@react-navigation/stack';
+import {Animated} from 'react-native';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useStyleUtils from '@hooks/useStyleUtils';
+import variables from '@styles/variables';
+
+type ModalCardStyleInterpolatorProps = {
+ isOnboardingModal?: boolean;
+ isFullScreenModal?: boolean;
+ shouldFadeScreen?: boolean;
+ props: StackCardInterpolationProps;
+ outputRangeMultiplier?: number;
+};
+
+type ModalCardStyleInterpolator = (props: ModalCardStyleInterpolatorProps) => StackCardInterpolatedStyle;
+
+const useModalCardStyleInterpolator = (): ModalCardStyleInterpolator => {
+ const {shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth} = useResponsiveLayout();
+ const StyleUtils = useStyleUtils();
+
+ const modalCardStyleInterpolator: ModalCardStyleInterpolator = ({
+ props: {
+ current: {progress},
+ inverted,
+ layouts: {screen},
+ },
+ isOnboardingModal = false,
+ isFullScreenModal = false,
+ shouldFadeScreen = false,
+ outputRangeMultiplier = 1,
+ }) => {
+ if (isOnboardingModal ? onboardingIsMediumOrLargerScreenWidth : shouldFadeScreen) {
+ return {
+ cardStyle: {
+ opacity: progress,
+ },
+ };
+ }
+
+ const translateX = Animated.multiply(
+ progress.interpolate({
+ inputRange: [0, 1],
+ outputRange: [outputRangeMultiplier * (shouldUseNarrowLayout ? screen.width : variables.sideBarWidth), 0],
+ extrapolate: 'clamp',
+ }),
+ inverted,
+ );
+
+ const cardStyle = StyleUtils.getCardStyles(screen.width);
+
+ if (!isFullScreenModal || shouldUseNarrowLayout) {
+ cardStyle.transform = [{translateX}];
+ }
+
+ return {
+ containerStyle: {
+ overflow: 'hidden',
+ },
+ cardStyle,
+ };
+ };
+
+ return modalCardStyleInterpolator;
+};
+
+export default useModalCardStyleInterpolator;
diff --git a/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts
new file mode 100644
index 000000000000..de7971213526
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/useRootNavigatorOptions.ts
@@ -0,0 +1,156 @@
+import type {StackCardInterpolationProps} from '@react-navigation/stack';
+import useResponsiveLayout from '@hooks/useResponsiveLayout';
+import useStyleUtils from '@hooks/useStyleUtils';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
+import Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import variables from '@styles/variables';
+import CONFIG from '@src/CONFIG';
+import hideKeyboardOnSwipe from './hideKeyboardOnSwipe';
+import useModalCardStyleInterpolator from './useModalCardStyleInterpolator';
+
+type RootNavigatorOptions = {
+ rightModalNavigator: PlatformStackNavigationOptions;
+ onboardingModalNavigator: PlatformStackNavigationOptions;
+ leftModalNavigator: PlatformStackNavigationOptions;
+ homeScreen: PlatformStackNavigationOptions;
+ fullScreen: PlatformStackNavigationOptions;
+ centralPaneNavigator: PlatformStackNavigationOptions;
+ bottomTab: PlatformStackNavigationOptions;
+};
+
+const commonScreenOptions: PlatformStackNavigationOptions = {
+ web: {
+ cardOverlayEnabled: true,
+ },
+};
+
+const useRootNavigatorOptions = () => {
+ const themeStyles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
+ const {shouldUseNarrowLayout} = useResponsiveLayout();
+ const modalCardStyleInterpolator = useModalCardStyleInterpolator();
+
+ return {
+ rightModalNavigator: {
+ ...commonScreenOptions,
+ ...hideKeyboardOnSwipe,
+ animation: Animations.SLIDE_FROM_RIGHT,
+ // We want pop in RHP since there are some flows that would work weird otherwise
+ animationTypeForReplace: 'pop',
+ web: {
+ presentation: Presentation.TRANSPARENT_MODAL,
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ // This is necessary to cover translated sidebar with overlay.
+ width: shouldUseNarrowLayout ? '100%' : '200%',
+ // Excess space should be on the left so we need to position from right.
+ right: 0,
+ },
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props}),
+ },
+ },
+ onboardingModalNavigator: {
+ web: {
+ presentation: Presentation.TRANSPARENT_MODAL,
+ cardOverlayEnabled: false,
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ backgroundColor: 'transparent',
+ width: '100%',
+ top: 0,
+ left: 0,
+ position: 'fixed',
+ },
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isOnboardingModal: true}),
+ },
+ },
+ leftModalNavigator: {
+ ...commonScreenOptions,
+ animation: Animations.SLIDE_FROM_LEFT,
+ animationTypeForReplace: 'pop',
+ native: {
+ customAnimationOnGesture: true,
+ },
+ web: {
+ presentation: Presentation.TRANSPARENT_MODAL,
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props}),
+ // We want pop in LHP since there are some flows that would work weird otherwise
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+
+ // This is necessary to cover translated sidebar with overlay.
+ width: shouldUseNarrowLayout ? '100%' : '200%',
+
+ // LHP should be displayed in place of the sidebar
+ left: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth,
+ },
+ },
+ },
+ homeScreen: {
+ ...commonScreenOptions,
+ title: CONFIG.SITE_TITLE,
+ headerShown: false,
+ web: {
+ // Note: The card* properties won't be applied on mobile platforms, as they use the native defaults.
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props}),
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ width: shouldUseNarrowLayout ? '100%' : variables.sideBarWidth,
+
+ // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
+ marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth,
+ ...(shouldUseNarrowLayout ? {} : themeStyles.borderRight),
+ },
+ },
+ },
+
+ fullScreen: {
+ ...commonScreenOptions,
+ // We need to turn off animation for the full screen to avoid delay when closing screens.
+ animation: shouldUseNarrowLayout ? Animations.SLIDE_FROM_RIGHT : Animations.NONE,
+ web: {
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}),
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+
+ // This is necessary to cover whole screen. Including translated sidebar.
+ marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth,
+ },
+ },
+ },
+
+ centralPaneNavigator: {
+ ...commonScreenOptions,
+ ...hideKeyboardOnSwipe,
+ headerShown: false,
+ title: CONFIG.SITE_TITLE,
+ animation: shouldUseNarrowLayout ? undefined : Animations.NONE,
+ web: {
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props, isFullScreenModal: true}),
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ paddingRight: shouldUseNarrowLayout ? 0 : variables.sideBarWidth,
+ },
+ },
+ },
+
+ bottomTab: {
+ ...commonScreenOptions,
+ web: {
+ cardStyleInterpolator: (props: StackCardInterpolationProps) => modalCardStyleInterpolator({props}),
+ cardStyle: {
+ ...StyleUtils.getNavigationModalCardStyle(),
+ width: shouldUseNarrowLayout ? '100%' : variables.sideBarWidth,
+
+ // We need to shift the sidebar to not be covered by the StackNavigator so it can be clickable.
+ marginLeft: shouldUseNarrowLayout ? 0 : -variables.sideBarWidth,
+ ...(shouldUseNarrowLayout ? {} : themeStyles.borderRight),
+ },
+ },
+ },
+ } satisfies RootNavigatorOptions;
+};
+
+export default useRootNavigatorOptions;
diff --git a/src/libs/Navigation/AppNavigator/useSideModalStackScreenOptions.ts b/src/libs/Navigation/AppNavigator/useSideModalStackScreenOptions.ts
new file mode 100644
index 000000000000..6b6fb46e4122
--- /dev/null
+++ b/src/libs/Navigation/AppNavigator/useSideModalStackScreenOptions.ts
@@ -0,0 +1,35 @@
+import {CardStyleInterpolators} from '@react-navigation/stack';
+import type {GestureDirection} from '@react-navigation/stack/lib/typescript/src/types';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
+import type {PlatformStackNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+
+/**
+ * Side modal stack screen options generator function
+ * @param gestureDirection - The gesture direction of dismissing the modal
+ * @returns The screen options object
+ */
+const useSideModalStackScreenOptions = (gestureDirection: GestureDirection = 'horizontal'): PlatformStackNavigationOptions => {
+ const styles = useThemeStyles();
+
+ let universalGestureDirection: PlatformStackNavigationOptions['gestureDirection'] | undefined;
+ let webGestureDirection: GestureDirection | undefined;
+ if (gestureDirection === 'horizontal' || gestureDirection === 'vertical') {
+ universalGestureDirection = gestureDirection;
+ } else {
+ webGestureDirection = gestureDirection;
+ }
+
+ return {
+ headerShown: false,
+ animation: Animations.SLIDE_FROM_RIGHT,
+ gestureDirection: universalGestureDirection,
+ web: {
+ cardStyle: styles.navigationScreenCardStyle,
+ cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
+ ...(webGestureDirection && {gestureDirection: webGestureDirection}),
+ },
+ };
+};
+
+export default useSideModalStackScreenOptions;
diff --git a/src/libs/Navigation/NavigationRoot.tsx b/src/libs/Navigation/NavigationRoot.tsx
index c23c3783b3bf..cff9fd49fb7a 100644
--- a/src/libs/Navigation/NavigationRoot.tsx
+++ b/src/libs/Navigation/NavigationRoot.tsx
@@ -1,5 +1,5 @@
import type {NavigationState} from '@react-navigation/native';
-import {DefaultTheme, findFocusedRoute, NavigationContainer} from '@react-navigation/native';
+import {DarkTheme, DefaultTheme, findFocusedRoute, NavigationContainer} from '@react-navigation/native';
import React, {useContext, useEffect, useMemo, useRef} from 'react';
import {NativeModules} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -8,6 +8,7 @@ import useActiveWorkspace from '@hooks/useActiveWorkspace';
import useCurrentReportID from '@hooks/useCurrentReportID';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
+import useThemePreference from '@hooks/useThemePreference';
import Firebase from '@libs/Firebase';
import {FSPage} from '@libs/Fullstory';
import Log from '@libs/Log';
@@ -83,6 +84,7 @@ function parseAndLogRoute(state: NavigationState) {
function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, shouldShowRequire2FAModal}: NavigationRootProps) {
const firstRenderRef = useRef(true);
+ const themePreference = useThemePreference();
const theme = useTheme();
const {cleanStaleScrollOffsets} = useContext(ScrollOffsetContext);
@@ -130,16 +132,17 @@ function NavigationRoot({authenticated, lastVisitedPath, initialUrl, onReady, sh
}, []);
// https://reactnavigation.org/docs/themes
- const navigationTheme = useMemo(
- () => ({
- ...DefaultTheme,
+ const navigationTheme = useMemo(() => {
+ const defaultNavigationTheme = themePreference === CONST.THEME.DARK ? DarkTheme : DefaultTheme;
+
+ return {
+ ...defaultNavigationTheme,
colors: {
- ...DefaultTheme.colors,
+ ...defaultNavigationTheme.colors,
background: theme.appBG,
},
- }),
- [theme],
- );
+ };
+ }, [theme.appBG, themePreference]);
useEffect(() => {
if (firstRenderRef.current) {
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/index.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/index.ts
index 7368a4d1de79..17796333cdda 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/index.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/index.ts
@@ -1,11 +1,18 @@
-const TRANSITION_ANIMATIONS = {
+const InternalPlatformAnimations = {
SLIDE_FROM_LEFT: 'slide_from_left',
SLIDE_FROM_RIGHT: 'slide_from_right',
SLIDE_FROM_BOTTOM: 'slide_from_bottom',
IOS_FROM_LEFT: 'ios_from_left',
IOS_FROM_RIGHT: 'ios_from_right',
SIMPLE_PUSH: 'simple_push',
+} as const;
+
+const Animations = {
+ SLIDE_FROM_LEFT: 'slide_from_left',
+ SLIDE_FROM_RIGHT: 'slide_from_right',
+ MODAL: 'modal',
NONE: 'none',
} as const;
-export default TRANSITION_ANIMATIONS;
+export default Animations;
+export {InternalPlatformAnimations};
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.native.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.native.ts
index c38bca7b520b..c5e236e9c27d 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.native.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.native.ts
@@ -1,7 +1,7 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
-import Animations from '..';
-import type SlideFromBottomTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import {InternalPlatformAnimations} from '..';
-const slideFromBottom: SlideFromBottomTransitionNavigationOptions = {animation: Animations.SLIDE_FROM_BOTTOM} satisfies NativeStackNavigationOptions;
+const slideFromBottom: PlatformSpecificNavigationOptions = {animation: InternalPlatformAnimations.SLIDE_FROM_BOTTOM} satisfies NativeStackNavigationOptions;
export default slideFromBottom;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.ts
index ab0ea51081a1..4862c60629a5 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/index.ts
@@ -1,7 +1,7 @@
import type {StackNavigationOptions} from '@react-navigation/stack';
import GestureDirection from '@libs/Navigation/PlatformStackNavigation/navigationOptions/gestureDirection';
-import type SlideFromBottomTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-const slideFromBottom: SlideFromBottomTransitionNavigationOptions = {animationEnabled: true, gestureDirection: GestureDirection.VERTICAL} satisfies StackNavigationOptions;
+const slideFromBottom: PlatformSpecificNavigationOptions = {animationEnabled: true, gestureDirection: GestureDirection.VERTICAL} satisfies StackNavigationOptions;
export default slideFromBottom;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/types.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/types.ts
deleted file mode 100644
index 7e76f03db881..000000000000
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromBottom/types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-
-type SlideFromBottomTransitionNavigationOptions = PlatformSpecificNavigationOptions;
-
-export default SlideFromBottomTransitionNavigationOptions;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.android.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.android.ts
index bc00eabd828a..5350cbf967ab 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.android.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.android.ts
@@ -1,8 +1,8 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
-import Animations from '..';
-import type SlideFromLeftTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import {InternalPlatformAnimations} from '..';
// `slide_from_right` is resolved to `default` transition on iOS, but this transition causes issues on iOS
-const slideFromLeft: SlideFromLeftTransitionNavigationOptions = {animation: Animations.IOS_FROM_LEFT} satisfies NativeStackNavigationOptions;
+const slideFromLeft: PlatformSpecificNavigationOptions = {animation: InternalPlatformAnimations.IOS_FROM_LEFT} satisfies NativeStackNavigationOptions;
export default slideFromLeft;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ios.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ios.ts
index 3969719ca6b1..261cd5f451af 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ios.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ios.ts
@@ -1,9 +1,9 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
-import Animations from '..';
-import type SlideFromLeftTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import {InternalPlatformAnimations} from '..';
// default transition is causing weird keyboard appearance: - https://github.com/Expensify/App/issues/37257
// so we are using `slide_from_left` which is similar to default and not causing keyboard transition issues
-const slideFromLeft: SlideFromLeftTransitionNavigationOptions = {animation: Animations.SLIDE_FROM_LEFT} satisfies NativeStackNavigationOptions;
+const slideFromLeft: PlatformSpecificNavigationOptions = {animation: InternalPlatformAnimations.SLIDE_FROM_LEFT} satisfies NativeStackNavigationOptions;
export default slideFromLeft;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ts
index 05faefd0be0a..0d87ce5864a8 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/index.ts
@@ -1,7 +1,7 @@
import type {StackNavigationOptions} from '@react-navigation/stack';
import GestureDirection from '@libs/Navigation/PlatformStackNavigation/navigationOptions/gestureDirection';
-import type SlideFromLeftTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-const slideFromLeft: SlideFromLeftTransitionNavigationOptions = {animationEnabled: true, gestureDirection: GestureDirection.HORIZONTAL_INVERTED} satisfies StackNavigationOptions;
+const slideFromLeft: PlatformSpecificNavigationOptions = {animationEnabled: true, gestureDirection: GestureDirection.HORIZONTAL_INVERTED} satisfies StackNavigationOptions;
export default slideFromLeft;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/types.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/types.ts
deleted file mode 100644
index f170562c3b7a..000000000000
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromLeft/types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-
-type SlideFromLeftTransitionNavigationOptions = PlatformSpecificNavigationOptions;
-
-export default SlideFromLeftTransitionNavigationOptions;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.android.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.android.ts
index da58d4d964a5..a42d5075b443 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.android.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.android.ts
@@ -1,7 +1,7 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
-import Animations from '..';
-import type SlideFromRightTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import {InternalPlatformAnimations} from '..';
-const transition: SlideFromRightTransitionNavigationOptions = {animation: Animations.IOS_FROM_RIGHT} satisfies NativeStackNavigationOptions;
+const transition: PlatformSpecificNavigationOptions = {animation: InternalPlatformAnimations.IOS_FROM_RIGHT} satisfies NativeStackNavigationOptions;
export default transition;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ios.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ios.ts
index 7b4677b2bf2f..287fe4ccbe12 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ios.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ios.ts
@@ -1,9 +1,9 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
-import Animations from '..';
-import type SlideFromRightTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
+import {InternalPlatformAnimations} from '..';
// default transition is causing weird keyboard appearance: - https://github.com/Expensify/App/issues/37257
// so we are using `simple_push` which is similar to default and not causing keyboard transition issues
-const transition: SlideFromRightTransitionNavigationOptions = {animation: Animations.SIMPLE_PUSH} satisfies NativeStackNavigationOptions;
+const transition: PlatformSpecificNavigationOptions = {animation: InternalPlatformAnimations.SIMPLE_PUSH} satisfies NativeStackNavigationOptions;
export default transition;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ts
index 2bc6b96b944f..8b6bdf9a323e 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/index.ts
@@ -1,6 +1,6 @@
import type {StackNavigationOptions} from '@react-navigation/stack';
-import type SlideFromRightTransitionNavigationOptions from './types';
+import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-const slideFromRight: SlideFromRightTransitionNavigationOptions = {animationEnabled: true, gestureDirection: 'horizontal'} satisfies StackNavigationOptions;
+const slideFromRight: PlatformSpecificNavigationOptions = {animationEnabled: true, gestureDirection: 'horizontal'} satisfies StackNavigationOptions;
export default slideFromRight;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/types.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/types.ts
deleted file mode 100644
index d1afa32d0dcf..000000000000
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/slideFromRight/types.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type {PlatformSpecificNavigationOptions} from '@libs/Navigation/PlatformStackNavigation/types';
-
-type SlideFromRightTransitionNavigationOptions = PlatformSpecificNavigationOptions;
-
-export default SlideFromRightTransitionNavigationOptions;
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/withAnimation.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/withAnimation.ts
index d485c62ea463..9fafa1f14bad 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/withAnimation.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/animation/withAnimation.ts
@@ -15,7 +15,7 @@ function withAnimation
screenOptions === undefined ? {} : (({animation, keyboardHandlingEnabled, web, native, ...rest}: PlatformStackNavigationOptions) => rest)(screenOptions);
-const buildPlatformSpecificNavigationOptions = (
- screenOptions: PlatformStackNavigationOptions,
-): PlatformSpecificNavigationOptions => ({
+const buildPlatformSpecificNavigationOptions = (screenOptions: PlatformStackNavigationOptions): NavigationOptions => ({
keyboardHandlingEnabled: screenOptions.keyboardHandlingEnabled,
- ...withAnimation(screenOptions),
+ ...withAnimation(screenOptions),
...getCommonNavigationOptions(screenOptions),
});
diff --git a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/presentation/index.ts b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/presentation/index.ts
index 0454b87427f1..0d768f269d58 100644
--- a/src/libs/Navigation/PlatformStackNavigation/navigationOptions/presentation/index.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/navigationOptions/presentation/index.ts
@@ -1,5 +1,7 @@
const Presentation = {
CARD: 'card',
+ MODAL: 'modal',
+ TRANSPARENT_MODAL: 'transparentModal',
} as const;
export default Presentation;
diff --git a/src/libs/Navigation/PlatformStackNavigation/types/NavigationOptions.ts b/src/libs/Navigation/PlatformStackNavigation/types/NavigationOptions.ts
index eab3bc313b37..b4e1ab3252cf 100644
--- a/src/libs/Navigation/PlatformStackNavigation/types/NavigationOptions.ts
+++ b/src/libs/Navigation/PlatformStackNavigation/types/NavigationOptions.ts
@@ -1,5 +1,7 @@
import type {NativeStackNavigationOptions} from '@react-navigation/native-stack';
import type {StackNavigationOptions} from '@react-navigation/stack';
+import type Animations from '@libs/Navigation/PlatformStackNavigation/navigationOptions/animation';
+import type Presentation from '@libs/Navigation/PlatformStackNavigation/navigationOptions/presentation';
import type CommonProperties from '@src/types/utils/CommonProperties';
// Navigation properties that are only available in web or native stack navigations.
@@ -14,14 +16,14 @@ type GeneralPlatformStackNavigationOptions = {
native?: NativeOnlyNavigationOptions;
keyboardHandlingEnabled?: boolean;
- animation?: 'slide_from_left' | 'slide_from_right' | 'modal' | 'none';
- presentation?: 'card' | 'modal' | 'transparentModal';
+ animation?: (typeof Animations)[keyof typeof Animations];
+ presentation?: (typeof Presentation)[keyof typeof Presentation];
};
// Combines common and general platform-specific options for PlatformStackNavigation.
type PlatformStackNavigationOptions = CommonStackNavigationOptions & GeneralPlatformStackNavigationOptions;
-// Used to represent platform-specific navigation options.
+// Used to represent navigation options specific to the native implementation/platform (`stack` or `native-stack`).
type PlatformSpecificNavigationOptions = StackNavigationOptions | NativeStackNavigationOptions;
export type {
diff --git a/src/libs/Navigation/getOnboardingModalScreenOptions/index.native.ts b/src/libs/Navigation/getOnboardingModalScreenOptions/index.native.ts
deleted file mode 100644
index 98dd131a9332..000000000000
--- a/src/libs/Navigation/getOnboardingModalScreenOptions/index.native.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions';
-import type {ThemeStyles} from '@styles/index';
-import type {StyleUtilsType} from '@styles/utils';
-
-function getOnboardingModalScreenOptions(isSmallScreenWidth: boolean, styles: ThemeStyles, StyleUtils: StyleUtilsType) {
- return {
- ...getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils).fullScreen,
- gestureEnabled: false,
- };
-}
-
-export default getOnboardingModalScreenOptions;
diff --git a/src/libs/Navigation/getOnboardingModalScreenOptions/index.ts b/src/libs/Navigation/getOnboardingModalScreenOptions/index.ts
deleted file mode 100644
index aad1964f441c..000000000000
--- a/src/libs/Navigation/getOnboardingModalScreenOptions/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import getRootNavigatorScreenOptions from '@libs/Navigation/AppNavigator/getRootNavigatorScreenOptions';
-import type {ThemeStyles} from '@styles/index';
-import type {StyleUtilsType} from '@styles/utils';
-
-function getOnboardingModalScreenOptions(isSmallScreenWidth: boolean, styles: ThemeStyles, StyleUtils: StyleUtilsType, shouldUseNarrowLayout: boolean) {
- return getRootNavigatorScreenOptions(isSmallScreenWidth, styles, StyleUtils).onboardingModalNavigator(shouldUseNarrowLayout);
-}
-
-export default getOnboardingModalScreenOptions;
diff --git a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
index f7c2140b1117..d31c3693d495 100644
--- a/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
+++ b/src/libs/Navigation/setupCustomAndroidBackHandler/index.android.ts
@@ -1,13 +1,13 @@
import {findFocusedRoute, StackActions} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import {BackHandler, NativeModules} from 'react-native';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import getTopmostCentralPaneRoute from '@navigation/getTopmostCentralPaneRoute';
import navigationRef from '@navigation/navigationRef';
import type {BottomTabNavigatorParamList, RootStackParamList, State} from '@navigation/types';
import NAVIGATORS from '@src/NAVIGATORS';
import SCREENS from '@src/SCREENS';
-type SearchPageProps = StackScreenProps;
+type SearchPageProps = PlatformStackScreenProps;
// We need to do some custom handling for the back button on Android for actions related to the search page.
function setupCustomAndroidBackHandler() {
diff --git a/src/libs/Navigation/switchPolicyID.ts b/src/libs/Navigation/switchPolicyID.ts
index 16e705258e58..3d7592fcf057 100644
--- a/src/libs/Navigation/switchPolicyID.ts
+++ b/src/libs/Navigation/switchPolicyID.ts
@@ -1,4 +1,4 @@
-import {getActionFromState} from '@react-navigation/core';
+import {CommonActions, getActionFromState} from '@react-navigation/core';
import type {NavigationAction, NavigationContainerRef, NavigationState, PartialState} from '@react-navigation/native';
import {getPathFromState} from '@react-navigation/native';
import type {Writable} from 'type-fest';
@@ -52,6 +52,17 @@ function getActionForBottomTabNavigator(action: StackNavigationAction, state: Na
params.policyID = policyID;
}
+ // If there already is a 'Home' route, we want to change the params rather than pushing a new 'Home' route,
+ // so that the screen does not get re-mounted. This would cause an empty screen/white flash when navigating back from the workspace switcher.
+ const homeRoute = bottomTabNavigatorRoute.state.routes.at(-1);
+ if (homeRoute && homeRoute.name === SCREENS.HOME) {
+ return {
+ ...CommonActions.setParams(params),
+ source: homeRoute?.key,
+ };
+ }
+
+ // If there is no 'Home' route, we want to push a new route.
return {
type: CONST.NAVIGATION.ACTION_TYPE.PUSH,
payload: {
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 798e77d86ecc..eae4388b019e 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -17,7 +17,7 @@ import type {SaveSearchParams} from '@libs/API/parameters';
import type CONST from '@src/CONST';
import type {Country, IOUAction, IOUType} from '@src/CONST';
import type NAVIGATORS from '@src/NAVIGATORS';
-import type {HybridAppRoute, Route as Routes} from '@src/ROUTES';
+import type {Route as ExpensifyRoute, HybridAppRoute, Route as Routes} from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type EXIT_SURVEY_REASON_FORM_INPUT_IDS from '@src/types/form/ExitSurveyReasonForm';
import type {CompanyCardFeed} from '@src/types/onyx';
@@ -1167,6 +1167,18 @@ type MoneyRequestNavigatorParamList = {
backTo?: Routes;
currency?: string;
};
+ [SCREENS.MONEY_REQUEST.HOLD]: {
+ /** ID of the transaction the page was opened for */
+ transactionID: string;
+
+ /** ID of the report that user is providing hold reason to */
+ reportID: string;
+
+ /** Link to previous page */
+ backTo: ExpensifyRoute;
+
+ searchHash?: number;
+ };
[SCREENS.MONEY_REQUEST.STEP_ATTENDEES]: {
action: IOUAction;
iouType: Exclude;
@@ -1594,6 +1606,18 @@ type SearchReportParamList = {
reportID: string;
reportActionID?: string;
};
+ [SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP]: {
+ /** ID of the transaction the page was opened for */
+ transactionID: string;
+
+ /** ID of the report that user is providing hold reason to */
+ reportID: string;
+
+ /** Link to previous page */
+ backTo: ExpensifyRoute;
+
+ searchHash?: number;
+ };
};
type SearchAdvancedFiltersParamList = {
diff --git a/src/pages/ConciergePage.tsx b/src/pages/ConciergePage.tsx
index 46f17e76c083..897d1c429799 100644
--- a/src/pages/ConciergePage.tsx
+++ b/src/pages/ConciergePage.tsx
@@ -1,5 +1,4 @@
import {useFocusEffect} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect, useRef} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
@@ -10,6 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import * as App from '@userActions/App';
import * as Report from '@userActions/Report';
@@ -22,7 +22,7 @@ type ConciergePageOnyxProps = {
session: OnyxEntry;
};
-type ConciergePageProps = ConciergePageOnyxProps & StackScreenProps;
+type ConciergePageProps = ConciergePageOnyxProps & PlatformStackScreenProps;
/*
* This is a "utility page", that does this:
diff --git a/src/pages/Debug/DebugDetailsConstantPickerPage.tsx b/src/pages/Debug/DebugDetailsConstantPickerPage.tsx
index a98ef9963542..e195351cc0a4 100644
--- a/src/pages/Debug/DebugDetailsConstantPickerPage.tsx
+++ b/src/pages/Debug/DebugDetailsConstantPickerPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import isObject from 'lodash/isObject';
import React, {useMemo, useState} from 'react';
import {View} from 'react-native';
@@ -10,12 +9,13 @@ import type {ListItem} from '@components/SelectionList/types';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import {appendParam} from '@libs/Url';
import type SCREENS from '@src/SCREENS';
import {DETAILS_CONSTANT_OPTIONS} from './const';
-type DebugDetailsConstantPickerPageProps = StackScreenProps;
+type DebugDetailsConstantPickerPageProps = PlatformStackScreenProps;
function DebugDetailsConstantPickerPage({
route: {
diff --git a/src/pages/Debug/DebugDetailsDateTimePickerPage.tsx b/src/pages/Debug/DebugDetailsDateTimePickerPage.tsx
index 920b5b52076c..b2be1429ee5b 100644
--- a/src/pages/Debug/DebugDetailsDateTimePickerPage.tsx
+++ b/src/pages/Debug/DebugDetailsDateTimePickerPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import {format} from 'date-fns';
import React, {useState} from 'react';
import {View} from 'react-native';
@@ -12,11 +11,12 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import DateUtils from '@libs/DateUtils';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import {appendParam} from '@libs/Url';
import type SCREENS from '@src/SCREENS';
-type DebugDetailsDateTimePickerPageProps = StackScreenProps;
+type DebugDetailsDateTimePickerPageProps = PlatformStackScreenProps;
function DebugDetailsDateTimePickerPage({
route: {
diff --git a/src/pages/Debug/Report/DebugReportPage.tsx b/src/pages/Debug/Report/DebugReportPage.tsx
index 67fa0a6c5113..85a562f6827e 100644
--- a/src/pages/Debug/Report/DebugReportPage.tsx
+++ b/src/pages/Debug/Report/DebugReportPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -17,6 +16,7 @@ import DebugUtils from '@libs/DebugUtils';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import DebugDetails from '@pages/Debug/DebugDetails';
@@ -29,7 +29,7 @@ import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import DebugReportActions from './DebugReportActions';
-type DebugReportPageProps = StackScreenProps;
+type DebugReportPageProps = PlatformStackScreenProps;
type Metadata = {
title: string;
diff --git a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
index 0b260a8bc93e..429f42b58dda 100644
--- a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
+++ b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
@@ -15,6 +14,7 @@ import DateUtils from '@libs/DateUtils';
import DebugUtils from '@libs/DebugUtils';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import * as NumberUtils from '@libs/NumberUtils';
import ReportActionItem from '@pages/home/report/ReportActionItem';
@@ -26,7 +26,7 @@ import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {PersonalDetailsList, ReportAction, Session} from '@src/types/onyx';
-type DebugReportActionCreatePageProps = StackScreenProps;
+type DebugReportActionCreatePageProps = PlatformStackScreenProps;
const getInitialReportAction = (reportID: string, session: OnyxEntry, personalDetailsList: OnyxEntry) =>
DebugUtils.stringifyJSON({
diff --git a/src/pages/Debug/ReportAction/DebugReportActionPage.tsx b/src/pages/Debug/ReportAction/DebugReportActionPage.tsx
index 68743278d871..9478d66018f7 100644
--- a/src/pages/Debug/ReportAction/DebugReportActionPage.tsx
+++ b/src/pages/Debug/ReportAction/DebugReportActionPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
@@ -11,6 +10,7 @@ import DebugUtils from '@libs/DebugUtils';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import DebugDetails from '@pages/Debug/DebugDetails';
import DebugJSON from '@pages/Debug/DebugJSON';
@@ -20,7 +20,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import DebugReportActionPreview from './DebugReportActionPreview';
-type DebugReportActionPageProps = StackScreenProps;
+type DebugReportActionPageProps = PlatformStackScreenProps;
function DebugReportActionPage({
route: {
diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx
index d7d359d289f4..25023badbd1e 100644
--- a/src/pages/EditReportFieldPage.tsx
+++ b/src/pages/EditReportFieldPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import React, {useState} from 'react';
import {useOnyx} from 'react-native-onyx';
@@ -14,6 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import isSearchTopmostCentralPane from '@libs/Navigation/isSearchTopmostCentralPane';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {EditRequestNavigatorParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import CONST from '@src/CONST';
@@ -25,7 +25,7 @@ import EditReportFieldDate from './EditReportFieldDate';
import EditReportFieldDropdown from './EditReportFieldDropdown';
import EditReportFieldText from './EditReportFieldText';
-type EditReportFieldPageProps = StackScreenProps;
+type EditReportFieldPageProps = PlatformStackScreenProps;
function EditReportFieldPage({route}: EditReportFieldPageProps) {
const {windowWidth} = useWindowDimensions();
diff --git a/src/pages/FlagCommentPage.tsx b/src/pages/FlagCommentPage.tsx
index 49045c66c72b..fbedd5fc6c39 100644
--- a/src/pages/FlagCommentPage.tsx
+++ b/src/pages/FlagCommentPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {View} from 'react-native';
import type {SvgProps} from 'react-native-svg';
@@ -13,6 +12,7 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {FlagCommentNavigatorParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as Report from '@userActions/Report';
@@ -22,7 +22,7 @@ import type SCREENS from '@src/SCREENS';
import withReportAndReportActionOrNotFound from './home/report/withReportAndReportActionOrNotFound';
import type {WithReportAndReportActionOrNotFoundProps} from './home/report/withReportAndReportActionOrNotFound';
-type FlagCommentPageNavigationProps = StackScreenProps;
+type FlagCommentPageNavigationProps = PlatformStackScreenProps;
type FlagCommentPageProps = WithReportAndReportActionOrNotFoundProps & FlagCommentPageNavigationProps;
diff --git a/src/pages/GetAssistancePage.tsx b/src/pages/GetAssistancePage.tsx
index 90b7ccbb28d8..aecb78b76a76 100644
--- a/src/pages/GetAssistancePage.tsx
+++ b/src/pages/GetAssistancePage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
@@ -15,6 +14,7 @@ import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import * as Link from '@userActions/Link';
import * as Report from '@userActions/Report';
@@ -29,7 +29,7 @@ type GetAssistanceOnyxProps = {
account: OnyxEntry;
};
-type GetAssistancePageProps = GetAssistanceOnyxProps & StackScreenProps;
+type GetAssistancePageProps = GetAssistanceOnyxProps & PlatformStackScreenProps;
function GetAssistancePage({route, account}: GetAssistancePageProps) {
const styles = useThemeStyles();
diff --git a/src/pages/GroupChatNameEditPage.tsx b/src/pages/GroupChatNameEditPage.tsx
index 425e8a421cb2..100efb69cae1 100644
--- a/src/pages/GroupChatNameEditPage.tsx
+++ b/src/pages/GroupChatNameEditPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback, useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
@@ -12,6 +11,7 @@ import useAutoFocusInput from '@hooks/useAutoFocusInput';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {NewChatNavigatorParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as ValidationUtils from '@libs/ValidationUtils';
@@ -30,7 +30,7 @@ type GroupChatNameEditPageOnyxProps = {
};
type GroupChatNameEditPageProps = GroupChatNameEditPageOnyxProps &
- Partial> & {
+ Partial> & {
report?: ReportOnyxType;
};
diff --git a/src/pages/InviteReportParticipantsPage.tsx b/src/pages/InviteReportParticipantsPage.tsx
index 6a5bf6832fd6..b639d984a132 100644
--- a/src/pages/InviteReportParticipantsPage.tsx
+++ b/src/pages/InviteReportParticipantsPage.tsx
@@ -1,4 +1,3 @@
-import type {RouteProp} from '@react-navigation/native';
import {useRoute} from '@react-navigation/native';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import type {SectionListData} from 'react-native';
@@ -20,6 +19,7 @@ import * as UserSearchPhraseActions from '@libs/actions/RoomMembersUserSearchPhr
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as LoginUtils from '@libs/LoginUtils';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
@@ -44,7 +44,7 @@ type InviteReportParticipantsPageProps = InviteReportParticipantsPageOnyxProps &
type Sections = Array>>;
function InviteReportParticipantsPage({betas, personalDetails, report, didScreenTransitionEnd}: InviteReportParticipantsPageProps) {
- const route = useRoute>();
+ const route = useRoute>();
const {options, areOptionsInitialized} = useOptionsList({
shouldInitialize: didScreenTransitionEnd,
});
diff --git a/src/pages/LogInWithShortLivedAuthTokenPage.tsx b/src/pages/LogInWithShortLivedAuthTokenPage.tsx
index e604f2ccf847..45c640fc856e 100644
--- a/src/pages/LogInWithShortLivedAuthTokenPage.tsx
+++ b/src/pages/LogInWithShortLivedAuthTokenPage.tsx
@@ -1,10 +1,10 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useEffect} from 'react';
import {NativeModules} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {PublicScreensParamList} from '@libs/Navigation/types';
import * as Session from '@userActions/Session';
import CONST from '@src/CONST';
@@ -14,7 +14,7 @@ import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import SessionExpiredPage from './ErrorPage/SessionExpiredPage';
-type LogInWithShortLivedAuthTokenPageProps = StackScreenProps;
+type LogInWithShortLivedAuthTokenPageProps = PlatformStackScreenProps;
function LogInWithShortLivedAuthTokenPage({route}: LogInWithShortLivedAuthTokenPageProps) {
const {email = '', shortLivedAuthToken = '', shortLivedToken = '', authTokenType, exitTo, error} = route?.params ?? {};
diff --git a/src/pages/LogOutPreviousUserPage.tsx b/src/pages/LogOutPreviousUserPage.tsx
index deb95a576c3d..bb381bb156ed 100644
--- a/src/pages/LogOutPreviousUserPage.tsx
+++ b/src/pages/LogOutPreviousUserPage.tsx
@@ -1,10 +1,10 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useContext, useEffect} from 'react';
import {NativeModules} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import {InitialURLContext} from '@components/InitialURLContextProvider';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import * as SessionUtils from '@libs/SessionUtils';
import Navigation from '@navigation/Navigation';
import type {AuthScreensParamList} from '@navigation/types';
@@ -24,7 +24,7 @@ type LogOutPreviousUserPageOnyxProps = {
isAccountLoading: boolean;
};
-type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & StackScreenProps;
+type LogOutPreviousUserPageProps = LogOutPreviousUserPageOnyxProps & PlatformStackScreenProps;
// This page is responsible for handling transitions from OldDot. Specifically, it logs the current user
// out if the transition is for another user.
diff --git a/src/pages/OnboardingAccounting/types.ts b/src/pages/OnboardingAccounting/types.ts
index 4f7a3ebc3439..fb9e1e1caac4 100644
--- a/src/pages/OnboardingAccounting/types.ts
+++ b/src/pages/OnboardingAccounting/types.ts
@@ -1,8 +1,8 @@
-import type {StackScreenProps} from '@react-navigation/stack';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types';
import type SCREENS from '@src/SCREENS';
-type OnboardingAccountingProps = StackScreenProps;
+type OnboardingAccountingProps = PlatformStackScreenProps;
type BaseOnboardingAccountingProps = OnboardingAccountingProps & {
/* Whether to use native styles tailored for native devices */
diff --git a/src/pages/OnboardingEmployees/types.ts b/src/pages/OnboardingEmployees/types.ts
index b4cdafced839..84d93e6152a4 100644
--- a/src/pages/OnboardingEmployees/types.ts
+++ b/src/pages/OnboardingEmployees/types.ts
@@ -1,8 +1,8 @@
-import type {StackScreenProps} from '@react-navigation/stack';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types';
import type SCREENS from '@src/SCREENS';
-type OnboardingEmployeesProps = StackScreenProps;
+type OnboardingEmployeesProps = PlatformStackScreenProps;
type BaseOnboardingEmployeesProps = OnboardingEmployeesProps & {
/* Whether to use native styles tailored for native devices */
diff --git a/src/pages/OnboardingPersonalDetails/types.ts b/src/pages/OnboardingPersonalDetails/types.ts
index 79aca4af4639..e8b99d949fa7 100644
--- a/src/pages/OnboardingPersonalDetails/types.ts
+++ b/src/pages/OnboardingPersonalDetails/types.ts
@@ -1,16 +1,14 @@
-import type {RouteProp} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types';
import type SCREENS from '@src/SCREENS';
-type OnboardingPersonalDetailsProps = Record & StackScreenProps;
+type OnboardingPersonalDetailsProps = Record & PlatformStackScreenProps;
-type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps & {
- /* Whether to use native styles tailored for native devices */
- shouldUseNativeStyles: boolean;
-
- route: RouteProp;
-};
+type BaseOnboardingPersonalDetailsProps = WithCurrentUserPersonalDetailsProps &
+ PlatformStackScreenProps & {
+ /* Whether to use native styles tailored for native devices */
+ shouldUseNativeStyles: boolean;
+ };
export type {OnboardingPersonalDetailsProps, BaseOnboardingPersonalDetailsProps};
diff --git a/src/pages/OnboardingPurpose/types.ts b/src/pages/OnboardingPurpose/types.ts
index 7a61196fd328..8f2f99b97e56 100644
--- a/src/pages/OnboardingPurpose/types.ts
+++ b/src/pages/OnboardingPurpose/types.ts
@@ -1,8 +1,8 @@
-import type {StackScreenProps} from '@react-navigation/stack';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {OnboardingModalNavigatorParamList} from '@libs/Navigation/types';
import type SCREENS from '@src/SCREENS';
-type OnboardingPurposeProps = Record & StackScreenProps;
+type OnboardingPurposeProps = Record & PlatformStackScreenProps;
type BaseOnboardingPurposeProps = OnboardingPurposeProps & {
/* Whether to use native styles tailored for native devices */
diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx
index 53a52f9cebb5..bfe534420e0d 100644
--- a/src/pages/PrivateNotes/PrivateNotesEditPage.tsx
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.tsx
@@ -1,5 +1,4 @@
import {useFocusEffect} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import lodashDebounce from 'lodash/debounce';
import React, {useCallback, useMemo, useRef, useState} from 'react';
@@ -17,6 +16,7 @@ import useHtmlPaste from '@hooks/useHtmlPaste';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {PrivateNotesNavigatorParamList} from '@libs/Navigation/types';
import Parser from '@libs/Parser';
import * as ReportUtils from '@libs/ReportUtils';
@@ -34,7 +34,7 @@ import type {Report} from '@src/types/onyx';
import type {Note} from '@src/types/onyx/Report';
type PrivateNotesEditPageProps = WithReportAndPrivateNotesOrNotFoundProps &
- StackScreenProps & {
+ PlatformStackScreenProps & {
/** The report currently being looked at */
report: Report;
};
diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.tsx b/src/pages/PrivateNotes/PrivateNotesListPage.tsx
index 474075d928f8..2271eee7c54e 100644
--- a/src/pages/PrivateNotes/PrivateNotesListPage.tsx
+++ b/src/pages/PrivateNotes/PrivateNotesListPage.tsx
@@ -1,4 +1,3 @@
-import type {RouteProp} from '@react-navigation/native';
import {useRoute} from '@react-navigation/native';
import React, {useCallback, useMemo} from 'react';
import {useOnyx} from 'react-native-onyx';
@@ -12,6 +11,7 @@ import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {PrivateNotesNavigatorParamList} from '@libs/Navigation/types';
import type {WithReportAndPrivateNotesOrNotFoundProps} from '@pages/home/report/withReportAndPrivateNotesOrNotFound';
import withReportAndPrivateNotesOrNotFound from '@pages/home/report/withReportAndPrivateNotesOrNotFound';
@@ -37,7 +37,7 @@ type NoteListItem = {
};
function PrivateNotesListPage({report, accountID: sessionAccountID}: PrivateNotesListPageProps) {
- const route = useRoute>();
+ const route = useRoute>();
const backTo = route.params.backTo;
const [personalDetailsList] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const styles = useThemeStyles();
diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx
index b9746126135d..8d0d69a09988 100755
--- a/src/pages/ProfilePage.tsx
+++ b/src/pages/ProfilePage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
@@ -24,6 +23,7 @@ import UserDetailsTooltip from '@components/UserDetailsTooltip';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import {parsePhoneNumber} from '@libs/PhoneNumber';
import * as ReportUtils from '@libs/ReportUtils';
@@ -43,7 +43,7 @@ import type {PersonalDetails, Report} from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import mapOnyxCollectionItems from '@src/utils/mapOnyxCollectionItems';
-type ProfilePageProps = StackScreenProps;
+type ProfilePageProps = PlatformStackScreenProps;
/**
* Gets the phone number to display for SMS logins
diff --git a/src/pages/ReferralDetailsPage.tsx b/src/pages/ReferralDetailsPage.tsx
index d8a27e171933..76dac1aca1a8 100644
--- a/src/pages/ReferralDetailsPage.tsx
+++ b/src/pages/ReferralDetailsPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
@@ -15,6 +14,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import Clipboard from '@libs/Clipboard';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReferralDetailsNavigatorParamList} from '@libs/Navigation/types';
import * as Link from '@userActions/Link';
import CONST from '@src/CONST';
@@ -29,7 +29,7 @@ type ReferralDetailsPageOnyxProps = {
account: OnyxEntry;
};
-type ReferralDetailsPageProps = ReferralDetailsPageOnyxProps & StackScreenProps;
+type ReferralDetailsPageProps = ReferralDetailsPageOnyxProps & PlatformStackScreenProps;
function ReferralDetailsPage({route, account}: ReferralDetailsPageProps) {
const theme = useTheme();
diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
index 6c3b289e59df..bf5277185962 100644
--- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
+++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx
@@ -1,5 +1,3 @@
-import type {RouteProp} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import lodashPick from 'lodash/pick';
import React, {useEffect, useRef, useState} from 'react';
@@ -20,6 +18,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI';
import BankAccount from '@libs/models/BankAccount';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackRouteProp, PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReimbursementAccountNavigatorParamList} from '@libs/Navigation/types';
import * as PolicyUtils from '@libs/PolicyUtils';
import shouldReopenOnfido from '@libs/shouldReopenOnfido';
@@ -49,7 +48,7 @@ import Finish from './NonUSD/Finish/Finish';
import SignerInfo from './NonUSD/SignerInfo';
import RequestorStep from './RequestorStep';
-type ReimbursementAccountPageProps = WithPolicyOnyxProps & StackScreenProps;
+type ReimbursementAccountPageProps = WithPolicyOnyxProps & PlatformStackScreenProps;
const ROUTE_NAMES = {
COMPANY: 'company',
@@ -67,7 +66,7 @@ const SUPPORTED_FOREIGN_CURRENCIES: string[] = [CONST.CURRENCY.EUR, CONST.CURREN
* We can pass stepToOpen in the URL to force which step to show.
* Mainly needed when user finished the flow in verifying state, and Ops ask them to modify some fields from a specific step.
*/
-function getStepToOpenFromRouteParams(route: RouteProp): TBankAccountStep | '' {
+function getStepToOpenFromRouteParams(route: PlatformStackRouteProp): TBankAccountStep | '' {
switch (route.params.stepToOpen) {
case ROUTE_NAMES.NEW:
return CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT;
diff --git a/src/pages/ReportAvatar.tsx b/src/pages/ReportAvatar.tsx
index b9a91705a401..ac139e58a9ff 100644
--- a/src/pages/ReportAvatar.tsx
+++ b/src/pages/ReportAvatar.tsx
@@ -1,8 +1,8 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useMemo} from 'react';
import {useOnyx} from 'react-native-onyx';
import AttachmentModal from '@components/AttachmentModal';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {AuthScreensParamList} from '@libs/Navigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import * as UserUtils from '@libs/UserUtils';
@@ -10,7 +10,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
-type ReportAvatarProps = StackScreenProps;
+type ReportAvatarProps = PlatformStackScreenProps;
function ReportAvatar({route}: ReportAvatarProps) {
const reportIDFromRoute = route.params?.reportID ?? '-1';
diff --git a/src/pages/ReportDescriptionPage.tsx b/src/pages/ReportDescriptionPage.tsx
index 6062ef748f36..0aabe5ad5d58 100644
--- a/src/pages/ReportDescriptionPage.tsx
+++ b/src/pages/ReportDescriptionPage.tsx
@@ -1,5 +1,5 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import * as ReportUtils from '@libs/ReportUtils';
import type {ReportDescriptionNavigatorParamList} from '@navigation/types';
import type SCREENS from '@src/SCREENS';
@@ -8,7 +8,7 @@ import withReportOrNotFound from './home/report/withReportOrNotFound';
import RoomDescriptionPage from './RoomDescriptionPage';
import TaskDescriptionPage from './tasks/TaskDescriptionPage';
-type ReportDescriptionPageProps = WithReportOrNotFoundProps & StackScreenProps;
+type ReportDescriptionPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps;
function ReportDescriptionPage(props: ReportDescriptionPageProps) {
const isTask = ReportUtils.isTaskReport(props.report);
diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx
index 9e438f0549e2..d86d6671ce16 100644
--- a/src/pages/ReportDetailsPage.tsx
+++ b/src/pages/ReportDetailsPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
@@ -34,6 +33,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportActions from '@libs/actions/Report';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReportDetailsNavigatorParamList} from '@libs/Navigation/types';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
@@ -70,7 +70,7 @@ type ReportDetailsPageMenuItem = {
shouldShowRightIcon?: boolean;
};
-type ReportDetailsPageProps = WithReportOrNotFoundProps & StackScreenProps;
+type ReportDetailsPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps;
const CASES = {
DEFAULT: 'default',
diff --git a/src/pages/ReportParticipantDetailsPage.tsx b/src/pages/ReportParticipantDetailsPage.tsx
index db978b70cad8..342449ae2bef 100644
--- a/src/pages/ReportParticipantDetailsPage.tsx
+++ b/src/pages/ReportParticipantDetailsPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
@@ -18,6 +17,7 @@ import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Report from '@libs/actions/Report';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import Navigation from '@navigation/Navigation';
@@ -37,7 +37,7 @@ type ReportParticipantDetailsOnyxProps = {
};
type ReportParticipantDetailsPageProps = WithReportOrNotFoundProps &
- StackScreenProps &
+ PlatformStackScreenProps &
ReportParticipantDetailsOnyxProps;
function ReportParticipantDetails({personalDetails, report, route}: ReportParticipantDetailsPageProps) {
diff --git a/src/pages/ReportParticipantRoleSelectionPage.tsx b/src/pages/ReportParticipantRoleSelectionPage.tsx
index 17b84e8903ea..95b3f88e9e37 100644
--- a/src/pages/ReportParticipantRoleSelectionPage.tsx
+++ b/src/pages/ReportParticipantRoleSelectionPage.tsx
@@ -1,4 +1,3 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {View} from 'react-native';
import type {ValueOf} from 'type-fest';
@@ -10,6 +9,7 @@ import type {ListItem} from '@components/SelectionList/types';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Report from '@libs/actions/Report';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import Navigation from '@navigation/Navigation';
import type {ParticipantsNavigatorParamList} from '@navigation/types';
import CONST from '@src/CONST';
@@ -19,7 +19,7 @@ import NotFoundPage from './ErrorPage/NotFoundPage';
import withReportOrNotFound from './home/report/withReportOrNotFound';
import type {WithReportOrNotFoundProps} from './home/report/withReportOrNotFound';
-type ReportParticipantRoleSelectionPageProps = WithReportOrNotFoundProps & StackScreenProps;
+type ReportParticipantRoleSelectionPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps;
type ListItemType = ListItem & {
value: ValueOf;
diff --git a/src/pages/ReportParticipantsPage.tsx b/src/pages/ReportParticipantsPage.tsx
index 1c91023f2d6f..e5476baeee86 100755
--- a/src/pages/ReportParticipantsPage.tsx
+++ b/src/pages/ReportParticipantsPage.tsx
@@ -1,5 +1,4 @@
import {useIsFocused} from '@react-navigation/native';
-import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {InteractionManager, View} from 'react-native';
import type {TextInput} from 'react-native';
@@ -28,6 +27,7 @@ import {turnOffMobileSelectionMode} from '@libs/actions/MobileSelectionMode';
import * as Report from '@libs/actions/Report';
import * as UserSearchPhraseActions from '@libs/actions/RoomMembersUserSearchPhrase';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ParticipantsNavigatorParamList} from '@libs/Navigation/types';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
@@ -41,7 +41,7 @@ import withReportOrNotFound from './home/report/withReportOrNotFound';
type MemberOption = Omit & {accountID: number};
-type ReportParticipantsPageProps = WithReportOrNotFoundProps & StackScreenProps;
+type ReportParticipantsPageProps = WithReportOrNotFoundProps & PlatformStackScreenProps;
function ReportParticipantsPage({report, route}: ReportParticipantsPageProps) {
const backTo = route.params.backTo;
const [selectedMembers, setSelectedMembers] = useState([]);
diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
index a9cee3236ad0..bcb46c781262 100644
--- a/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
+++ b/src/pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage.tsx
@@ -1,7 +1,7 @@
-import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {useOnyx} from 'react-native-onyx';
import usePolicy from '@hooks/usePolicy';
+import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {RestrictedActionParamList} from '@libs/Navigation/types';
import * as PolicyUtils from '@libs/PolicyUtils';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
@@ -11,7 +11,7 @@ import WorkspaceAdminRestrictedAction from './WorkspaceAdminRestrictedAction';
import WorkspaceOwnerRestrictedAction from './WorkspaceOwnerRestrictedAction';
import WorkspaceUserRestrictedAction from './WorkspaceUserRestrictedAction';
-type WorkspaceRestrictedActionPageProps = StackScreenProps;
+type WorkspaceRestrictedActionPageProps = PlatformStackScreenProps;
function WorkspaceRestrictedActionPage({
route: {
diff --git a/src/pages/RoomDescriptionPage.tsx b/src/pages/RoomDescriptionPage.tsx
index fde0eb72e2dc..68da1cabf59c 100644
--- a/src/pages/RoomDescriptionPage.tsx
+++ b/src/pages/RoomDescriptionPage.tsx
@@ -1,4 +1,3 @@
-import type {RouteProp} from '@react-navigation/native';
import {useFocusEffect, useRoute} from '@react-navigation/native';
import React, {useCallback, useRef, useState} from 'react';
import {View} from 'react-native';
@@ -15,6 +14,7 @@ import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
+import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
import type {ReportDescriptionNavigatorParamList} from '@libs/Navigation/types';
import Parser from '@libs/Parser';
import * as ReportUtils from '@libs/ReportUtils';
@@ -37,7 +37,7 @@ type RoomDescriptionPageProps = {
};
function RoomDescriptionPage({report, policies}: RoomDescriptionPageProps) {
- const route = useRoute