From e22170408a5b4b885ba30db76c64977e77a13d44 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 15 Oct 2021 14:07:03 +0300 Subject: [PATCH] refactor: cleanup scroll handlers (#5709) --- .../src/theme/BackToTopButton/index.tsx | 81 +++++++++++-------- .../src/theme/hooks/useHideableNavbar.ts | 79 +++++++----------- .../src/utils/useLocationChange.ts | 9 +-- 3 files changed, 77 insertions(+), 92 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx b/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx index feba4f36ea..1b88c9ed62 100644 --- a/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BackToTopButton/index.tsx @@ -7,11 +7,14 @@ import React, {useRef, useState} from 'react'; import clsx from 'clsx'; -import {useLocation} from '@docusaurus/router'; import {translate} from '@docusaurus/Translate'; import styles from './styles.module.css'; -import {ThemeClassNames, useScrollPosition} from '@docusaurus/theme-common'; +import { + ThemeClassNames, + useScrollPosition, + useLocationChange, +} from '@docusaurus/theme-common'; const threshold = 300; @@ -68,42 +71,52 @@ function useSmoothScrollToTop(): UseSmoothScrollTopReturn { } function BackToTopButton(): JSX.Element { - const location = useLocation(); - const {smoothScrollTop, cancelScrollToTop} = useSmoothScrollToTop(); const [show, setShow] = useState(false); + const isFocusedAnchor = useRef(false); + const {smoothScrollTop, cancelScrollToTop} = useSmoothScrollToTop(); - useScrollPosition( - ({scrollY: scrollTop}, lastPosition) => { - // No lastPosition means component is just being mounted. - // Not really a scroll event from the user, so we ignore it - if (!lastPosition) { - return; + useScrollPosition(({scrollY: scrollTop}, lastPosition) => { + const lastScrollTop = lastPosition?.scrollY; + + // No lastScrollTop means component is just being mounted. + // Not really a scroll event from the user, so we ignore it + if (!lastScrollTop) { + return; + } + + if (isFocusedAnchor.current) { + isFocusedAnchor.current = false; + return; + } + + const isScrollingUp = scrollTop < lastScrollTop; + + if (!isScrollingUp) { + cancelScrollToTop(); + } + + if (scrollTop < threshold) { + setShow(false); + return; + } + + if (isScrollingUp) { + const documentHeight = document.documentElement.scrollHeight; + const windowHeight = window.innerHeight; + if (scrollTop + windowHeight < documentHeight) { + setShow(true); } - const lastScrollTop = lastPosition.scrollY; + } else { + setShow(false); + } + }); - const isScrollingUp = scrollTop < lastScrollTop; - - if (!isScrollingUp) { - cancelScrollToTop(); - } - - if (scrollTop < threshold) { - setShow(false); - return; - } - - if (isScrollingUp) { - const documentHeight = document.documentElement.scrollHeight; - const windowHeight = window.innerHeight; - if (scrollTop + windowHeight < documentHeight) { - setShow(true); - } - } else { - setShow(false); - } - }, - [location], - ); + useLocationChange((locationChangeEvent) => { + if (locationChangeEvent.location.hash) { + isFocusedAnchor.current = true; + setShow(false); + } + }); return (