docusaurus/packages/docusaurus-theme-classic/src/theme/hooks/useHideableNavbar.js
2020-04-05 17:30:59 +03:00

94 lines
2.2 KiB
JavaScript

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useState, useCallback, useEffect} from 'react';
import {useLocation} from '@docusaurus/router';
import useLocationHash from '@theme/hooks/useLocationHash';
const useHideableNavbar = hideOnScroll => {
const [isNavbarVisible, setIsNavbarVisible] = useState(true);
const [isFocusedAnchor, setIsFocusedAnchor] = useState(false);
const [lastScrollTop, setLastScrollTop] = useState(0);
const [navbarHeight, setNavbarHeight] = useState(0);
const navbarRef = useCallback(node => {
if (node !== null) {
setNavbarHeight(node.getBoundingClientRect().height);
}
}, []);
const location = useLocation();
const [hash, setHash] = useLocationHash(location.hash);
const handleScroll = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
if (scrollTop === 0) {
setIsNavbarVisible(true);
}
if (scrollTop < navbarHeight) {
return;
}
if (isFocusedAnchor) {
setIsFocusedAnchor(false);
setIsNavbarVisible(false);
setLastScrollTop(scrollTop);
return;
}
const documentHeight = document.documentElement.scrollHeight - navbarHeight;
const windowHeight = window.innerHeight;
if (lastScrollTop && scrollTop >= lastScrollTop) {
setIsNavbarVisible(false);
} else if (scrollTop + windowHeight < documentHeight) {
setIsNavbarVisible(true);
}
setLastScrollTop(scrollTop);
};
useEffect(() => {
if (!hideOnScroll) {
return undefined;
}
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [lastScrollTop, navbarHeight]);
useEffect(() => {
if (!hideOnScroll) {
return;
}
setIsNavbarVisible(true);
setHash(location.hash);
}, [location]);
useEffect(() => {
if (!hideOnScroll) {
return;
}
if (!hash) {
return;
}
setIsFocusedAnchor(true);
}, [hash]);
return {
navbarRef,
isNavbarVisible,
};
};
export default useHideableNavbar;