blob: 493811cfe8d71afef941153c66fd1ebe7f8429e4 [file]
import React, { type JSX, useEffect, useState, useCallback } from 'react';
import { createPortal } from 'react-dom';
import clsx from 'clsx';
import { translate } from '@docusaurus/Translate';
import useIsBrowser from '@docusaurus/useIsBrowser';
import { useLocation } from '@docusaurus/router';
import { useActivePlugin, useActiveVersion, useDocsSidebar } from '@docusaurus/plugin-content-docs/client';
import { ThemeClassNames } from '@docusaurus/theme-common';
import DocSidebarItems from '@theme/DocSidebarItems';
import SearchBar from '@theme/SearchBar';
import { getDocsSidebarScope, supportsDocsDomainNavigation } from '@site/src/utils/docs-sidebar-scope';
import styles from './MobileSidebarDrawer.module.css';
export default function MobileSidebarDrawer(): JSX.Element | null {
const isBrowser = useIsBrowser();
const sidebar = useDocsSidebar();
const activePlugin = useActivePlugin();
const activeVersion = useActiveVersion(activePlugin?.pluginId);
const { pathname } = useLocation();
const usesDomainNavigation = supportsDocsDomainNavigation(activePlugin?.pluginId, activeVersion?.name);
const [open, setOpen] = useState(false);
const close = useCallback(() => setOpen(false), []);
useEffect(() => {
if (!open) return undefined;
const { style } = document.body;
const previous = style.overflow;
style.overflow = 'hidden';
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') setOpen(false);
};
window.addEventListener('keydown', onKey);
return () => {
style.overflow = previous;
window.removeEventListener('keydown', onKey);
};
}, [open]);
useEffect(() => {
setOpen(false);
}, [pathname]);
if (!sidebar) return null;
const sidebarScope = getDocsSidebarScope(sidebar.items, pathname);
const scopedSidebarItems = usesDomainNavigation ? sidebarScope.scopedItems : sidebar.items;
const drawerLabel = usesDomainNavigation && sidebarScope.activeDomain
? sidebarScope.activeDomain.label
: translate({id: 'docs.navigation.menu', message: 'Menu'});
const drawer = (
<div className={clsx(open && styles.open)} aria-hidden={!open}>
<div
className={styles.backdrop}
onClick={close}
role="presentation"
/>
<aside
className={styles.drawer}
aria-label={translate({id: 'docs.navigation.sidebar', message: 'Docs sidebar'})}
>
<div className={styles.header}>
<span>{drawerLabel}</span>
<button
type="button"
className={styles.close}
onClick={close}
aria-label={translate({id: 'docs.navigation.closeSidebar', message: 'Close docs sidebar'})}
>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
<path
d="M5 5l10 10M15 5L5 15"
stroke="currentColor"
strokeWidth="1.6"
strokeLinecap="round"
/>
</svg>
</button>
</div>
<nav
className={styles.body}
aria-label={translate({id: 'docs.navigation.sidebarNavigation', message: 'Docs sidebar navigation'})}
>
<ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list', styles.menu)}>
<DocSidebarItems
items={scopedSidebarItems}
activePath={pathname}
onItemClick={(item) => {
if (item.type === 'link') {
close();
}
if (item.type === 'category' && item.href) {
close();
}
}}
level={1}
/>
</ul>
</nav>
</aside>
</div>
);
return (
<>
<div className={styles.toolbar}>
{!usesDomainNavigation && (
<div className={styles.toolbarSearch}>
<SearchBar />
</div>
)}
<button
type="button"
className={clsx(styles.toolbarIconBtn, usesDomainNavigation && styles.toolbarMenuBtn)}
onClick={() => setOpen(true)}
aria-label={translate({id: 'docs.navigation.openSidebar', message: 'Open docs sidebar'})}
aria-expanded={open}
>
<svg className={styles.toolbarIcon} viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" />
</svg>
{usesDomainNavigation && (
<span className={styles.toolbarMenuLabel}>
{translate({id: 'docs.navigation.browseSection', message: 'Browse this section'})}
</span>
)}
</button>
</div>
{isBrowser && createPortal(drawer, document.body)}
</>
);
}