Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 3 additions & 30 deletions src/components/SelectionList/BaseSelectionList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import useSingleExecution from '@hooks/useSingleExecution';
import {focusedItemRef} from '@hooks/useSyncFocus/useSyncFocusImplementation';
import useThemeStyles from '@hooks/useThemeStyles';
import {addKeyDownPressListener, removeKeyDownPressListener} from '@libs/KeyboardShortcut/KeyDownPressListener';
import {isFocusRestoreInProgress} from '@libs/NavigationFocusReturn';
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
import CONST from '@src/CONST';
import getEmptyArray from '@src/types/utils/getEmptyArray';
Expand Down Expand Up @@ -114,7 +113,6 @@ function BaseSelectionList<TItem extends ListItem>({
const listRef = useRef<FlashListRef<TItem> | null>(null);
const itemFocusTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const keyboardListenerRef = useRef<ReturnType<typeof Keyboard.addListener> | null>(null);
const suppressNextFocusScrollRef = useRef(false);

const initialFocusedIndex = useMemo(() => data.findIndex((i) => i.keyForList === initiallyFocusedItemKey), [data, initiallyFocusedItemKey]);
const [itemsToHighlight, setItemsToHighlight] = useState<Set<string> | null>(null);
Expand Down Expand Up @@ -219,12 +217,8 @@ function BaseSelectionList<TItem extends ListItem>({
maxIndex: data.length - 1,
disabledIndexes: dataDetails.disabledArrowKeyIndexes,
isActive: isFocused,
onFocusedIndexChange: (index: number) => {
if (suppressNextFocusScrollRef.current) {
suppressNextFocusScrollRef.current = false;
return;
}
if (!shouldScrollToFocusedIndex) {
onFocusedIndexChange: (index, shouldScrollHint) => {
if (!shouldScrollHint || !shouldScrollToFocusedIndex) {
return;
}

Expand All @@ -238,17 +232,6 @@ function BaseSelectionList<TItem extends ListItem>({
},
});

// Keep the cursor on the restored row so keyboard nav continues from there, but don't scroll to it on the way back.
const setFocusedIndexFromRowFocus = useCallback(
(index: number) => {
if (isFocusRestoreInProgress() && index !== focusedIndex) {
suppressNextFocusScrollRef.current = true;
}
setFocusedIndex(index);
},
[focusedIndex, setFocusedIndex],
);

// extraData helps FlashList detect when data changes significantly (e.g., during filtering)
// Including data.length ensures FlashList resets its layout cache when the list size changes
// This prevents "index out of bounds" errors when filtering reduces the list size
Expand All @@ -271,9 +254,6 @@ function BaseSelectionList<TItem extends ListItem>({
}
}
if (shouldUpdateFocusedIndex && typeof indexToFocus === 'number') {
if (indexToFocus !== focusedIndex) {
suppressNextFocusScrollRef.current = true;
}
setFocusedIndex(indexToFocus);
}
onSelectRow(item);
Expand All @@ -286,7 +266,6 @@ function BaseSelectionList<TItem extends ListItem>({
isFocused,
canSelectMultiple,
shouldUpdateFocusedIndex,
focusedIndex,
onSelectRow,
shouldShowTextInput,
shouldClearInputOnSelect,
Expand Down Expand Up @@ -396,7 +375,7 @@ function BaseSelectionList<TItem extends ListItem>({
isSelected: selected,
...item,
}}
setFocusedIndex={setFocusedIndexFromRowFocus}
setFocusedIndex={setFocusedIndex}
index={index}
isFocused={isItemFocused}
isFocusVisible={isItemVisuallyFocused}
Expand Down Expand Up @@ -557,10 +536,6 @@ function BaseSelectionList<TItem extends ListItem>({
setFocusedIndex,
});

const suppressNextFocusScroll = useCallback(() => {
suppressNextFocusScrollRef.current = true;
}, []);

useSearchFocusSync({
searchValue: syncedSearchValue,
data,
Expand All @@ -570,8 +545,6 @@ function BaseSelectionList<TItem extends ListItem>({
shouldUpdateFocusedIndex,
scrollToIndex,
setFocusedIndex,
focusedIndex,
suppressNextFocusScroll,
});

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {focusedItemRef} from '@hooks/useSyncFocus/useSyncFocusImplementation';
import useThemeStyles from '@hooks/useThemeStyles';
import {addKeyDownPressListener, removeKeyDownPressListener} from '@libs/KeyboardShortcut/KeyDownPressListener';
import Log from '@libs/Log';
import {isFocusRestoreInProgress} from '@libs/NavigationFocusReturn';
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
import CONST from '@src/CONST';
import type {FlattenedItem, ListItem, SelectionListWithSectionsProps} from './types';
Expand Down Expand Up @@ -95,7 +94,6 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
const isTextInputFocusedRef = useRef<boolean>(false);
const hasKeyBeenPressed = useRef(false);
const [isKeyboardNavigating, setIsKeyboardNavigating] = useState(false);
const suppressNextFocusScrollRef = useRef(false);
const activeElementRole = useActiveElementRole();
const {isKeyboardShown} = useKeyboardState();
const {safeAreaPaddingBottomStyle} = useSafeAreaPaddings();
Expand Down Expand Up @@ -151,9 +149,8 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
maxIndex: flattenedData.length - 1,
disabledIndexes,
isActive: isScreenFocused && itemsCount > 0,
onFocusedIndexChange: (index: number) => {
if (suppressNextFocusScrollRef.current) {
suppressNextFocusScrollRef.current = false;
onFocusedIndexChange: (index, shouldScrollHint) => {
if (!shouldScrollHint) {
return;
}
if (!shouldScrollToFocusedIndex) {
Expand All @@ -170,23 +167,6 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
},
});

// Move the cursor, and skip the scroll the move would otherwise trigger when the index actually changes.
const setFocusedIndexWithoutScrollOnChange = (index: number) => {
if (index !== focusedIndex) {
suppressNextFocusScrollRef.current = true;
}
setFocusedIndex(index);
};

// Keep the cursor on the restored row so keyboard nav continues from there, but don't scroll to it on the way back.
const setFocusedIndexFromRowFocus = (index: number) => {
if (isFocusRestoreInProgress()) {
setFocusedIndexWithoutScrollOnChange(index);
} else {
setFocusedIndex(index);
}
};

const getFocusedItem = (): TItem | undefined => {
if (focusedIndex < 0 || focusedIndex >= flattenedData.length) {
return;
Expand All @@ -212,7 +192,7 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
}
}
if (shouldUpdateFocusedIndex && typeof indexToFocus === 'number') {
setFocusedIndexWithoutScrollOnChange(indexToFocus);
setFocusedIndex(indexToFocus);
}
onSelectRow(item);

Expand All @@ -238,9 +218,6 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
};

const updateAndScrollToFocusedIndex = (index: number, shouldScroll = true) => {
if (!shouldScroll) {
suppressNextFocusScrollRef.current = true;
}
setFocusedIndex(index);
if (shouldScroll) {
scrollToIndex(index);
Expand Down Expand Up @@ -312,10 +289,6 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
setFocusedIndex,
});

const suppressNextFocusScroll = () => {
suppressNextFocusScrollRef.current = true;
};

useSearchFocusSync({
searchValue: syncedSearchValue,
data: flattenedData,
Expand All @@ -325,9 +298,7 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
shouldUpdateFocusedIndex,
scrollToIndex,
setFocusedIndex,
focusedIndex,
firstFocusableIndex,
suppressNextFocusScroll,
});

const textInputComponent = () => {
Expand Down Expand Up @@ -402,7 +373,7 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
shouldSingleExecuteRowSelect={shouldSingleExecuteRowSelect}
onDismissError={onDismissError}
rightHandSideComponent={rightHandSideComponent}
setFocusedIndex={setFocusedIndexFromRowFocus}
setFocusedIndex={setFocusedIndex}
singleExecution={singleExecution}
shouldSyncFocus={!isTextInputFocusedRef.current && isKeyboardNavigating}
shouldIgnoreFocus={shouldIgnoreFocus}
Expand Down
16 changes: 0 additions & 16 deletions src/components/SelectionList/hooks/useSearchFocusSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,8 @@ type UseSearchFocusSyncParams<TItem extends ListItem, TData = TItem> = {
/** Function to set the focused index */
setFocusedIndex: (index: number) => void;

/** The current focused index — needed to avoid arming scroll suppression when the index won't actually change */
focusedIndex?: number;

/** The first focusable index in the list (useful when index 0 is a header). Defaults to 0. */
firstFocusableIndex?: number;

/** Optional callback to suppress the scroll that onFocusedIndexChange would otherwise trigger when setFocusedIndex is called */
suppressNextFocusScroll?: () => void;
};

/**
Expand All @@ -53,9 +47,7 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({
shouldUpdateFocusedIndex,
scrollToIndex,
setFocusedIndex,
focusedIndex,
firstFocusableIndex = 0,
suppressNextFocusScroll,
}: UseSearchFocusSyncParams<TItem, TData>) {
const prevSearchValue = usePrevious(searchValue);
const prevSelectedOptionsCount = usePrevious(selectedOptionsCount);
Expand All @@ -80,9 +72,6 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({

if (foundSelectedItemIndex !== -1 && !canSelectMultiple) {
scrollToIndex(foundSelectedItemIndex, false);
if (foundSelectedItemIndex !== focusedIndex) {
suppressNextFocusScroll?.();
}
setFocusedIndex(foundSelectedItemIndex);
return;
}
Expand All @@ -102,9 +91,6 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({

// Scroll to top of list and focus on first focusable item (not header)
scrollToIndex(0, false);
if (firstFocusableIndex !== focusedIndex) {
suppressNextFocusScroll?.();
}
setFocusedIndex(firstFocusableIndex);
}, [
canSelectMultiple,
Expand All @@ -118,9 +104,7 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({
shouldUpdateFocusedIndex,
searchValue,
isItemSelected,
focusedIndex,
firstFocusableIndex,
suppressNextFocusScroll,
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type UseSelectedItemFocusSyncParams<TItem extends ListItem, TData = TItem> = {
searchValue: string | undefined;

/** Function to set the focused index */
setFocusedIndex: (index: number) => void;
setFocusedIndex: (index: number, shouldScrollHint?: boolean) => void;
};

/**
Expand All @@ -39,7 +39,7 @@ function useSelectedItemFocusSync<TItem extends ListItem, TData = TItem>({
if (selectedItemIndex === -1 || selectedItemIndex === focusedIndex || searchValue) {
return;
}
setFocusedIndex(selectedItemIndex);
setFocusedIndex(selectedItemIndex, true);

// Only sync focus when selectedItemIndex changes, not when other dependencies update
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand Down
Loading
Loading