mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-24 14:36:59 +02:00
refactor(v2): mobile dropdown navbar: expand when subitem become active (#5168)
This commit is contained in:
parent
007e901354
commit
818fb3956b
3 changed files with 63 additions and 5 deletions
|
@ -7,21 +7,49 @@
|
||||||
|
|
||||||
import React, {useState, useRef, useEffect} from 'react';
|
import React, {useState, useRef, useEffect} from 'react';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {useLocation} from '@docusaurus/router';
|
|
||||||
import {
|
import {
|
||||||
isSamePath,
|
isSamePath,
|
||||||
useCollapsible,
|
useCollapsible,
|
||||||
Collapsible,
|
Collapsible,
|
||||||
|
useLocalPathname,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
import type {
|
import type {
|
||||||
DesktopOrMobileNavBarItemProps,
|
DesktopOrMobileNavBarItemProps,
|
||||||
Props,
|
Props,
|
||||||
} from '@theme/NavbarItem/DropdownNavbarItem';
|
} from '@theme/NavbarItem/DropdownNavbarItem';
|
||||||
|
import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';
|
||||||
|
|
||||||
import {NavLink} from '@theme/NavbarItem/DefaultNavbarItem';
|
import {NavLink} from '@theme/NavbarItem/DefaultNavbarItem';
|
||||||
import NavbarItem from '@theme/NavbarItem';
|
import NavbarItem from '@theme/NavbarItem';
|
||||||
|
|
||||||
const dropdownLinkActiveClass = 'dropdown__link--active';
|
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({
|
function DropdownNavbarItemDesktop({
|
||||||
items,
|
items,
|
||||||
position,
|
position,
|
||||||
|
@ -102,12 +130,20 @@ function DropdownNavbarItemMobile({
|
||||||
position: _position, // Need to destructure position from props so that it doesn't get passed on.
|
position: _position, // Need to destructure position from props so that it doesn't get passed on.
|
||||||
...props
|
...props
|
||||||
}: DesktopOrMobileNavBarItemProps) {
|
}: DesktopOrMobileNavBarItemProps) {
|
||||||
const {pathname} = useLocation();
|
const localPathname = useLocalPathname();
|
||||||
const {collapsed, toggleCollapsed} = useCollapsible({
|
const containsActive = containsActiveItems(items, localPathname);
|
||||||
initialState: () =>
|
|
||||||
!items?.some((item) => isSamePath(item.to, pathname)) ?? true,
|
const {collapsed, toggleCollapsed, setCollapsed} = useCollapsible({
|
||||||
|
initialState: () => !containsActive,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Expand/collapse if any item active after a navigation
|
||||||
|
useEffect(() => {
|
||||||
|
if (containsActive) {
|
||||||
|
setCollapsed(!containsActive);
|
||||||
|
}
|
||||||
|
}, [localPathname, containsActive]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
className={clsx('menu__list-item', {
|
className={clsx('menu__list-item', {
|
||||||
|
|
|
@ -63,3 +63,5 @@ export {
|
||||||
AnnouncementBarProvider,
|
AnnouncementBarProvider,
|
||||||
useAnnouncementBar,
|
useAnnouncementBar,
|
||||||
} from './utils/announcementBarUtils';
|
} from './utils/announcementBarUtils';
|
||||||
|
|
||||||
|
export {useLocalPathname} from './utils/useLocalPathname';
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/**
|
||||||
|
* 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 useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
|
import {useLocation} from '@docusaurus/router';
|
||||||
|
|
||||||
|
// Get the pathname of current route, without the optional site baseUrl
|
||||||
|
// - /docs/myDoc => /docs/myDoc
|
||||||
|
// - /baseUrl/docs/myDoc => /docs/myDoc
|
||||||
|
export function useLocalPathname(): string {
|
||||||
|
const {
|
||||||
|
siteConfig: {baseUrl},
|
||||||
|
} = useDocusaurusContext();
|
||||||
|
const {pathname} = useLocation();
|
||||||
|
return pathname.replace(baseUrl, '/');
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue