feat: on back navigation, close mobile sidebar (#5462)

* On back, close mobile navbar sidebar

* more reliable code to block history pop events

* android backbutton: just close the drawer without cancellin the backward navigation
This commit is contained in:
Sébastien Lorber 2021-09-02 16:03:17 +02:00 committed by GitHub
parent 6b7f3e8553
commit f361e89b14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 0 deletions

View file

@ -15,6 +15,7 @@ import {
useThemeConfig,
useMobileSecondaryMenuRenderer,
usePrevious,
useHistoryPopHandler,
} from '@docusaurus/theme-common';
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
@ -58,6 +59,18 @@ function useMobileSidebar() {
const [shown, setShown] = useState(false);
// Close mobile sidebar on navigation pop
// Most likely firing when using the Android back button (but not only)
useHistoryPopHandler(() => {
if (shown) {
setShown(false);
// Should we prevent the navigation here?
// See https://github.com/facebook/docusaurus/pull/5462#issuecomment-911699846
// return false; // prevent pop navigation
}
return undefined;
});
const toggle = useCallback(() => {
setShown((s) => !s);
}, []);

View file

@ -71,3 +71,5 @@ export {useLocalPathname} from './utils/useLocalPathname';
export {translateTagsPageTitle, listTagsByLetters} from './utils/tagsUtils';
export type {TagLetterEntry} from './utils/tagsUtils';
export {useHistoryPopHandler} from './utils/historyUtils';

View file

@ -0,0 +1,50 @@
/**
* 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 {useEffect, useRef} from 'react';
import {useHistory} from '@docusaurus/router';
import type {Location, Action} from '@docusaurus/history';
type HistoryBlockHandler = (location: Location, action: Action) => void | false;
/*
Permits to register a handler that will be called on history actions (pop,push,replace)
If the handler returns false, the navigation transition will be blocked/cancelled
*/
export function useHistoryActionHandler(handler: HistoryBlockHandler): void {
const {block} = useHistory();
// Avoid stale closure issues without triggering useless re-renders
const lastHandlerRef = useRef(handler);
useEffect(() => {
lastHandlerRef.current = handler;
}, [handler]);
useEffect(() => {
// See https://github.com/remix-run/history/blob/main/docs/blocking-transitions.md
return block((location, action) => {
return lastHandlerRef.current(location, action);
});
}, [block, lastHandlerRef]);
}
/*
Permits to register a handler that will be called on history pop navigation (backward/forward)
If the handler returns false, the backward/forward transition will be blocked
Unfortunately there's no good way to detect the "direction" (backward/forward) of the POP event.
*/
export function useHistoryPopHandler(handler: HistoryBlockHandler): void {
useHistoryActionHandler((location, action) => {
if (action === 'POP') {
// Eventually block navigation if handler returns false
return handler(location, action);
}
// Don't block other navigation actions
return undefined;
});
}