Skip to content
Merged
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
1 change: 1 addition & 0 deletions src/components/Search/SearchMultipleSelectionPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ function SearchMultipleSelectionPicker<T extends string | string[]>({
sections={sections}
ListItem={MultiSelectListItem}
initiallyFocusedItemKey={initiallyFocusedKey}
shouldUpdateFocusedIndex
shouldClearInputOnSelect={false}
shouldShowTextInput={shouldShowTextInput}
textInputOptions={textInputOptions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
}
}
if (shouldUpdateFocusedIndex && typeof indexToFocus === 'number') {
if (indexToFocus !== focusedIndex) {
suppressNextFocusScrollRef.current = true;
}
setFocusedIndex(indexToFocus);
}
onSelectRow(item);
Expand Down Expand Up @@ -268,6 +271,10 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
setFocusedIndex,
});

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

useSearchFocusSync({
searchValue: textInputOptions?.value,
data: flattenedData,
Expand All @@ -277,7 +284,9 @@ function BaseSelectionListWithSections<TItem extends ListItem>({
shouldUpdateFocusedIndex,
scrollToIndex,
setFocusedIndex,
focusedIndex,
firstFocusableIndex,
suppressNextFocusScroll,
});

const textInputComponent = () => {
Expand Down
16 changes: 16 additions & 0 deletions src/components/SelectionList/hooks/useSearchFocusSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ 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 @@ -47,7 +53,9 @@ 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 @@ -72,6 +80,9 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({

if (foundSelectedItemIndex !== -1 && !canSelectMultiple) {
scrollToIndex(foundSelectedItemIndex, false);
if (foundSelectedItemIndex !== focusedIndex) {
suppressNextFocusScroll?.();
}
setFocusedIndex(foundSelectedItemIndex);
return;
}
Expand All @@ -91,6 +102,9 @@ 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 @@ -104,7 +118,9 @@ function useSearchFocusSync<TItem extends ListItem, TData = TItem>({
shouldUpdateFocusedIndex,
searchValue,
isItemSelected,
focusedIndex,
firstFocusableIndex,
suppressNextFocusScroll,
]);
}

Expand Down
Loading