Skip to content

Commit

Permalink
fix(theme-classic): consistently apply the right active class name fo…
Browse files Browse the repository at this point in the history
…r all navbar items
  • Loading branch information
Josh-Cena committed May 16, 2022
1 parent b744886 commit 4d33da3
Show file tree
Hide file tree
Showing 10 changed files with 36 additions and 81 deletions.
16 changes: 3 additions & 13 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,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;
Expand Down Expand Up @@ -974,22 +975,11 @@ declare module '@theme/NavbarItem' {
} & SearchNavbarItemProps)
);

export type Types = Props['type'];
export type NavbarItemType = Props['type'];

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';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@
import React from 'react';
import clsx from 'clsx';
import NavbarNavLink from '@theme/NavbarItem/NavbarNavLink';
import {getInfimaActiveClassName} from '@theme/NavbarItem/utils';
import type {
DesktopOrMobileNavBarItemProps,
Props,
} from '@theme/NavbarItem/DefaultNavbarItem';

/**
* On desktop and mobile, we would apply different class names for dropdown
* items.
* @see https://github.com/facebook/docusaurus/pull/5431
*/
const getInfimaActiveClassName = (
mobile?: boolean,
): `${'menu' | 'navbar'}__link--active` =>
mobile ? 'menu__link--active' : 'navbar__link--active';

function DefaultNavbarItemDesktop({
className,
isDropdownItem = false,
Expand All @@ -25,6 +34,7 @@ function DefaultNavbarItemDesktop({
isDropdownItem ? 'dropdown__link' : 'navbar__item navbar__link',
className,
)}
isDropdownLink={isDropdownItem}
{...props}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ import type {
} from '@theme/NavbarItem/DropdownNavbarItem';
import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';

const dropdownLinkActiveClass = 'dropdown__link--active';

function isItemActive(
item: LinkLikeNavbarItemProps,
localPathname: string,
Expand Down Expand Up @@ -51,6 +49,7 @@ function DropdownNavbarItemDesktop({
items,
position,
className,
onClick,
...props
}: DesktopOrMobileNavBarItemProps) {
const dropdownRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -114,12 +113,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}
/>
Expand All @@ -133,6 +132,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();
Expand Down Expand Up @@ -172,7 +172,7 @@ function DropdownNavbarItemMobile({
<NavbarItem
mobile
isDropdownItem
onClick={props.onClick}
onClick={onClick}
activeClassName="menu__link--active"
{...childItemProps}
key={i}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,11 @@ export default function LocaleDropdownNavbarItem({
fullyQualified: false,
})}`;
return {
isNavLink: true,
label: localeConfigs[locale]!.label,
to,
target: '_self',
autoAddBaseUrl: false,
className: locale === currentLocale ? 'dropdown__link--active' : '',
isActive: () => locale === currentLocale,
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ 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,
to,
href,
label,
html,
activeClassName = '',
isDropdownLink,
prependBaseUrlToHref,
...props
}: Props): JSX.Element {
Expand All @@ -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
Expand Down Expand Up @@ -64,9 +61,6 @@ export default function NavbarNavLink({
<Link
to={toUrl}
isNavLink
activeClassName={
!props.className?.includes(activeClassName) ? activeClassName : ''
}
{...((activeBasePath || activeBaseRegex) && {
isActive: (_match, location) =>
activeBaseRegex
Expand Down
27 changes: 9 additions & 18 deletions packages/docusaurus-theme-classic/src/theme/NavbarItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,22 @@

import React from 'react';
import ComponentTypes from '@theme/NavbarItem/ComponentTypes';
import {type Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem';
import type {Types, Props} from '@theme/NavbarItem';
import type {NavbarItemType, Props} from '@theme/NavbarItem';

const getNavbarItemComponent = (type: NonNullable<Types>) => {
const component = ComponentTypes[type];
if (!component) {
throw new Error(`No NavbarItem component found for type "${type}".`);
}
return component;
};

function getComponentType(type: Types, isDropdown: boolean) {
function normalizeComponentType(type: NavbarItemType, props: object) {
// Backward compatibility: navbar item with no type set
// but containing dropdown items should use the type "dropdown"
if (!type || type === 'default') {
return isDropdown ? 'dropdown' : 'default';
return 'items' in props ? 'dropdown' : 'default';
}
return type as NonNullable<Types>;
return type;
}

export default function NavbarItem({type, ...props}: Props): JSX.Element {
const componentType = getComponentType(
type,
(props as DropdownNavbarItemProps).items !== undefined,
);
const NavbarItemComponent = getNavbarItemComponent(componentType);
const componentType = normalizeComponentType(type, props);
const NavbarItemComponent = ComponentTypes[componentType];
if (!NavbarItemComponent) {
throw new Error(`No NavbarItem component found for type "${type}".`);
}
return <NavbarItemComponent {...(props as never)} />;
}
13 changes: 0 additions & 13 deletions packages/docusaurus-theme-classic/src/theme/NavbarItem/utils.ts

This file was deleted.

0 comments on commit 4d33da3

Please sign in to comment.