From 818fb3956b49f26234c90ba5e9fcb950e925ebdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Lorber?= Date: Wed, 14 Jul 2021 19:42:47 +0200 Subject: [PATCH] refactor(v2): mobile dropdown navbar: expand when subitem become active (#5168) --- .../theme/NavbarItem/DropdownNavbarItem.tsx | 46 +++++++++++++++++-- packages/docusaurus-theme-common/src/index.ts | 2 + .../src/utils/useLocalPathname.ts | 20 ++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 packages/docusaurus-theme-common/src/utils/useLocalPathname.ts diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx index b8ab9d7cd5..7dec9776e9 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx @@ -7,21 +7,49 @@ import React, {useState, useRef, useEffect} from 'react'; import clsx from 'clsx'; -import {useLocation} from '@docusaurus/router'; import { isSamePath, useCollapsible, Collapsible, + useLocalPathname, } from '@docusaurus/theme-common'; import type { DesktopOrMobileNavBarItemProps, Props, } from '@theme/NavbarItem/DropdownNavbarItem'; +import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; + import {NavLink} from '@theme/NavbarItem/DefaultNavbarItem'; import NavbarItem from '@theme/NavbarItem'; const dropdownLinkActiveClass = 'dropdown__link--active'; +function isItemActive( + item: LinkLikeNavbarItemProps, + localPathname: string, +): boolean { + if (isSamePath(item.to, localPathname)) { + return true; + } + if ( + item.activeBaseRegex && + new RegExp(item.activeBaseRegex).test(localPathname) + ) { + return true; + } + if (item.activeBasePath && localPathname.startsWith(item.activeBasePath)) { + return true; + } + return false; +} + +function containsActiveItems( + items: readonly LinkLikeNavbarItemProps[], + localPathname: string, +): boolean { + return items.some((item) => isItemActive(item, localPathname)); +} + function DropdownNavbarItemDesktop({ items, position, @@ -102,12 +130,20 @@ function DropdownNavbarItemMobile({ position: _position, // Need to destructure position from props so that it doesn't get passed on. ...props }: DesktopOrMobileNavBarItemProps) { - const {pathname} = useLocation(); - const {collapsed, toggleCollapsed} = useCollapsible({ - initialState: () => - !items?.some((item) => isSamePath(item.to, pathname)) ?? true, + const localPathname = useLocalPathname(); + const containsActive = containsActiveItems(items, localPathname); + + const {collapsed, toggleCollapsed, setCollapsed} = useCollapsible({ + initialState: () => !containsActive, }); + // Expand/collapse if any item active after a navigation + useEffect(() => { + if (containsActive) { + setCollapsed(!containsActive); + } + }, [localPathname, containsActive]); + return (
  • /docs/myDoc +// - /baseUrl/docs/myDoc => /docs/myDoc +export function useLocalPathname(): string { + const { + siteConfig: {baseUrl}, + } = useDocusaurusContext(); + const {pathname} = useLocation(); + return pathname.replace(baseUrl, '/'); +}