-
-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathDocSearch.tsx
More file actions
101 lines (90 loc) · 2.88 KB
/
DocSearch.tsx
File metadata and controls
101 lines (90 loc) · 2.88 KB
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
92
93
94
95
96
97
98
99
100
101
import type {
AutocompleteState,
AutocompleteOptions,
} from '@algolia/autocomplete-core';
import React from 'react';
import { createPortal } from 'react-dom';
import type { SearchClient } from 'typesense';
import type { ConfigurationOptions as TypesenseConfigurationOptions } from 'typesense/lib/Typesense/Configuration';
import type { SearchParams as TypesenseSearchParams } from 'typesense/lib/Typesense/Documents';
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;
}>;
export interface DocSearchProps {
typesenseCollectionName: string;
typesenseServerConfig: TypesenseConfigurationOptions;
typesenseSearchParameters: TypesenseSearchParams;
placeholder?: string;
transformItems?: (items: DocSearchHit[]) => DocSearchHit[];
hitComponent?: (props: {
hit: InternalDocSearchHit | StoredDocSearchHit;
children: React.ReactNode;
}) => JSX.Element;
resultsFooterComponent?: (props: {
state: AutocompleteState<InternalDocSearchHit>;
}) => JSX.Element | null;
transformSearchClient?: (searchClient: SearchClient) => SearchClient;
disableUserPersonalization?: boolean;
initialQuery?: string;
navigator?: AutocompleteOptions<InternalDocSearchHit>['navigator'];
translations?: DocSearchTranslations;
getMissingResultsUrl?: ({ query }: { query: string }) => string;
matomoSearchAnalytics?: boolean;
}
export function DocSearch(props: DocSearchProps) {
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);
}, [setIsOpen]);
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
)}
</>
);
}