Skip to content

Commit bde955d

Browse files
fix(ui): keyboard nav on picker
1 parent 7496abb commit bde955d

File tree

1 file changed

+38
-6
lines changed
  • invokeai/frontend/web/src/common/components/Picker

1 file changed

+38
-6
lines changed

invokeai/frontend/web/src/common/components/Picker/Picker.tsx

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ import { useStore } from '@nanostores/react';
1414
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
1515
import { typedMemo } from 'common/util/typedMemo';
1616
import { NO_DRAG_CLASS, NO_WHEEL_CLASS } from 'features/nodes/types/constants';
17-
import type { ReadableAtom, WritableAtom } from 'nanostores';
17+
import type { AnyStore, ReadableAtom, Task, WritableAtom } from 'nanostores';
1818
import { atom, computed } from 'nanostores';
19+
import type { StoreValues } from 'nanostores/computed';
1920
import type { ChangeEvent, PropsWithChildren, RefObject } from 'react';
2021
import React, {
2122
createContext,
@@ -614,20 +615,41 @@ export const Picker = typedMemo(<T extends object>(props: PickerProps<T>) => {
614615
Picker.displayName = 'Picker';
615616

616617
const PickerSyncer = typedMemo(<T extends object>() => {
617-
const { optionsOrGroups, $searchTerm, $activeOptionId, $filteredOptions, searchable, isMatch, getOptionId } =
618-
usePickerContext();
618+
const {
619+
optionsOrGroups,
620+
$searchTerm,
621+
$activeOptionId,
622+
$groupStatusMap,
623+
$areAllGroupsDisabled,
624+
$filteredOptions,
625+
searchable,
626+
isMatch,
627+
getOptionId,
628+
} = usePickerContext<T>();
619629
const searchTerm = useStore($searchTerm);
630+
const groupStatusMap = useStore($groupStatusMap);
631+
const areAllGroupsDisabled = useStore($areAllGroupsDisabled);
620632
const [debouncedSearchTerm] = useDebounce(searchTerm, 300);
621633

622634
useEffect(() => {
623635
if (!debouncedSearchTerm || !searchable) {
624-
$filteredOptions.set(optionsOrGroups);
625-
$activeOptionId.set(getFirstOptionId(optionsOrGroups, getOptionId));
636+
const filtered = optionsOrGroups.filter((item) => {
637+
if (isGroup(item)) {
638+
return groupStatusMap[item.id] || areAllGroupsDisabled;
639+
} else {
640+
return true;
641+
}
642+
});
643+
$filteredOptions.set(filtered as T[] | Group<T>[]);
644+
$activeOptionId.set(getFirstOptionId(filtered as T[] | Group<T>[], getOptionId));
626645
} else {
627646
const lowercasedSearchTerm = debouncedSearchTerm.toLowerCase();
628647
const filtered = [];
629648
for (const item of optionsOrGroups) {
630649
if (isGroup(item)) {
650+
if (!groupStatusMap[item.id] && !areAllGroupsDisabled) {
651+
continue;
652+
}
631653
const filteredItems = item.options.filter((item) => isMatch(item, lowercasedSearchTerm));
632654
if (filteredItems.length > 0) {
633655
filtered.push({ ...item, options: filteredItems });
@@ -641,7 +663,17 @@ const PickerSyncer = typedMemo(<T extends object>() => {
641663
$filteredOptions.set(filtered as T[] | Group<T>[]);
642664
$activeOptionId.set(getFirstOptionId(filtered as T[] | Group<T>[], getOptionId));
643665
}
644-
}, [debouncedSearchTerm, $activeOptionId, getOptionId, isMatch, $filteredOptions, searchable, optionsOrGroups]);
666+
}, [
667+
debouncedSearchTerm,
668+
$activeOptionId,
669+
getOptionId,
670+
isMatch,
671+
$filteredOptions,
672+
searchable,
673+
optionsOrGroups,
674+
groupStatusMap,
675+
areAllGroupsDisabled,
676+
]);
645677

646678
return null;
647679
});

0 commit comments

Comments
 (0)