@@ -34,6 +34,7 @@ import type {
34
34
DocSearchModalProps ,
35
35
StoredDocSearchHit ,
36
36
DocSearchTransformClient ,
37
+ DocSearchHit ,
37
38
} from '@docsearch/react' ;
38
39
39
40
import type { AutocompleteState } from '@algolia/autocomplete-core' ;
@@ -50,6 +51,85 @@ type DocSearchProps = Omit<
50
51
51
52
let DocSearchModal : typeof DocSearchModalType | null = null ;
52
53
54
+ function importDocSearchModalIfNeeded ( ) {
55
+ if ( DocSearchModal ) {
56
+ return Promise . resolve ( ) ;
57
+ }
58
+ return Promise . all ( [
59
+ import ( '@docsearch/react/modal' ) as Promise <
60
+ typeof import ( '@docsearch/react' )
61
+ > ,
62
+ import ( '@docsearch/react/style' ) ,
63
+ import ( './styles.css' ) ,
64
+ ] ) . then ( ( [ { DocSearchModal : Modal } ] ) => {
65
+ DocSearchModal = Modal ;
66
+ } ) ;
67
+ }
68
+
69
+ function useNavigator ( {
70
+ externalUrlRegex,
71
+ } : Pick < DocSearchProps , 'externalUrlRegex' > ) {
72
+ const history = useHistory ( ) ;
73
+ const [ navigator ] = useState < DocSearchModalProps [ 'navigator' ] > ( ( ) => {
74
+ return {
75
+ navigate ( params ) {
76
+ // Algolia results could contain URL's from other domains which cannot
77
+ // be served through history and should navigate with window.location
78
+ if ( isRegexpStringMatch ( externalUrlRegex , params . itemUrl ) ) {
79
+ window . location . href = params . itemUrl ;
80
+ } else {
81
+ history . push ( params . itemUrl ) ;
82
+ }
83
+ } ,
84
+ } ;
85
+ } ) ;
86
+ return navigator ;
87
+ }
88
+
89
+ function useTransformSearchClient ( ) : DocSearchModalProps [ 'transformSearchClient' ] {
90
+ const {
91
+ siteMetadata : { docusaurusVersion} ,
92
+ } = useDocusaurusContext ( ) ;
93
+ return useCallback (
94
+ ( searchClient : DocSearchTransformClient ) => {
95
+ searchClient . addAlgoliaAgent ( 'docusaurus' , docusaurusVersion ) ;
96
+ return searchClient ;
97
+ } ,
98
+ [ docusaurusVersion ] ,
99
+ ) ;
100
+ }
101
+
102
+ function useTransformItems ( props : Pick < DocSearchProps , 'transformItems' > ) {
103
+ const processSearchResultUrl = useSearchResultUrlProcessor ( ) ;
104
+ const [ transformItems ] = useState < DocSearchModalProps [ 'transformItems' ] > (
105
+ ( ) => {
106
+ return ( items : DocSearchHit [ ] ) =>
107
+ props . transformItems
108
+ ? // Custom transformItems
109
+ props . transformItems ( items )
110
+ : // Default transformItems
111
+ items . map ( ( item ) => ( {
112
+ ...item ,
113
+ url : processSearchResultUrl ( item . url ) ,
114
+ } ) ) ;
115
+ } ,
116
+ ) ;
117
+ return transformItems ;
118
+ }
119
+
120
+ function useResultsFooterComponent ( {
121
+ closeModal,
122
+ } : {
123
+ closeModal : ( ) => void ;
124
+ } ) : DocSearchProps [ 'resultsFooterComponent' ] {
125
+ return useMemo (
126
+ ( ) =>
127
+ ( { state} ) =>
128
+ < ResultsFooter state = { state } onClose = { closeModal } /> ,
129
+ [ closeModal ] ,
130
+ ) ;
131
+ }
132
+
53
133
function Hit ( {
54
134
hit,
55
135
children,
@@ -79,19 +159,15 @@ function ResultsFooter({state, onClose}: ResultsFooterProps) {
79
159
) ;
80
160
}
81
161
82
- function mergeFacetFilters ( f1 : FacetFilters , f2 : FacetFilters ) : FacetFilters {
83
- const normalize = ( f : FacetFilters ) : FacetFilters =>
84
- typeof f === 'string' ? [ f ] : f ;
85
- return [ ...normalize ( f1 ) , ...normalize ( f2 ) ] ;
86
- }
87
-
88
- function DocSearch ( {
162
+ function useSearchParameters ( {
89
163
contextualSearch,
90
- externalUrlRegex,
91
164
...props
92
- } : DocSearchProps ) {
93
- const { siteMetadata} = useDocusaurusContext ( ) ;
94
- const processSearchResultUrl = useSearchResultUrlProcessor ( ) ;
165
+ } : DocSearchProps ) : DocSearchProps [ 'searchParameters' ] {
166
+ function mergeFacetFilters ( f1 : FacetFilters , f2 : FacetFilters ) : FacetFilters {
167
+ const normalize = ( f : FacetFilters ) : FacetFilters =>
168
+ typeof f === 'string' ? [ f ] : f ;
169
+ return [ ...normalize ( f1 ) , ...normalize ( f2 ) ] ;
170
+ }
95
171
96
172
const contextualSearchFacetFilters =
97
173
useAlgoliaContextualFacetFilters ( ) as FacetFilters ;
@@ -105,37 +181,27 @@ function DocSearch({
105
181
: // ... or use config facetFilters
106
182
configFacetFilters ;
107
183
108
- // We let user override default searchParameters if she wants to
109
- const searchParameters : DocSearchProps [ 'searchParameters' ] = {
184
+ // We let users override default searchParameters if they want to
185
+ return {
110
186
...props . searchParameters ,
111
187
facetFilters,
112
188
} ;
189
+ }
190
+
191
+ function DocSearch ( { externalUrlRegex, ...props } : DocSearchProps ) {
192
+ const navigator = useNavigator ( { externalUrlRegex} ) ;
193
+ const searchParameters = useSearchParameters ( { ...props } ) ;
194
+ const transformItems = useTransformItems ( props ) ;
195
+ const transformSearchClient = useTransformSearchClient ( ) ;
113
196
114
- const history = useHistory ( ) ;
115
197
const searchContainer = useRef < HTMLDivElement | null > ( null ) ;
116
- // TODO remove after React 19 upgrade?
198
+ // TODO remove "as any" after React 19 upgrade
117
199
const searchButtonRef = useRef < HTMLButtonElement > ( null as any ) ;
118
200
const [ isOpen , setIsOpen ] = useState ( false ) ;
119
201
const [ initialQuery , setInitialQuery ] = useState < string | undefined > (
120
202
undefined ,
121
203
) ;
122
204
123
- const importDocSearchModalIfNeeded = useCallback ( ( ) => {
124
- if ( DocSearchModal ) {
125
- return Promise . resolve ( ) ;
126
- }
127
-
128
- return Promise . all ( [
129
- import ( '@docsearch/react/modal' ) as Promise <
130
- typeof import ( '@docsearch/react' )
131
- > ,
132
- import ( '@docsearch/react/style' ) ,
133
- import ( './styles.css' ) ,
134
- ] ) . then ( ( [ { DocSearchModal : Modal } ] ) => {
135
- DocSearchModal = Modal ;
136
- } ) ;
137
- } , [ ] ) ;
138
-
139
205
const prepareSearchContainer = useCallback ( ( ) => {
140
206
if ( ! searchContainer . current ) {
141
207
const divElement = document . createElement ( 'div' ) ;
@@ -147,7 +213,7 @@ function DocSearch({
147
213
const openModal = useCallback ( ( ) => {
148
214
prepareSearchContainer ( ) ;
149
215
importDocSearchModalIfNeeded ( ) . then ( ( ) => setIsOpen ( true ) ) ;
150
- } , [ importDocSearchModalIfNeeded , prepareSearchContainer ] ) ;
216
+ } , [ prepareSearchContainer ] ) ;
151
217
152
218
const closeModal = useCallback ( ( ) => {
153
219
setIsOpen ( false ) ;
@@ -169,51 +235,7 @@ function DocSearch({
169
235
[ openModal ] ,
170
236
) ;
171
237
172
- const navigator = useRef ( {
173
- navigate ( { itemUrl} : { itemUrl ?: string } ) {
174
- // Algolia results could contain URL's from other domains which cannot
175
- // be served through history and should navigate with window.location
176
- if ( isRegexpStringMatch ( externalUrlRegex , itemUrl ) ) {
177
- window . location . href = itemUrl ! ;
178
- } else {
179
- history . push ( itemUrl ! ) ;
180
- }
181
- } ,
182
- } ) . current ;
183
-
184
- const transformItems = useRef < DocSearchModalProps [ 'transformItems' ] > (
185
- ( items ) =>
186
- props . transformItems
187
- ? // Custom transformItems
188
- props . transformItems ( items )
189
- : // Default transformItems
190
- items . map ( ( item ) => ( {
191
- ...item ,
192
- url : processSearchResultUrl ( item . url ) ,
193
- } ) ) ,
194
- ) . current ;
195
-
196
- // @ts -expect-error: TODO fix lib issue after React 19, using JSX.Element
197
- const resultsFooterComponent : DocSearchProps [ 'resultsFooterComponent' ] =
198
- useMemo (
199
- ( ) =>
200
- // eslint-disable-next-line react/no-unstable-nested-components
201
- ( footerProps : Omit < ResultsFooterProps , 'onClose' > ) : ReactNode =>
202
- < ResultsFooter { ...footerProps } onClose = { closeModal } /> ,
203
- [ closeModal ] ,
204
- ) ;
205
-
206
- const transformSearchClient = useCallback (
207
- ( searchClient : DocSearchTransformClient ) => {
208
- searchClient . addAlgoliaAgent (
209
- 'docusaurus' ,
210
- siteMetadata . docusaurusVersion ,
211
- ) ;
212
-
213
- return searchClient ;
214
- } ,
215
- [ siteMetadata . docusaurusVersion ] ,
216
- ) ;
238
+ const resultsFooterComponent = useResultsFooterComponent ( { closeModal} ) ;
217
239
218
240
useDocSearchKeyboardEvents ( {
219
241
isOpen,
0 commit comments