mirror of
https://github.com/facebook/docusaurus.git
synced 2025-12-26 09:43:10 +00:00
fix(theme-classic): consistently apply the right active class name for all navbar items (#7430)
This commit is contained in:
parent
5fcb742aa1
commit
f609acab4f
|
|
@ -214,13 +214,6 @@ export default function getSwizzleConfig(): SwizzleConfig {
|
|||
description:
|
||||
'The Navbar item components mapping. Can be ejected to add custom navbar item types. See https://github.com/facebook/docusaurus/issues/7227.',
|
||||
},
|
||||
// TODO should probably not even appear here
|
||||
'NavbarItem/utils': {
|
||||
actions: {
|
||||
eject: 'forbidden',
|
||||
wrap: 'forbidden',
|
||||
},
|
||||
},
|
||||
NotFound: {
|
||||
actions: {
|
||||
eject: 'safe',
|
||||
|
|
|
|||
|
|
@ -809,7 +809,8 @@ declare module '@theme/NavbarItem/NavbarNavLink' {
|
|||
readonly exact?: boolean;
|
||||
readonly label?: ReactNode;
|
||||
readonly html?: string;
|
||||
readonly prependBaseUrlToHref?: string;
|
||||
readonly prependBaseUrlToHref?: boolean;
|
||||
readonly isDropdownLink?: boolean;
|
||||
}
|
||||
|
||||
export default function NavbarNavLink(props: Props): JSX.Element;
|
||||
|
|
@ -982,17 +983,6 @@ declare module '@theme/NavbarItem' {
|
|||
export default function NavbarItem(props: Props): JSX.Element;
|
||||
}
|
||||
|
||||
declare module '@theme/NavbarItem/utils' {
|
||||
/**
|
||||
* On desktop and mobile, we would apply different class names for dropdown
|
||||
* items.
|
||||
* @see https://github.com/facebook/docusaurus/pull/5431
|
||||
*/
|
||||
export function getInfimaActiveClassName(
|
||||
mobile?: boolean,
|
||||
): `${'menu' | 'navbar'}__link--active`;
|
||||
}
|
||||
|
||||
declare module '@theme/PaginatorNavLink' {
|
||||
import type {ReactNode} from 'react';
|
||||
import type {PropNavigationLink} from '@docusaurus/plugin-content-docs';
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
|
||||
import {getInfimaActiveClassName} from '@theme/NavbarItem/utils';
|
||||
import type {
|
||||
DesktopOrMobileNavBarItemProps,
|
||||
Props,
|
||||
|
|
@ -25,6 +24,7 @@ function DefaultNavbarItemDesktop({
|
|||
isDropdownItem ? 'dropdown__link' : 'navbar__item navbar__link',
|
||||
className,
|
||||
)}
|
||||
isDropdownLink={isDropdownItem}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
|
@ -58,7 +58,8 @@ export default function DefaultNavbarItem({
|
|||
<Comp
|
||||
{...props}
|
||||
activeClassName={
|
||||
props.activeClassName ?? getInfimaActiveClassName(mobile)
|
||||
props.activeClassName ??
|
||||
(mobile ? 'menu__link--active' : 'navbar__link--active')
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
|
||||
import {useLayoutDoc} from '@docusaurus/theme-common';
|
||||
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
|
||||
import {getInfimaActiveClassName} from '@theme/NavbarItem/utils';
|
||||
import type {Props} from '@theme/NavbarItem/DocNavbarItem';
|
||||
|
||||
export default function DocNavbarItem({
|
||||
|
|
@ -27,20 +25,14 @@ export default function DocNavbarItem({
|
|||
return null;
|
||||
}
|
||||
|
||||
const activeDocInfimaClassName = getInfimaActiveClassName(props.mobile);
|
||||
|
||||
return (
|
||||
<DefaultNavbarItem
|
||||
exact
|
||||
{...props}
|
||||
className={clsx(props.className, {
|
||||
[activeDocInfimaClassName]:
|
||||
// Do not make the item active if the active doc doesn't have sidebar.
|
||||
// If `activeDoc === doc` react-router will make it active anyways,
|
||||
// regardless of the existence of a sidebar
|
||||
activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar,
|
||||
})}
|
||||
activeClassName={activeDocInfimaClassName}
|
||||
isActive={() =>
|
||||
activeDoc?.path === doc.path ||
|
||||
(!!activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar)
|
||||
}
|
||||
label={staticLabel ?? doc.id}
|
||||
to={doc.path}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -6,11 +6,9 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {useActiveDocContext} from '@docusaurus/plugin-content-docs/client';
|
||||
import {useLayoutDocsSidebar} from '@docusaurus/theme-common';
|
||||
import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
|
||||
import {getInfimaActiveClassName} from '@theme/NavbarItem/utils';
|
||||
import type {Props} from '@theme/NavbarItem/DocSidebarNavbarItem';
|
||||
|
||||
export default function DocSidebarNavbarItem({
|
||||
|
|
@ -26,16 +24,11 @@ export default function DocSidebarNavbarItem({
|
|||
`DocSidebarNavbarItem: Sidebar with ID "${sidebarId}" doesn't have anything to be linked to.`,
|
||||
);
|
||||
}
|
||||
const activeDocInfimaClassName = getInfimaActiveClassName(props.mobile);
|
||||
|
||||
return (
|
||||
<DefaultNavbarItem
|
||||
exact
|
||||
{...props}
|
||||
className={clsx(props.className, {
|
||||
[activeDocInfimaClassName]: activeDoc?.sidebar === sidebarId,
|
||||
})}
|
||||
activeClassName={activeDocInfimaClassName}
|
||||
isActive={() => activeDoc?.sidebar === sidebarId}
|
||||
label={label ?? sidebarLink.label}
|
||||
to={sidebarLink.path}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ export default function DocsVersionDropdownNavbarItem({
|
|||
activeDocContext.alternateDocVersions[version.name] ??
|
||||
getVersionMainDoc(version);
|
||||
return {
|
||||
isNavLink: true,
|
||||
label: version.label,
|
||||
to: versionDoc.path,
|
||||
isActive: () => version === activeDocContext.activeVersion,
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ import type {
|
|||
Props,
|
||||
} from '@theme/NavbarItem/DropdownNavbarItem';
|
||||
|
||||
const dropdownLinkActiveClass = 'dropdown__link--active';
|
||||
|
||||
function isItemActive(
|
||||
item: LinkLikeNavbarItemProps,
|
||||
localPathname: string,
|
||||
|
|
@ -50,6 +48,7 @@ function DropdownNavbarItemDesktop({
|
|||
items,
|
||||
position,
|
||||
className,
|
||||
onClick,
|
||||
...props
|
||||
}: DesktopOrMobileNavBarItemProps) {
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
|
|
@ -113,12 +112,12 @@ function DropdownNavbarItemDesktop({
|
|||
? nextNavbarItem
|
||||
: // Next item is another dropdown; focus on the inner
|
||||
// anchor element instead so there's outline
|
||||
nextNavbarItem.querySelector('a');
|
||||
(targetItem as HTMLElement).focus();
|
||||
nextNavbarItem.querySelector('a')!;
|
||||
targetItem.focus();
|
||||
}
|
||||
}
|
||||
}}
|
||||
activeClassName={dropdownLinkActiveClass}
|
||||
activeClassName="dropdown__link--active"
|
||||
{...childItemProps}
|
||||
key={i}
|
||||
/>
|
||||
|
|
@ -132,6 +131,7 @@ function DropdownNavbarItemMobile({
|
|||
items,
|
||||
className,
|
||||
position, // Need to destructure position from props so that it doesn't get passed on.
|
||||
onClick,
|
||||
...props
|
||||
}: DesktopOrMobileNavBarItemProps) {
|
||||
const localPathname = useLocalPathname();
|
||||
|
|
@ -171,7 +171,7 @@ function DropdownNavbarItemMobile({
|
|||
<NavbarItem
|
||||
mobile
|
||||
isDropdownItem
|
||||
onClick={props.onClick}
|
||||
onClick={onClick}
|
||||
activeClassName="menu__link--active"
|
||||
{...childItemProps}
|
||||
key={i}
|
||||
|
|
|
|||
|
|
@ -33,12 +33,20 @@ export default function LocaleDropdownNavbarItem({
|
|||
fullyQualified: false,
|
||||
})}`;
|
||||
return {
|
||||
isNavLink: true,
|
||||
label: localeConfigs[locale]!.label,
|
||||
to,
|
||||
target: '_self',
|
||||
autoAddBaseUrl: false,
|
||||
className: locale === currentLocale ? 'dropdown__link--active' : '',
|
||||
className:
|
||||
// eslint-disable-next-line no-nested-ternary
|
||||
locale === currentLocale
|
||||
? // Similar idea as DefaultNavbarItem: select the right Infima active
|
||||
// class name. This cannot be substituted with isActive, because the
|
||||
// target URLs contain `pathname://` and therefore are not NavLinks!
|
||||
mobile
|
||||
? 'menu__link--active'
|
||||
: 'dropdown__link--active'
|
||||
: '',
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@ import {isRegexpStringMatch} from '@docusaurus/theme-common';
|
|||
import IconExternalLink from '@theme/IconExternalLink';
|
||||
import type {Props} from '@theme/NavbarItem/NavbarNavLink';
|
||||
|
||||
const dropdownLinkActiveClass = 'dropdown__link--active';
|
||||
|
||||
export default function NavbarNavLink({
|
||||
activeBasePath,
|
||||
activeBaseRegex,
|
||||
|
|
@ -22,7 +20,7 @@ export default function NavbarNavLink({
|
|||
href,
|
||||
label,
|
||||
html,
|
||||
activeClassName = '',
|
||||
isDropdownLink,
|
||||
prependBaseUrlToHref,
|
||||
...props
|
||||
}: Props): JSX.Element {
|
||||
|
|
@ -32,7 +30,6 @@ export default function NavbarNavLink({
|
|||
const activeBaseUrl = useBaseUrl(activeBasePath);
|
||||
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
|
||||
const isExternalLink = label && href && !isInternalUrl(href);
|
||||
const isDropdownLink = activeClassName === dropdownLinkActiveClass;
|
||||
|
||||
// Link content is set through html XOR label
|
||||
const linkContentProps = html
|
||||
|
|
@ -64,9 +61,6 @@ export default function NavbarNavLink({
|
|||
<Link
|
||||
to={toUrl}
|
||||
isNavLink
|
||||
activeClassName={
|
||||
!props.className?.includes(activeClassName) ? activeClassName : ''
|
||||
}
|
||||
{...((activeBasePath || activeBaseRegex) && {
|
||||
isActive: (_match, location) =>
|
||||
activeBaseRegex
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable import/no-named-export */
|
||||
|
||||
export const getInfimaActiveClassName = (
|
||||
mobile?: boolean,
|
||||
): `${'menu' | 'navbar'}__link--active` =>
|
||||
mobile ? 'menu__link--active' : 'navbar__link--active';
|
||||
Loading…
Reference in New Issue