blob: 709c1f64468553f39e6bc78b380c0164079ba5fc [file] [log] [blame]
/**
* 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 React from "react";
import clsx from "clsx";
import Link from "@docusaurus/Link";
import useBaseUrl from "@docusaurus/useBaseUrl";
import IconExternalLink from "@theme/IconExternalLink";
import isInternalUrl from "@docusaurus/isInternalUrl";
import { isRegexpStringMatch } from "@docusaurus/theme-common";
import { getInfimaActiveClassName } from "./index";
const dropdownLinkActiveClass = "dropdown__link--active";
export function NavLink({
activeBasePath,
activeBaseRegex,
to,
href,
link,
label,
activeClassName = "",
prependBaseUrlToHref,
...props
}) {
// TODO all this seems hacky
// {to: 'version'} should probably be forbidden, in favor of {to: '/version'}
const toUrl = useBaseUrl(to);
const activeBaseUrl = useBaseUrl(activeBasePath);
const normalizedHref = useBaseUrl(href, {
forcePrependBaseUrl: true,
});
const isExternalLink = label && href && !isInternalUrl(href);
const isDropdownLink = activeClassName === dropdownLinkActiveClass;
if (link) {
return (
<a href={link} rel="noopener noreferrer" className="dropdown__link">
<span>{label}</span>
</a>
);
}
return (
<Link
{...(href
? {
href: prependBaseUrlToHref ? normalizedHref : href,
}
: {
isNavLink: true,
activeClassName: !props.className?.includes(activeClassName)
? activeClassName
: "",
to: toUrl,
...(activeBasePath || activeBaseRegex
? {
isActive: (_match, location) =>
activeBaseRegex
? isRegexpStringMatch(activeBaseRegex, location.pathname)
: location.pathname.startsWith(activeBaseUrl),
}
: null),
})}
{...props}
>
{isExternalLink ? (
<span>
{label}
<IconExternalLink
{...(isDropdownLink && {
width: 12,
height: 12,
})}
/>
</span>
) : (
label
)}
</Link>
);
}
function DefaultNavbarItemDesktop({
className,
isDropdownItem = false,
...props
}) {
const element = (
<NavLink
className={clsx(
isDropdownItem ? "dropdown__link" : "navbar__item navbar__link",
className
)}
{...props}
/>
);
if (isDropdownItem) {
return <li>{element}</li>;
}
return element;
}
function DefaultNavbarItemMobile({
className,
isDropdownItem: _isDropdownItem,
...props
}) {
let { link, label } = props;
if (link) {
return (
<a href={link} rel="noopener noreferrer" className="menu__link">
<span>{label}</span>
</a>
);
}
return (
<li className="menu__list-item">
<NavLink className={clsx("menu__link", className)} {...props} />
</li>
);
}
function DefaultNavbarItem({
mobile = false,
position: _position,
// Need to destructure position from props so that it doesn't get passed on.
...props
}) {
const Comp = mobile ? DefaultNavbarItemMobile : DefaultNavbarItemDesktop;
return (
<Comp
{...props}
activeClassName={
props.activeClassName ?? getInfimaActiveClassName(mobile)
}
/>
);
}
export default DefaultNavbarItem;