Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
57a0673
refactor: harden the new-transaction highlight rail and consolidate i…
TaduJR Jul 15, 2026
5b2d4f9
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Jul 16, 2026
6333557
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Jul 31, 2026
a2522ea
fix: new-transaction highlight edge cases and narrow WideRHP subscrip…
TaduJR Jul 31, 2026
61a3e95
refactor: scope the rail deletion guard per report and release it whe…
TaduJR Jul 31, 2026
9b3e869
fix: identify rail flags by stamp so a sweep clears only what it sche…
TaduJR Aug 1, 2026
79d7f6a
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 1, 2026
9576399
fix: key rail flags by instance so clearing one cannot race a re-flag
TaduJR Aug 1, 2026
dc3da32
refactor: derive the visible RHP keys instead of syncing them by hand
TaduJR Aug 2, 2026
a5fdb3c
fix: slice the RHP stack by route order, not by extracted key order
TaduJR Aug 2, 2026
ed70220
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 2, 2026
58a2bfe
fix: identify what a window latched, and hold a dismissing RHP's width
TaduJR Aug 2, 2026
513945a
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 4, 2026
fda9ced
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 7, 2026
8d40cbc
fix: hold a dismissing screen's width, and cover the hooks jest could…
TaduJR Aug 7, 2026
7b780ff
fix: bound a width hint's life again, and stop the pulse hopping twice
TaduJR Aug 7, 2026
dc6ecbe
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 16, 2026
a51d871
fix: keep a highlight through a re-sort, and stop notifying on every …
TaduJR Aug 16, 2026
11d01fc
fix: make the settled latch follow the loaded flag, not snapshot it
TaduJR Aug 16, 2026
71b330f
test: give the 1→2 rail test a report the expense can be added to
TaduJR Aug 17, 2026
1d40ac7
fix: release the width floor once the caller reaches it
TaduJR Aug 17, 2026
ff6925c
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 20, 2026
f7469fd
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 22, 2026
0273340
fix: drop a pulse whose highlight was retracted mid-entry
TaduJR Aug 23, 2026
46ca584
test: decode stamped flag keys in the split-move-out assertions
TaduJR Aug 23, 2026
99f51cd
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 24, 2026
08c4054
fix: keep a dismissing RHP's width when a covered RHP is still in state
TaduJR Aug 24, 2026
a8eea47
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 26, 2026
bee4bd8
fix: correct width holding, selector identity and highlight windows
TaduJR Aug 26, 2026
6e47542
fix: track seen RHP route keys in state so the compiler can see them …
TaduJR Aug 26, 2026
35ac48d
fix: reveal a row whose play was dropped, and narrow three over-broad…
TaduJR Aug 26, 2026
348ee16
refactor: share the report-visibility predicate between both rail con…
TaduJR Aug 26, 2026
a3cce3d
fix: tell an RHP beside this tab from one over another
TaduJR Aug 26, 2026
e59bea3
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 26, 2026
3bf3970
fix: compare list lengths, and claim a tab only when focused
TaduJR Aug 26, 2026
4741b61
chore: spell three coinages the dictionary rejects
TaduJR Aug 27, 2026
b9b7e5b
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 27, 2026
82326ff
fix: treat a report list hydrating from empty as a load, not adds
TaduJR Aug 27, 2026
84acbef
test: assert the offline rail by flag key, not by bare transaction ID
TaduJR Aug 27, 2026
66c5a2a
docs: say why the sweep timer is uncancelled
TaduJR Aug 27, 2026
3913447
docs: correct what the freshness window actually samples
TaduJR Aug 27, 2026
18cca0b
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Aug 28, 2026
c4f95cf
docs: say that the narrow flag already carries RHP membership
TaduJR Aug 28, 2026
dfb0a6d
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 1, 2026
5d73fd1
refactor: use the repo's own focus hook in useIsReportVisible
TaduJR Sep 1, 2026
3ece13e
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 1, 2026
f8af331
chore: docs
TaduJR Sep 1, 2026
fb00786
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 1, 2026
1c45061
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 2, 2026
03e450a
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 3, 2026
b4482da
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 8, 2026
b5b5f3f
fix: add the required wide-RHP field to main's new perf test context
TaduJR Sep 8, 2026
f10d174
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 8, 2026
beb2721
Merge branch 'main' of https://github.com/TaduJR/App into refactor-Re…
TaduJR Sep 8, 2026
a8c6c1d
docs: say the visible screen is assumed to be the pane beside the RHP
TaduJR Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ const decorators = [
SearchContextProvider,
]}
>
<ScreenWrapperStatusContext.Provider value={{didScreenTransitionEnd: true, isSafeAreaTopPaddingApplied: false, isSafeAreaBottomPaddingApplied: false}}>
<ScreenWrapperStatusContext.Provider
value={{didScreenTransitionEnd: true, shouldUseNarrowLayoutOnWideRHP: false, isSafeAreaTopPaddingApplied: false, isSafeAreaBottomPaddingApplied: false}}
>
<Story />
</ScreenWrapperStatusContext.Provider>
</ComposeProviders>
Expand Down
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ const CONST = {
BACKGROUND_IMAGE_TRANSITION_DURATION: 1000,
SCREEN_TRANSITION_END_TIMEOUT: 1000,
PENDING_TRANSACTION_DELETION_DELAY: 4000,
PENDING_TRANSACTION_FRESHNESS_WINDOW: 60000,
PENDING_TRANSACTION_SCROLL_DELAY: 1000,

// Delay before pre-inserting the Search fullscreen route under the RHP on the confirmation screen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import useAppFocusEvent from '@hooks/useAppFocusEvent';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import {useIsReportLoadPending} from '@hooks/useInFlightRequests';
import useIsReportActionsLoaded from '@hooks/useIsReportActionsLoaded';
import useIsReportVisible from '@hooks/useIsReportVisible';
import useLoadReportActions from '@hooks/useLoadReportActions';
import useLocalize from '@hooks/useLocalize';
import useNetworkWithOfflineStatus from '@hooks/useNetworkWithOfflineStatus';
Expand Down Expand Up @@ -124,8 +125,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
const [isVisible, setIsVisible] = useState(Visibility.isVisible);
const isFocused = useIsFocused();
const {shouldUseNarrowLayout} = useResponsiveLayoutOnWideRHP();
// The table is visible whenever it's wide, or — on narrow — only when focused (the RHP has closed).
const isReportVisible = shouldUseNarrowLayout ? isFocused : true;
const isReportVisible = useIsReportVisible(shouldUseNarrowLayout);
const route = useRoute<PlatformStackRouteProp<ReportsSplitNavigatorParamList, typeof SCREENS.REPORT>>();
const reportIDFromRoute = route?.params?.reportID;
const isReportLoadPending = useIsReportLoadPending(reportIDFromRoute);
Expand Down Expand Up @@ -158,7 +158,7 @@ function MoneyRequestReportActionsList({onLayout}: MoneyRequestReportListProps)
const [pendingNewTransactionIDs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {
selector: pendingNewTransactionIDsSelector,
});
const newTransactions = useNewTransactions(reportLoadingState?.hasOnceLoadedReportActions, reportTransactions, pendingNewTransactionIDs, reportIDFromRoute, isFocused);
const newTransactions = useNewTransactions(reportLoadingState?.hasOnceLoadedReportActions, reportTransactions, pendingNewTransactionIDs, reportIDFromRoute, isReportVisible);
Comment thread
TaduJR marked this conversation as resolved.
const showReportActionsLoadingState = reportLoadingState?.isLoadingInitialReportActions && !reportLoadingState?.hasOnceLoadedReportActions;
const isInitialReportLoadPending = !isOffline && isReportLoadPending && !reportLoadingState?.hasOnceLoadedReportActions;
const reportTransactionIDs = useMemo(() => transactions.map((transaction) => transaction.transactionID), [transactions]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import TransactionPreview from '@components/ReportActionItem/TransactionPreview'
import {useWideRHPActions} from '@components/WideRHPContextProvider';

import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useIsReportVisible from '@hooks/useIsReportVisible';
import useNetwork from '@hooks/useNetwork';
import useNewTransactions from '@hooks/useNewTransactions';
import useOnyx from '@hooks/useOnyx';
import usePolicy from '@hooks/usePolicy';
import useReportTransactionsCollection from '@hooks/useReportTransactionsCollection';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useTransactionViolations from '@hooks/useTransactionViolations';
Expand Down Expand Up @@ -69,9 +70,10 @@ function MoneyRequestReportPreview({
}: MoneyRequestReportPreviewProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {shouldUseNarrowLayout, isSmallScreenWidth} = useResponsiveLayout();
const {shouldUseNarrowLayoutIgnoringWideRHP, isSmallScreenWidth} = useResponsiveLayoutOnWideRHP();
const {markReportRHPWidth, unmarkReportRHPWidth} = useWideRHPActions();
// Deferred presses need focus, which is narrower than the visibility the highlight below is gated on.
const isFocused = useIsFocused();
const personalDetailsList = usePersonalDetails();
const {email: currentUserEmail, accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
Expand Down Expand Up @@ -153,8 +155,8 @@ function MoneyRequestReportPreview({
);

const reportPreviewStyles = useMemo(
() => StyleUtils.getMoneyRequestReportPreviewStyle(shouldUseNarrowLayout, transactions.length, widths.currentWidth, widths.currentWrapperWidth),
[StyleUtils, widths, shouldUseNarrowLayout, transactions.length],
() => StyleUtils.getMoneyRequestReportPreviewStyle(shouldUseNarrowLayoutIgnoringWideRHP, transactions.length, widths.currentWidth, widths.currentWrapperWidth),
[StyleUtils, widths, shouldUseNarrowLayoutIgnoringWideRHP, transactions.length],
);
const shouldShowPayerAndReceiver = useMemo(() => {
if (!isIOUReport(iouReport) && action.childType !== CONST.REPORT.TYPE.IOU) {
Expand Down Expand Up @@ -207,7 +209,6 @@ function MoneyRequestReportPreview({
const [pendingNewTransactionIDs] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${chatReportID}`, {
selector: pendingNewTransactionIDsSelector,
});
const isFocused = useIsFocused();
// Transactions arrive in batches and `useNewTransactions` would diff each batch as newly added expenses.
// Withhold the list until every transaction the report claims has arrived.
const expectedTransactionCount = iouReport?.transactionCount ?? 0;
Expand All @@ -220,9 +221,10 @@ function MoneyRequestReportPreview({
setHasCompletedDelivery(true);
}
const transactionsForDiff = isDeliveryComplete || hasCompletedDelivery ? transactions : undefined;
const newTransactions = useNewTransactions(hasOnceLoadedReportActions, transactionsForDiff, pendingNewTransactionIDs, chatReportID, isFocused);
// Don't surface the highlight while the preview is covered — it'd animate the one-shot off-screen and be missed.
const isReportVisible = shouldUseNarrowLayout ? isFocused : true;
// A modal pane can be covered at any width, so this reads the flag unadjusted for wide RHP.
const isReportVisible = useIsReportVisible(shouldUseNarrowLayoutIgnoringWideRHP);
const newTransactions = useNewTransactions(hasOnceLoadedReportActions, transactionsForDiff, pendingNewTransactionIDs, chatReportID, isReportVisible);
const newTransactionIDs = new Set(isReportVisible ? newTransactions.map((transaction) => transaction.transactionID) : []);

const transactionPreviewContainerStyles = [styles.h100, reportPreviewStyles.transactionPreviewCarouselStyle];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {createContext} from 'react';

type ScreenWrapperStatusContextType = {
didScreenTransitionEnd: boolean;
shouldUseNarrowLayoutOnWideRHP: boolean;
isSafeAreaTopPaddingApplied: boolean;
isSafeAreaBottomPaddingApplied: boolean;
};
Expand Down
11 changes: 5 additions & 6 deletions src/components/ScreenWrapper/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import useAccessibilityFocus from '@hooks/useAccessibilityFocus';
import useEnvironment from '@hooks/useEnvironment';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useResponsiveLayoutOnWideRHP from '@hooks/useResponsiveLayoutOnWideRHP';
import useSafeAreaPaddings from '@hooks/useSafeAreaPaddings';
import useThemeStyles from '@hooks/useThemeStyles';

Expand Down Expand Up @@ -127,8 +127,7 @@ function ScreenWrapper({
const mergedScreenWrapperRef = mergeRefs(screenWrapperRef, ref);

// We need to use isSmallScreenWidth instead of shouldUseNarrowLayout for a case where we want to show the offline indicator only on small screens
// eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth
const {isSmallScreenWidth, shouldUseNarrowLayout} = useResponsiveLayout();
const {isSmallScreenWidth, shouldUseNarrowLayoutIgnoringWideRHP, shouldUseNarrowLayout: shouldUseNarrowLayoutOnWideRHP} = useResponsiveLayoutOnWideRHP();

const styles = useThemeStyles();
const {isDevelopment} = useEnvironment();
Expand All @@ -147,14 +146,14 @@ function ScreenWrapper({
const includeSafeAreaPaddingBottom = isUsingEdgeToEdgeMode ? false : includeSafeAreaPaddingBottomProp;
const isSafeAreaTopPaddingApplied = includePaddingTop;
const statusContextValue = useMemo(
() => ({didScreenTransitionEnd, isSafeAreaTopPaddingApplied, isSafeAreaBottomPaddingApplied: includeSafeAreaPaddingBottom}),
[didScreenTransitionEnd, includeSafeAreaPaddingBottom, isSafeAreaTopPaddingApplied],
() => ({didScreenTransitionEnd, shouldUseNarrowLayoutOnWideRHP, isSafeAreaTopPaddingApplied, isSafeAreaBottomPaddingApplied: includeSafeAreaPaddingBottom}),
[didScreenTransitionEnd, shouldUseNarrowLayoutOnWideRHP, includeSafeAreaPaddingBottom, isSafeAreaTopPaddingApplied],
);

// This context allows us to disable the safe area padding offsetting the offline indicator in scrollable components like 'ScrollView', 'SelectionList' or 'FormProvider'.
// This is useful e.g. for the RightModalNavigator, where we want to avoid the safe area padding offsetting the offline indicator because we only show the offline indicator on small screens.
const {isInNarrowPane} = useContext(NarrowPaneContext);
const isMobileWebNarrowLayout = getPlatform() === CONST.PLATFORM.WEB && isMobile() && shouldUseNarrowLayout;
const isMobileWebNarrowLayout = getPlatform() === CONST.PLATFORM.WEB && isMobile() && shouldUseNarrowLayoutIgnoringWideRHP;
const shouldMoveAccessibilityFocus = isMobileWebNarrowLayout && isInNarrowPane;
const shouldHideFromAccessibility = isMobileWebNarrowLayout && !isFocused;
const {addSafeAreaPadding, showOnSmallScreens, showOnWideScreens} = useContext(ScreenWrapperOfflineIndicatorContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,12 @@ function TransactionGroupListExpandedImpl({
});
return;
}
markReportRHPWidth(reportID, 'wide');
const route = ROUTES.SEARCH_REPORT.getRoute({reportID, backTo});
// Marked after the new-tab guard: opening in a new tab never mounts the screen that would consume the hint, so it would pin this report wide on a later visit.
if (openInternalRouteInNewTab(route, event)) {
return;
}
markReportRHPWidth(reportID, 'wide');
Navigation.navigate(route);
};

Expand Down
17 changes: 9 additions & 8 deletions src/components/Search/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,6 @@ function Search({
}
}

if (item.transactions.length > 1) {
markReportRHPWidth(reportID, 'super-wide');
} else {
unmarkReportRHPWidth(reportID, 'super-wide');
}

// Persist the current search context so prev/next navigation arrows
// in the report RHP can reference the correct result set.
saveLastSearchParams({
Expand All @@ -693,9 +687,17 @@ function Search({
reportID,
backTo,
});
if (item.transactions.length <= 1) {
// A report that no longer qualifies must not keep the hint an earlier visit left behind, whether or not this click navigates.
unmarkReportRHPWidth(reportID, 'super-wide');
}
// Marked after the new-tab guard: opening in a new tab never mounts the screen that would consume the hint, so it would pin this report wide on a later visit.
if (openInternalRouteInNewTab(route, event)) {
return;
}
if (item.transactions.length > 1) {
markReportRHPWidth(reportID, 'super-wide');
}
requestAnimationFrame(() => Navigation.navigate(route));
return;
}
Expand Down Expand Up @@ -728,8 +730,6 @@ function Search({
return;
}

markReportRHPWidth(reportID, 'wide');

if (isTransactionItem && transactionPreviewData) {
setOptimisticDataForTransactionThreadPreview(transactionItem, transactionPreviewData, getCurrencyDecimals, transactionItem?.reportAction?.childReportID);
}
Expand All @@ -738,6 +738,7 @@ function Search({
if (openInternalRouteInNewTab(route, event)) {
return;
}
markReportRHPWidth(reportID, 'wide');
requestAnimationFrame(() => Navigation.navigate(route));
},
[
Expand Down
4 changes: 0 additions & 4 deletions src/components/WideRHPContextProvider/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ const defaultWideRHPActionsContextValue: WideRHPActionsContextType = {
markReportRHPWidth: () => {},
unmarkReportRHPWidth: () => {},
getReportRHPWidthHint: () => undefined,
syncRHPKeys: () => {},
clearWideRHPKeys: () => {},
setIsWideRHPClosing: () => {},
setIsSuperWideRHPClosing: () => {},
};

export {defaultWideRHPStateContextValue, defaultWideRHPActionsContextValue};
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import getVisibleRHPKeys from './getVisibleRHPRouteKeys';

// Helper function to determine if wide or super wide RHP is displayed below the currently focused route
export default function getIsRHPDisplayedBelow(focusedRouteKey: string | undefined, allSuperWideRHPRouteKeys: string[], allWideRHPRouteKeys: string[]) {
const {visibleSuperWideRHPRouteKeys, visibleWideRHPRouteKeys} = getVisibleRHPKeys(allSuperWideRHPRouteKeys, allWideRHPRouteKeys);

export default function getIsRHPDisplayedBelow(focusedRouteKey: string | undefined, visibleSuperWideRHPRouteKeys: string[], visibleWideRHPRouteKeys: string[]) {
if (!focusedRouteKey) {
return {
isWideRHPBelow: false,
Expand Down
59 changes: 30 additions & 29 deletions src/components/WideRHPContextProvider/getVisibleRHPRouteKeys.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,55 @@
import extractNavigationKeys from '@libs/Navigation/helpers/extractNavigationKeys';
import getLastVisibleRHPRouteKey from '@libs/Navigation/helpers/getLastVisibleRHPRouteKey';
import {navigationRef} from '@libs/Navigation/Navigation';

import type {NavigationState} from '@react-navigation/native';

type VisibleRHPKeys = {
visibleWideRHPRouteKeys: string[];
visibleSuperWideRHPRouteKeys: string[];
presentRouteKeys: string[];
};

const emptyRHPKeysState: VisibleRHPKeys = {
visibleWideRHPRouteKeys: [],
visibleSuperWideRHPRouteKeys: [],
presentRouteKeys: [],
};

/**
* Extracts the keys of the screens that are currently displayed from the array of all Wide/Super Wide RHP keys
*
* @param allWideRHPKeys - an array of all Wide/Super Wide RHP keys
* A key missing from the navigation state may be a screen dismissing or one that was never shown, and only the first
* holds a width. Callers must record `presentRouteKeys` so `seenRouteKeys` can tell those apart.
*/
function getVisibleRHPKeys(allSuperWideRHPKeys: string[], allWideRHPKeys: string[]): VisibleRHPKeys {
if (!navigationRef.isReady()) {
return emptyRHPKeysState;
}

const rootState = navigationRef.getRootState();
if (!rootState) {
function getVisibleRHPKeys(state: NavigationState | undefined, allWideRHPKeys: string[], allSuperWideRHPKeys: string[], seenRouteKeys: ReadonlySet<string>): VisibleRHPKeys {
// Nothing registered is the common case, and there is then no key to match the tree against.
if (!state || (!allWideRHPKeys.length && !allSuperWideRHPKeys.length)) {
return emptyRHPKeysState;
}

const lastVisibleRHPRouteKey = getLastVisibleRHPRouteKey(rootState);
const lastRHPRoute = rootState.routes.find((route) => route.key === lastVisibleRHPRouteKey);

if (!lastRHPRoute) {
return emptyRHPKeysState;
// A covered RHP needs no hand-clearing: this returns undefined for it, and its keys are still in the state below, so the displayed check rejects them too.
const lastVisibleRHPRouteKey = getLastVisibleRHPRouteKey(state);
const lastRHPRoute = state.routes.find((route) => route.key === lastVisibleRHPRouteKey);

let visibleRHPKeys = new Set<string>();
if (lastRHPRoute?.state?.routes) {
const superWideRHPIndex = lastRHPRoute.state.routes.findLastIndex((route) => route?.key && allSuperWideRHPKeys.includes(route.key));
const wideRHPIndex = lastRHPRoute.state.routes.findLastIndex((route) => route?.key && allWideRHPKeys.includes(route.key));

if (superWideRHPIndex > -1) {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state.routes.slice(superWideRHPIndex));
} else if (wideRHPIndex > -1) {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state.routes.slice(wideRHPIndex));
} else {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state.routes);
}
}

const superWideRHPIndex = lastRHPRoute.state?.routes.findLastIndex((route) => route?.key && allSuperWideRHPKeys.includes(route.key)) ?? -1;
const wideRHPIndex = lastRHPRoute.state?.routes.findLastIndex((route) => route?.key && allWideRHPKeys.includes(route.key)) ?? -1;

let visibleRHPKeys;
if (superWideRHPIndex > -1) {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state?.routes.slice(superWideRHPIndex));
} else if (wideRHPIndex > -1) {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state?.routes.slice(wideRHPIndex));
} else {
visibleRHPKeys = extractNavigationKeys(lastRHPRoute.state?.routes);
}
const keysInState = extractNavigationKeys(state.routes);
const isDisplayed = (key: string) => visibleRHPKeys.has(key) || (seenRouteKeys.has(key) && !keysInState.has(key));

return {
visibleWideRHPRouteKeys: allWideRHPKeys.filter((key) => visibleRHPKeys.has(key)),
visibleSuperWideRHPRouteKeys: allSuperWideRHPKeys.filter((key) => visibleRHPKeys.has(key)),
visibleWideRHPRouteKeys: allWideRHPKeys.filter(isDisplayed),
visibleSuperWideRHPRouteKeys: allSuperWideRHPKeys.filter(isDisplayed),
presentRouteKeys: [...allWideRHPKeys, ...allSuperWideRHPKeys].filter((key) => keysInState.has(key)),
};
}

Expand Down
Loading
Loading