({
initialQuery: initialQueryProp,
autoFocus = true,
placeholder,
onSubmitQuery,
className,
suggestionType = 'searchPostSuggestions',
onFocus,
onClearQuery,
enableSuggestions = true,
}: PostsSearchProps)
| 53 | } & Pick<HTMLAttributes<HTMLInputElement>, 'onFocus'>; |
| 54 | |
| 55 | export default function PostsSearch({ |
| 56 | initialQuery: initialQueryProp, |
| 57 | autoFocus = true, |
| 58 | placeholder, |
| 59 | onSubmitQuery, |
| 60 | className, |
| 61 | suggestionType = 'searchPostSuggestions', |
| 62 | onFocus, |
| 63 | onClearQuery, |
| 64 | enableSuggestions = true, |
| 65 | }: PostsSearchProps): ReactElement { |
| 66 | const { time, contentCurationFilter } = useSearchContextProvider(); |
| 67 | const { user } = useAuthContext(); |
| 68 | const searchBoxRef = useRef<HTMLDivElement>(null); |
| 69 | const [query, setQuery] = useState<string>(); |
| 70 | const [items, setItems] = useState<string[]>([]); |
| 71 | const { value: searchVersion } = useConditionalFeature({ |
| 72 | feature: feature.searchVersion, |
| 73 | shouldEvaluate: |
| 74 | !!query && |
| 75 | suggestionType === 'searchPostSuggestions' && |
| 76 | enableSuggestions, |
| 77 | }); |
| 78 | const SEARCH_URL = SEARCH_TYPES[suggestionType]; |
| 79 | const purify = useDomPurify(); |
| 80 | const [isFocused, setIsFocused] = useState(false); |
| 81 | const initialQuery = useRef<string>(initialQueryProp || ''); |
| 82 | // `query` only catches up after the suggestion debounce, so submitting has to |
| 83 | // read the raw input value or an early Enter would search for nothing. |
| 84 | const typedQuery = useRef<string>(initialQueryProp || ''); |
| 85 | |
| 86 | const { data: searchResults, isPending } = useQuery<{ |
| 87 | [suggestionType: string]: { hits: { title: string }[] }; |
| 88 | }>({ |
| 89 | // Bookmark and reading-history suggestions are private per user. |
| 90 | queryKey: generateQueryKey(RequestKey.Search, user, suggestionType, query), |
| 91 | queryFn: () => |
| 92 | gqlClient.request(SEARCH_URL, { query, version: searchVersion }), |
| 93 | enabled: !!query && enableSuggestions, |
| 94 | staleTime: StaleTime.Default, |
| 95 | }); |
| 96 | |
| 97 | useEffect(() => { |
| 98 | if (!isPending) { |
| 99 | setItems( |
| 100 | searchResults?.[suggestionType]?.hits.map((hit) => |
| 101 | purify?.sanitize?.(hit.title), |
| 102 | ) ?? [], |
| 103 | ); |
| 104 | } |
| 105 | }, [searchResults, isPending, suggestionType, purify]); |
| 106 | |
| 107 | const submitQuery = async (item?: string) => { |
| 108 | const itemQuery = item?.replace?.(sanitizeSearchTitleMatch, ''); |
| 109 | await onSubmitQuery(itemQuery || typedQuery.current || '', { |
| 110 | filters: { |
| 111 | time: time.toString(), |
| 112 | contentCuration: contentCurationFilter, |
nothing calls this directly
no test coverage detected