diff --git a/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.js b/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.js index 35151d8824..bba9aee8c5 100644 --- a/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.js +++ b/packages/docusaurus-theme-search-algolia/src/theme/SearchBar/index.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useRef, useCallback} from 'react'; +import React, {useState, useRef, useCallback} from 'react'; import classnames from 'classnames'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -13,10 +13,8 @@ import {useHistory} from '@docusaurus/router'; import './styles.css'; -let loaded = false; - const Search = props => { - const initialized = useRef(false); + const [algoliaLoaded, setAlgoliaLoaded] = useState(false); const searchBarRef = useRef(null); const {siteConfig = {}} = useDocusaurusContext(); const { @@ -24,63 +22,62 @@ const Search = props => { } = siteConfig; const history = useHistory(); - function initAlgolia(focusOnInit) { - if (!initialized.current) { - window.docsearch({ - appId: algolia.appId, - apiKey: algolia.apiKey, - indexName: algolia.indexName, - inputSelector: '#search_input_react', - algoliaOptions: algolia.algoliaOptions, - // Override algolia's default selection event, allowing us to do client-side - // navigation and avoiding a full page refresh. - handleSelected: (_input, _event, suggestion) => { - // Use an anchor tag to parse the absolute url into a relative url - // Alternatively, we can use new URL(suggestion.url) but its not supported in IE - const a = document.createElement('a'); - a.href = suggestion.url; + function initAlgolia() { + window.docsearch({ + appId: algolia.appId, + apiKey: algolia.apiKey, + indexName: algolia.indexName, + inputSelector: '#search_input_react', + algoliaOptions: algolia.algoliaOptions, + // Override algolia's default selection event, allowing us to do client-side + // navigation and avoiding a full page refresh. + handleSelected: (_input, _event, suggestion) => { + // Use an anchor tag to parse the absolute url into a relative url + // Alternatively, we can use new URL(suggestion.url) but its not supported in IE + const a = document.createElement('a'); + a.href = suggestion.url; - // Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id - // So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details. - const routePath = - `#__docusaurus` === a.hash - ? `${a.pathname}` - : `${a.pathname}${a.hash}`; - history.push(routePath); - }, - }); - initialized.current = true; - // Needed because the search input loses focus after calling window.docsearch() - if (focusOnInit) { - searchBarRef.current.focus(); - } - } + // Algolia use closest parent element id #__docusaurus when a h1 page title does not have an id + // So, we can safely remove it. See https://github.com/facebook/docusaurus/issues/1828 for more details. + const routePath = + `#__docusaurus` === a.hash + ? `${a.pathname}` + : `${a.pathname}${a.hash}`; + history.push(routePath); + }, + }); + + // Needed because the search input loses focus after calling window.docsearch() + searchBarRef.current.focus(); } - function loadAlgolia(focusAfterLoading) { - if (!loaded) { - Promise.all([import('docsearch.js'), import('./algolia.css')]).then( - ([{default: docsearch}]) => { - loaded = true; - window.docsearch = docsearch; - initAlgolia(focusAfterLoading); - }, - ); - } else { - initAlgolia(focusAfterLoading); + const loadAlgolia = () => { + if (algoliaLoaded) { + return; } - } - const toggleSearchIconClick = useCallback( - event => { - if (!searchBarRef.current.contains(event.target)) { - searchBarRef.current.focus(); - } + Promise.all([import('docsearch.js'), import('./algolia.css')]).then( + ([{default: docsearch}]) => { + setAlgoliaLoaded(true); + window.docsearch = docsearch; + initAlgolia(); + }, + ); + }; - props.handleSearchBarToggle(!props.isSearchBarExpanded); - }, - [props.isSearchBarExpanded], - ); + const toggleSearchIconClick = useCallback(() => { + loadAlgolia(); + + if (algoliaLoaded) { + searchBarRef.current.focus(); + } + + props.handleSearchBarToggle(!props.isSearchBarExpanded); + }, [props.isSearchBarExpanded]); + + const handleSearchInputBlur = useCallback(() => { + props.handleSearchBarToggle(!props.isSearchBarExpanded); + }, [algoliaLoaded]); return (
@@ -104,10 +101,9 @@ const Search = props => { {'search-bar-expanded': props.isSearchBarExpanded}, {'search-bar': !props.isSearchBarExpanded}, )} - onClick={loadAlgolia.bind(this, true)} - onMouseOver={loadAlgolia.bind(this, false)} - onFocus={toggleSearchIconClick} - onBlur={toggleSearchIconClick} + onMouseOver={loadAlgolia} + onFocus={loadAlgolia} + onBlur={handleSearchInputBlur} ref={searchBarRef} />