import React, { useCallback, useMemo, useRef, useState } from 'react'; import { View, Text, TextInput, Pressable } from 'react-native'; import { FlashList } from '@shopify/flash-list'; import BottomSheet, { BottomSheetBackdrop, BottomSheetView } from '@gorhom/bottom-sheet'; import Svg, { Path } from 'react-native-svg'; import type { SearchableEntity, SearchResult } from '../types/algorand'; import { searchEntities } from '../utils/search'; function SearchIcon({ size = 16, color = '#a1a1aa' }: { size?: number; color?: string }) { return ( ); } interface SearchSheetProps { data: T[]; placeholder?: string; onSelect?: (item: T) => void; renderItem: (item: T) => React.ReactElement; className?: string; } export function SearchSheet({ data, placeholder = 'Search...', onSelect, renderItem, className, }: SearchSheetProps) { const sheetRef = useRef(null); const [query, setQuery] = useState(''); const [isOpen, setIsOpen] = useState(false); const snapPoints = useMemo(() => ['50%', '80%'], []); const results = useMemo(() => { if (!query.trim()) { return data.slice(0, 10).map((item) => ({ item, score: 1, matches: [] as string[] })); } return searchEntities(data, query, 10); }, [data, query]); const handleOpen = useCallback(() => { setIsOpen(true); sheetRef.current?.snapToIndex(0); }, []); const handleSelect = useCallback( (item: T) => { onSelect?.(item); setQuery(''); sheetRef.current?.close(); }, [onSelect], ); const renderBackdrop = useCallback( (props: React.ComponentProps) => ( ), [], ); const renderResultItem = useCallback( ({ item }: { item: SearchResult }) => ( handleSelect(item.item)} className="px-4 py-3 border-b border-zinc-800" > {renderItem(item.item)} ), [handleSelect, renderItem], ); return ( {/* Search Trigger Button */} {placeholder} {/* Bottom Sheet */} { if (index === -1) setIsOpen(false); }} > {/* Search Input */} {/* Results */} `search-${index}`} ListEmptyComponent={ {query.trim() ? 'No results found.' : 'No items available.'} } /> ); }