diff --git a/apps/web/src/components/ui/search/SearchModal/SearchModalContent.stories.tsx b/apps/web/src/components/ui/search/SearchModal/SearchModalContent.stories.tsx index 836e490fc..2db207db5 100644 --- a/apps/web/src/components/ui/search/SearchModal/SearchModalContent.stories.tsx +++ b/apps/web/src/components/ui/search/SearchModal/SearchModalContent.stories.tsx @@ -31,6 +31,7 @@ const mockSearchItems: SearchItem[] = [ value: 'document-1', keywords: ['document', 'file', 'pdf'], type: 'item', + onSelect: fn(), }, { icon: '📊', @@ -39,6 +40,7 @@ const mockSearchItems: SearchItem[] = [ value: 'dashboard-1', keywords: ['dashboard', 'analytics', 'charts'], type: 'item', + onSelect: fn(), }, ...Array.from({ length: 10 }).map((_, index) => ({ icon: '📊', @@ -47,6 +49,7 @@ const mockSearchItems: SearchItem[] = [ value: `testing-${index}`, keywords: ['dashboard', 'analytics', 'charts'], type: 'item' as const, + onSelect: fn(), })), ]; diff --git a/apps/web/src/components/ui/search/SearchModal/SearchModalContent.tsx b/apps/web/src/components/ui/search/SearchModal/SearchModalContent.tsx index d2f350463..abd7177d3 100644 --- a/apps/web/src/components/ui/search/SearchModal/SearchModalContent.tsx +++ b/apps/web/src/components/ui/search/SearchModal/SearchModalContent.tsx @@ -4,7 +4,8 @@ import { SearchEmptyState } from './SearchEmptyState'; import { SearchFooter } from './SearchFooter'; import { SearchInput } from './SearchInput'; import { SearchModalContentItems } from './SearchModalContentItems'; -import type { SearchItem, SearchModalContentProps } from './search-modal.types'; +import type { SearchModalContentProps } from './search-modal.types'; +import { useViewSearchItem } from './useViewSearchItem'; export const SearchModalContent = ({ searchItems, @@ -20,6 +21,10 @@ export const SearchModalContent = ({ secondaryContent, openSecondaryContent, }: SearchModalContentProps) => { + const { handleKeyDown, focusedValue, setFocusedValue } = useViewSearchItem({ + searchItems, + onViewSearchItem, + }); const [searchValue, setSearchValue] = useState(defaulSearchValue); const onSearchChangePreflight = (searchValue: string) => { @@ -30,7 +35,9 @@ export const SearchModalContent = ({ return ( ({ value={value} disabled={disabled} onSelect={() => { + console.log('onSelect', value); onSelect?.(); }} > diff --git a/apps/web/src/components/ui/search/SearchModal/search-modal.types.ts b/apps/web/src/components/ui/search/SearchModal/search-modal.types.ts index 5a56ba907..9a0c5b91d 100644 --- a/apps/web/src/components/ui/search/SearchModal/search-modal.types.ts +++ b/apps/web/src/components/ui/search/SearchModal/search-modal.types.ts @@ -6,7 +6,7 @@ export type SearchItem = { value: T; keywords?: string[]; meta?: M; - onSelect?: () => void; + onSelect?: () => void; //should only be used for side effects loading?: boolean; disabled?: boolean; type: 'item'; @@ -33,7 +33,7 @@ export type SearchModalContentProps = { filterContent?: React.ReactNode; searchItems: SearchItems[]; onSearchChange: (searchValue: string) => void; - onSelect: (item: SearchItem) => void; + onSelect: (item: SearchItem, modifier: 'select' | 'navigate') => void; onViewSearchItem: (item: SearchItem) => void; emptyState?: React.ReactNode | string; placeholder?: string; diff --git a/apps/web/src/components/ui/search/SearchModal/useViewSearchItem.ts b/apps/web/src/components/ui/search/SearchModal/useViewSearchItem.ts new file mode 100644 index 000000000..d014ea50b --- /dev/null +++ b/apps/web/src/components/ui/search/SearchModal/useViewSearchItem.ts @@ -0,0 +1,45 @@ +import { useState } from 'react'; +import type { SearchItem, SearchItems } from './search-modal.types'; + +export const useViewSearchItem = ({ + searchItems, + onViewSearchItem, +}: { + searchItems: SearchItems[]; + onViewSearchItem: (item: SearchItem) => void; +}) => { + const [focusedValue, setFocusedValue] = useState(''); + + const handleKeyDown = (e: React.KeyboardEvent) => { + if ((e.key === 'ArrowDown' || e.key === 'ArrowUp') && onViewSearchItem) { + // Wait for next tick to get updated focusedValue + setTimeout(() => { + if (!focusedValue) return; + + const findItem = (items: typeof searchItems): SearchItem | null => { + for (const item of items) { + if (item.type === 'item' && item.value === focusedValue) { + return item; + } + if (item.type === 'group') { + const found = findItem(item.items); + if (found) return found; + } + } + return null; + }; + + const item = findItem(searchItems); + if (item) { + onViewSearchItem(item); + } + }, 0); + } + }; + + return { + handleKeyDown, + focusedValue, + setFocusedValue, + }; +};