fix(v2): fix input losing focus on init (#2188)

* fix(v2): fix input losing focus on init

* fix(v2): add onMouseOver handler
This commit is contained in:
Alexey Pyltsyn 2020-01-08 18:08:03 +03:00 committed by Yangshun Tay
parent 7e750de6fa
commit 5252111fa0

View file

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