1- import React , {
2- useCallback ,
3- useEffect ,
4- useMemo ,
5- useRef ,
6- useState ,
7- } from "react" ;
1+ import React , { useCallback , useMemo , useRef , useState } from "react" ;
82
93import { createPortal } from "react-dom" ;
104
11- import { useDocSearchKeyboardEvents } from "@docsearch/react" ;
5+ import { DocSearchButton , useDocSearchKeyboardEvents } from "@docsearch/react" ;
126import Head from "@docusaurus/Head" ;
137import Link from "@docusaurus/Link" ;
14- import Noop from "@docusaurus/Noop" ;
15- import Translate from "@docusaurus/Translate" ;
168import { useHistory } from "@docusaurus/router" ;
179import {
1810 isRegexpStringMatch ,
@@ -22,27 +14,21 @@ import {
2214 useAlgoliaContextualFacetFilters ,
2315 useSearchResultUrlProcessor ,
2416} from "@docusaurus/theme-search-algolia/client" ;
17+ import Translate from "@docusaurus/Translate" ;
2518import useDocusaurusContext from "@docusaurus/useDocusaurusContext" ;
2619
27- import type { SearchClient } from "algoliasearch/lite" ;
28-
29- import "./styles.css" ;
30-
31- import { useNonepressThemeConfig } from "@nullbot/docusaurus-theme-nonepress/client" ;
32-
33- import IconSearch from "@theme/Icon/Search" ;
3420import translations from "@theme/SearchTranslations" ;
3521
22+ import type { AutocompleteState } from "@algolia/autocomplete-core" ;
23+ import type {
24+ DocSearchModalProps ,
25+ DocSearchModal as DocSearchModalType ,
26+ } from "@docsearch/react" ;
3627import type {
3728 InternalDocSearchHit ,
3829 StoredDocSearchHit ,
3930} from "@docsearch/react/dist/esm/types" ;
40- import type {
41- DocSearchModal as DocSearchModalType ,
42- DocSearchModalProps ,
43- DocSearchButtonProps ,
44- } from "@docsearch/react" ;
45- import type { AutocompleteState } from "@algolia/autocomplete-core" ;
31+ import type { SearchClient } from "algoliasearch/lite" ;
4632
4733type DocSearchProps = Omit <
4834 DocSearchModalProps ,
@@ -97,54 +83,6 @@ function mergeFacetFilters(f1: FacetFilters, f2: FacetFilters): FacetFilters {
9783 return [ ...normalize ( f1 ) , ...normalize ( f2 ) ] as FacetFilters ;
9884}
9985
100- const ACTION_KEY_DEFAULT = "Ctrl" as const ;
101- const ACTION_KEY_APPLE = "⌘" as const ;
102-
103- function isAppleDevice ( ) : boolean {
104- return / M a c | i P h o n e | i P o d | i P a d / i. test ( navigator . platform ) ;
105- }
106-
107- const DocSearchButton = React . forwardRef <
108- HTMLButtonElement ,
109- DocSearchButtonProps
110- > ( ( { translations = { } , ...props } , ref ) => {
111- const { buttonText = "Search" , buttonAriaLabel = "Search" } = translations ;
112-
113- const [ key , setKey ] = useState <
114- typeof ACTION_KEY_APPLE | typeof ACTION_KEY_DEFAULT | null
115- > ( null ) ;
116-
117- useEffect ( ( ) => {
118- if ( typeof navigator !== "undefined" ) {
119- isAppleDevice ( ) ? setKey ( ACTION_KEY_APPLE ) : setKey ( ACTION_KEY_DEFAULT ) ;
120- }
121- } , [ ] ) ;
122-
123- return (
124- < button
125- type = "button"
126- className = "doc-search-btn"
127- aria-label = { buttonAriaLabel }
128- { ...props }
129- ref = { ref }
130- >
131- < span className = "doc-search-btn-container" >
132- < IconSearch className = "doc-search-btn-icon" />
133- < span className = "doc-search-btn-placeholder" > { buttonText } </ span >
134- </ span >
135-
136- < span className = "doc-search-btn-keys" >
137- { key !== null && (
138- < >
139- < kbd className = "kbd kbd-sm" > { key } </ kbd >
140- < kbd className = "kbd kbd-sm" > K</ kbd >
141- </ >
142- ) }
143- </ span >
144- </ button >
145- ) ;
146- } ) ;
147-
14886function DocSearch ( {
14987 contextualSearch,
15088 externalUrlRegex,
@@ -185,38 +123,46 @@ function DocSearch({
185123 }
186124
187125 return Promise . all ( [
188- import ( "@docsearch/react/dist/esm/DocSearchModal.js" ) ,
189- import ( "@docsearch/css/dist/_variables.css" ) ,
190- import ( "@docsearch/css/dist/modal.css" ) ,
126+ import ( "@docsearch/react/modal" ) as Promise <
127+ typeof import ( "@docsearch/react" )
128+ > ,
129+ import ( "@docsearch/react/style" ) ,
130+ import ( "./styles.css" ) ,
191131 ] ) . then ( ( [ { DocSearchModal : Modal } ] ) => {
192132 DocSearchModal = Modal ;
193133 } ) ;
194134 } , [ ] ) ;
195135
196- const onOpen = useCallback ( ( ) => {
197- importDocSearchModalIfNeeded ( ) . then ( ( ) => {
198- searchContainer . current = document . createElement ( "div" ) ;
199- document . body . insertBefore (
200- searchContainer . current ,
201- document . body . firstChild ,
202- ) ;
203- setIsOpen ( true ) ;
204- } ) ;
205- } , [ importDocSearchModalIfNeeded , setIsOpen ] ) ;
136+ const prepareSearchContainer = useCallback ( ( ) => {
137+ if ( ! searchContainer . current ) {
138+ const divElement = document . createElement ( "div" ) ;
139+ searchContainer . current = divElement ;
140+ document . body . insertBefore ( divElement , document . body . firstChild ) ;
141+ }
142+ } , [ ] ) ;
143+
144+ const openModal = useCallback ( ( ) => {
145+ prepareSearchContainer ( ) ;
146+ importDocSearchModalIfNeeded ( ) . then ( ( ) => setIsOpen ( true ) ) ;
147+ } , [ importDocSearchModalIfNeeded , prepareSearchContainer ] ) ;
206148
207- const onClose = useCallback ( ( ) => {
149+ const closeModal = useCallback ( ( ) => {
208150 setIsOpen ( false ) ;
209- searchContainer . current ?. remove ( ) ;
210- } , [ setIsOpen ] ) ;
151+ searchButtonRef . current ?. focus ( ) ;
152+ } , [ ] ) ;
211153
212- const onInput = useCallback (
154+ const handleInput = useCallback (
213155 ( event : KeyboardEvent ) => {
214- importDocSearchModalIfNeeded ( ) . then ( ( ) => {
215- setIsOpen ( true ) ;
216- setInitialQuery ( event . key ) ;
217- } ) ;
156+ if ( event . key === "f" && ( event . metaKey || event . ctrlKey ) ) {
157+ // ignore browser's ctrl+f
158+ return ;
159+ }
160+ // prevents duplicate key insertion in the modal input
161+ event . preventDefault ( ) ;
162+ setInitialQuery ( event . key ) ;
163+ openModal ( ) ;
218164 } ,
219- [ importDocSearchModalIfNeeded , setIsOpen , setInitialQuery ] ,
165+ [ openModal ] ,
220166 ) ;
221167
222168 const navigator = useRef ( {
@@ -246,10 +192,10 @@ function DocSearch({
246192 const resultsFooterComponent : DocSearchProps [ "resultsFooterComponent" ] =
247193 useMemo (
248194 ( ) =>
249-
195+ // eslint-disable-next-line react/no-unstable-nested-components
250196 ( footerProps : Omit < ResultsFooterProps , "onClose" > ) : JSX . Element =>
251- < ResultsFooter { ...footerProps } onClose = { onClose } /> ,
252- [ onClose ] ,
197+ < ResultsFooter { ...footerProps } onClose = { closeModal } /> ,
198+ [ closeModal ] ,
253199 ) ;
254200
255201 const transformSearchClient = useCallback (
@@ -266,9 +212,9 @@ function DocSearch({
266212
267213 useDocSearchKeyboardEvents ( {
268214 isOpen,
269- onOpen,
270- onClose,
271- onInput,
215+ onOpen : openModal ,
216+ onClose : closeModal ,
217+ onInput : handleInput ,
272218 searchButtonRef,
273219 } ) ;
274220
@@ -289,7 +235,7 @@ function DocSearch({
289235 onTouchStart = { importDocSearchModalIfNeeded }
290236 onFocus = { importDocSearchModalIfNeeded }
291237 onMouseOver = { importDocSearchModalIfNeeded }
292- onClick = { onOpen }
238+ onClick = { openModal }
293239 ref = { searchButtonRef }
294240 translations = { translations . button }
295241 />
@@ -299,7 +245,7 @@ function DocSearch({
299245 searchContainer . current &&
300246 createPortal (
301247 < DocSearchModal
302- onClose = { onClose }
248+ onClose = { closeModal }
303249 initialScrollY = { window . scrollY }
304250 initialQuery = { initialQuery }
305251 navigator = { navigator }
@@ -321,9 +267,6 @@ function DocSearch({
321267}
322268
323269export default function SearchBar ( ) : JSX . Element {
324- const { algolia } = useNonepressThemeConfig ( ) ;
325- if ( ! algolia ) {
326- return < Noop /> ;
327- }
328- return < DocSearch { ...( algolia as unknown as DocSearchProps ) } /> ;
270+ const { siteConfig } = useDocusaurusContext ( ) ;
271+ return < DocSearch { ...( siteConfig . themeConfig . algolia as DocSearchProps ) } /> ;
329272}
0 commit comments