-
Notifications
You must be signed in to change notification settings - Fork 390
/
DocSearch.tsx
91 lines (79 loc) · 3.14 KB
/
DocSearch.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import type { AutocompleteState, AutocompleteOptions } from '@algolia/autocomplete-core';
import type { LiteClient, SearchParamsObject } from 'algoliasearch/lite';
import React from 'react';
import { createPortal } from 'react-dom';
import { DocSearchButton } from './DocSearchButton';
import { DocSearchModal } from './DocSearchModal';
import type { DocSearchHit, InternalDocSearchHit, StoredDocSearchHit } from './types';
import { useDocSearchKeyboardEvents } from './useDocSearchKeyboardEvents';
import type { ButtonTranslations, ModalTranslations } from '.';
export type DocSearchTranslations = Partial<{
button: ButtonTranslations;
modal: ModalTranslations;
}>;
// The interface that describes the minimal implementation required for the algoliasearch client, when using the [`transformSearchClient`](https://docsearch.algolia.com/docs/api/#transformsearchclient) option.
export type DocSearchTransformClient = {
search: LiteClient['search'];
addAlgoliaAgent: LiteClient['addAlgoliaAgent'];
transporter: Pick<LiteClient['transporter'], 'algoliaAgent'>;
};
export interface DocSearchProps {
appId: string;
apiKey: string;
indexName: string;
placeholder?: string;
searchParameters?: SearchParamsObject;
maxResultsPerGroup?: number;
transformItems?: (items: DocSearchHit[]) => DocSearchHit[];
hitComponent?: (props: { hit: InternalDocSearchHit | StoredDocSearchHit; children: React.ReactNode }) => JSX.Element;
resultsFooterComponent?: (props: { state: AutocompleteState<InternalDocSearchHit> }) => JSX.Element | null;
transformSearchClient?: (searchClient: DocSearchTransformClient) => DocSearchTransformClient;
disableUserPersonalization?: boolean;
initialQuery?: string;
navigator?: AutocompleteOptions<InternalDocSearchHit>['navigator'];
translations?: DocSearchTranslations;
getMissingResultsUrl?: ({ query }: { query: string }) => string;
insights?: AutocompleteOptions<InternalDocSearchHit>['insights'];
}
export function DocSearch(props: DocSearchProps): JSX.Element {
const searchButtonRef = React.useRef<HTMLButtonElement>(null);
const [isOpen, setIsOpen] = React.useState(false);
const [initialQuery, setInitialQuery] = React.useState<string | undefined>(props?.initialQuery || undefined);
const onOpen = React.useCallback(() => {
setIsOpen(true);
}, [setIsOpen]);
const onClose = React.useCallback(() => {
setIsOpen(false);
setInitialQuery(props?.initialQuery);
}, [setIsOpen, props.initialQuery]);
const onInput = React.useCallback(
(event: KeyboardEvent) => {
setIsOpen(true);
setInitialQuery(event.key);
},
[setIsOpen, setInitialQuery],
);
useDocSearchKeyboardEvents({
isOpen,
onOpen,
onClose,
onInput,
searchButtonRef,
});
return (
<>
<DocSearchButton ref={searchButtonRef} translations={props?.translations?.button} onClick={onOpen} />
{isOpen &&
createPortal(
<DocSearchModal
{...props}
initialScrollY={window.scrollY}
initialQuery={initialQuery}
translations={props?.translations?.modal}
onClose={onClose}
/>,
document.body,
)}
</>
);
}