-
Notifications
You must be signed in to change notification settings - Fork 3.8k
[CP Staging] Revert "Fix reveal navigation under RHP + re-land reveal workspace route under RHP before dismissing on workspace creation " #90982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,31 +1,37 @@ | ||
| import type {ParamListBase, PartialState, Router, RouterConfigOptions} from '@react-navigation/native'; | ||
| import Log from '@libs/Log'; | ||
| import type {RootStackNavigatorAction} from '@libs/Navigation/AppNavigator/createRootStackNavigator/types'; | ||
| import type {CommonActions, ParamListBase, PartialState, Router, RouterConfigOptions, StackActionType} from '@react-navigation/native'; | ||
| import type {RemoveFullscreenUnderRHPActionType, ReplaceFullscreenUnderRHPActionType, RootStackNavigatorAction} from '@libs/Navigation/AppNavigator/createRootStackNavigator/types'; | ||
| import type {PlatformStackNavigationState, PlatformStackRouterFactory, PlatformStackRouterOptions} from '@libs/Navigation/PlatformStackNavigation/types'; | ||
| import CONST from '@src/CONST'; | ||
| import { | ||
| applyRevealPaddingOffset, | ||
| getFrozenHistoryStateForRemoveFullscreenUnderRHP, | ||
| getFrozenHistoryStateForReplaceFullscreenUnderRHP, | ||
| getRevealDismissState, | ||
| isDismissModalAction, | ||
| isRemoveFullscreenUnderRHPAction, | ||
| isReplaceFullscreenUnderRHPAction, | ||
| } from './addRootHistoryRouterExtensionUtils'; | ||
| import type {PendingReveal, RootHistoryState} from './addRootHistoryRouterExtensionUtils'; | ||
| import {enhanceStateWithHistory} from './utils'; | ||
|
|
||
| /** Manages root `state.history` for side-panel + reveal flows; per-branch rationale inline. */ | ||
| function isReplaceFullscreenUnderRHPAction(action: RootStackNavigatorAction): action is ReplaceFullscreenUnderRHPActionType { | ||
| return action.type === CONST.NAVIGATION.ACTION_TYPE.REPLACE_FULLSCREEN_UNDER_RHP; | ||
| } | ||
|
|
||
| function isRemoveFullscreenUnderRHPAction(action: RootStackNavigatorAction): action is RemoveFullscreenUnderRHPActionType { | ||
| return action.type === CONST.NAVIGATION.ACTION_TYPE.REMOVE_FULLSCREEN_UNDER_RHP; | ||
| } | ||
|
|
||
| /** | ||
| * Higher-order function that extends a React Navigation stack router with history | ||
| * management for the root stack navigator. | ||
| * | ||
| * It maintains a `history` array mirroring the routes and handles two concerns: | ||
| * | ||
| * 1. **Side panel** – preserves the CUSTOM_HISTORY_ENTRY_SIDE_PANEL entry through | ||
| * rehydration so the side panel open/close state survives navigation state rebuilds. | ||
| * | ||
| * 2. **REPLACE/REMOVE_FULLSCREEN_UNDER_RHP** - freezes the history array for these | ||
| * actions so that useLinking sees historyDelta=0 and does NOT push/pop any browser | ||
| * history entries for these intermediate state changes. The correct browser history | ||
| * update happens later when DISMISS_MODAL pops the RHP in the next animation frame. | ||
| */ | ||
| function addRootHistoryRouterExtension<RouterOptions extends PlatformStackRouterOptions = PlatformStackRouterOptions>( | ||
| originalRouter: PlatformStackRouterFactory<ParamListBase, RouterOptions>, | ||
| ) { | ||
| return (options: RouterOptions): Router<PlatformStackNavigationState<ParamListBase>, RootStackNavigatorAction> => { | ||
| return (options: RouterOptions): Router<PlatformStackNavigationState<ParamListBase>, CommonActions.Action | StackActionType> => { | ||
| const router = originalRouter(options); | ||
|
|
||
| // RHP snapshot taken on REPLACE; matching DISMISS must equal all three fields (key, | ||
| // routes depth, history depth) to commit the reveal freeze. | ||
| let pendingReveal: PendingReveal | null = null; | ||
|
|
||
| const getInitialState = (configOptions: RouterConfigOptions) => { | ||
| const state = router.getInitialState(configOptions); | ||
| return enhanceStateWithHistory(state); | ||
|
|
@@ -35,7 +41,6 @@ function addRootHistoryRouterExtension<RouterOptions extends PlatformStackRouter | |
| const state = router.getRehydratedState(partialState, configOptions); | ||
| const stateWithInitialHistory = enhanceStateWithHistory(state); | ||
|
|
||
| // Preserve trailing side-panel sentinel through state rebuilds. | ||
| if (state.history?.at(-1) === CONST.NAVIGATION.CUSTOM_HISTORY_ENTRY_SIDE_PANEL) { | ||
| stateWithInitialHistory.history = [...stateWithInitialHistory.history, CONST.NAVIGATION.CUSTOM_HISTORY_ENTRY_SIDE_PANEL]; | ||
| return stateWithInitialHistory; | ||
|
|
@@ -44,56 +49,24 @@ function addRootHistoryRouterExtension<RouterOptions extends PlatformStackRouter | |
| return stateWithInitialHistory; | ||
| }; | ||
|
|
||
| // Centralizes the `PartialState | FullState` cast to `getRehydratedState`'s input shape. | ||
| function rehydrate(newState: PartialState<RootHistoryState> | RootHistoryState, configOptions: RouterConfigOptions) { | ||
| return getRehydratedState(newState as PartialState<RootHistoryState>, configOptions); | ||
| } | ||
|
|
||
| const getStateForAction = (state: RootHistoryState, action: RootStackNavigatorAction, configOptions: RouterConfigOptions) => { | ||
| // Snapshot is stale if its RHP key vanished via a non-DISMISS path. | ||
| if (pendingReveal && !state.routes.some((r) => r.key === pendingReveal?.rhpKey)) { | ||
| Log.hmmm('[addRootHistoryRouterExtension] pending reveal RHP no longer in routes; clearing snapshot', {pendingReveal}); | ||
| pendingReveal = null; | ||
| } | ||
|
|
||
| const getStateForAction = (state: PlatformStackNavigationState<ParamListBase>, action: CommonActions.Action | StackActionType, configOptions: RouterConfigOptions) => { | ||
| const newState = router.getStateForAction(state, action, configOptions); | ||
|
|
||
| if (!newState) { | ||
| return null; | ||
| } | ||
|
|
||
| // REPLACE: capture pending reveal + freeze history (intermediate frame; useLinking historyDelta=0). | ||
| if (isReplaceFullscreenUnderRHPAction(action)) { | ||
| const result = getFrozenHistoryStateForReplaceFullscreenUnderRHP(state, newState, configOptions, pendingReveal, rehydrate); | ||
| pendingReveal = result.pendingReveal; | ||
| return result.state; | ||
| } | ||
|
|
||
| // REMOVE: cancel path; clear snapshot + freeze history (same rationale as REPLACE). | ||
| if (isRemoveFullscreenUnderRHPAction(action)) { | ||
| const result = getFrozenHistoryStateForRemoveFullscreenUnderRHP(state, newState, configOptions, rehydrate); | ||
| if (state.history) { | ||
| pendingReveal = null; | ||
| } | ||
| return result; | ||
| } | ||
|
|
||
| // DISMISS that completes the reveal: pad new history to pre-DISMISS length so | ||
| // useLinking sees historyDelta=0 and just `history.replace`s the current entry, | ||
| // preserving the prior fullscreen browser entry. (RN 7.x useLinking semantics.) | ||
| if (isDismissModalAction(action) && pendingReveal && state.history) { | ||
| const result = getRevealDismissState(state, newState, configOptions, pendingReveal, rehydrate); | ||
| pendingReveal = result.pendingReveal; | ||
| if (result.state) { | ||
| return result.state; | ||
| } | ||
| // For REPLACE/REMOVE_FULLSCREEN_UNDER_RHP we intentionally preserve the original | ||
| // history array so that useLinking sees historyDelta=0 and does NOT push/pop any | ||
| // browser history entries for these intermediate state changes. | ||
| if ((isReplaceFullscreenUnderRHPAction(action) || isRemoveFullscreenUnderRHPAction(action)) && state.history) { | ||
| // @ts-expect-error newState can be partial but getRehydratedState handles it correctly. | ||
| const rehydrated = getRehydratedState(newState, configOptions); | ||
| return {...rehydrated, history: state.history}; | ||
| } | ||
|
|
||
| // Default: re-apply the offset (single source of truth = leading sentinels in | ||
| // state.history). addPushParamsRouterExtension keeps all string entries, so | ||
| // reveal-padding sentinels survive PUSH_PARAMS / GO_BACK / POP / RESET dispatches. | ||
| const rehydrated = rehydrate(newState, configOptions); | ||
| return applyRevealPaddingOffset(state, rehydrated); | ||
| // @ts-expect-error newState may be partial, but getRehydratedState handles both partial and full states correctly. | ||
| return getRehydratedState(newState, configOptions); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| }; | ||
|
|
||
| return { | ||
|
|
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For tab-target reveals, spreading
rkeeps any existingparams.screen/params.paramsdeep-link hints on the tab route when the new focused tab has no params. If the tab was previously hydrated from a deep link, React Navigation will process those stale params after mount and issue a nested navigate that can override the freshly splicedstate, so revealing a workspace/search tab under an RHP can land back on the old nested screen instead of the requested route.Useful? React with 👍 / 👎.