diff --git a/src/components/Search/SearchList/index.tsx b/src/components/Search/SearchList/index.tsx index db4dfa18f065..bff474935cf4 100644 --- a/src/components/Search/SearchList/index.tsx +++ b/src/components/Search/SearchList/index.tsx @@ -3,10 +3,11 @@ import {isUserValidatedSelector} from '@selectors/Account'; import {accountIDSelector} from '@selectors/Session'; import {tierNameSelector} from '@selectors/UserWallet'; import type {FlashListProps, FlashListRef, ViewToken} from '@shopify/flash-list'; -import React, {useCallback, useContext, useImperativeHandle, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useContext, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState} from 'react'; import type {ForwardedRef} from 'react'; import {View} from 'react-native'; -import type {NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; +// eslint-disable-next-line no-restricted-imports +import type {NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView, StyleProp, ViewStyle} from 'react-native'; import Animated, {Easing, FadeOutUp, LinearTransition} from 'react-native-reanimated'; import Checkbox from '@components/Checkbox'; import * as Expensicons from '@components/Icon/Expensicons'; @@ -51,6 +52,9 @@ import BaseSearchList from './BaseSearchList'; const easing = Easing.bezier(0.76, 0.0, 0.24, 1.0); +// Keep a ref to the horizontal scroll offset so we can restore it if users change the search query +let savedHorizontalScrollOffset = 0; + type SearchListItem = TransactionListItemType | TransactionGroupListItemType | ReportActionListItemType | TaskListItemType; type SearchListItemComponentType = typeof TransactionListItem | typeof ChatListItem | typeof TransactionGroupListItem | typeof TaskListItem; @@ -233,6 +237,20 @@ function SearchList({ const minTableWidth = getTableMinWidth(columns); const shouldScrollHorizontally = !!SearchTableHeader && minTableWidth > windowWidth; + const horizontalScrollViewRef = useRef(null); + + const handleHorizontalScroll = useCallback((event: NativeSyntheticEvent) => { + savedHorizontalScrollOffset = event.nativeEvent.contentOffset.x; + }, []); + + // Restore horizontal scroll position synchronously before paint using useLayoutEffect to avoid a visible shift on the table + useLayoutEffect(() => { + if (!shouldScrollHorizontally || savedHorizontalScrollOffset <= 0) { + return; + } + horizontalScrollViewRef.current?.scrollTo({x: savedHorizontalScrollOffset, animated: false}); + }, [data, shouldScrollHorizontally]); + const handleLongPressRow = useCallback( (item: SearchListItem, itemTransactions?: TransactionListItemType[]) => { const currentRoute = navigationRef.current?.getCurrentRoute(); @@ -452,10 +470,14 @@ function SearchList({ if (shouldScrollHorizontally) { return ( {content}