diff --git a/packages/spotlight/src/components/actions/group-actions.tsx b/packages/spotlight/src/components/actions/group-actions.tsx index f8516deff..cce1cc8a8 100644 --- a/packages/spotlight/src/components/actions/group-actions.tsx +++ b/packages/spotlight/src/components/actions/group-actions.tsx @@ -15,6 +15,18 @@ interface GroupActionsProps> { setChildrenOptions: (options: inferSearchInteractionOptions<"children">) => void; } +const getUniqueOptions = >(options: TOption[], keyPath: keyof TOption) => { + const optionKeys = new Set(); + + return options.filter((option) => { + const optionKey = option[keyPath]; + if (optionKeys.has(optionKey)) return false; + + optionKeys.add(optionKey); + return true; + }); +}; + export const SpotlightGroupActions = >({ group, query, @@ -33,7 +45,7 @@ export const SpotlightGroupActions = >({ return null; } - const filteredOptions = options + const filteredOptions = getUniqueOptions(options, group.keyPath) .filter((option) => ("filter" in group ? group.filter(query, option) : false)) .sort((optionA, optionB) => { if ("sort" in group) { @@ -80,7 +92,7 @@ export const SpotlightGroupActions = >({ return null; } - return options.data.map((option) => ( + return getUniqueOptions(options.data, group.keyPath).map((option) => ( { }); }, []); - const items = useMemo(() => Array.from(itemsMap.values()).flatMap(({ items }) => items), [itemsMap]); + const items = useMemo(() => { + const uniqueItems: ContextSpecificItem[] = []; + const itemKeys = new Set(); + + for (const registration of itemsMap.values()) { + for (const item of registration.items) { + const itemKey = item.dedupeKey ?? item.id; + if (itemKeys.has(itemKey)) continue; + + itemKeys.add(itemKey); + uniqueItems.push(item); + } + } + + return uniqueItems; + }, [itemsMap]); const itemsContext = useMemo(() => ({ items }), [items]); const registration = useMemo(() => ({ registerItems, unregisterItems }), [registerItems, unregisterItems]);