core-components: fix route matching in SidebarItem

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2021-08-07 13:51:36 +02:00
parent b319a924df
commit 55a5dbd547
2 changed files with 61 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Fix for `SidebarItem` matching the active route too broadly.
@@ -34,7 +34,12 @@ import React, {
useContext,
useState,
} from 'react';
import { NavLink, NavLinkProps } from 'react-router-dom';
import {
Link,
NavLinkProps,
useLocation,
useResolvedPath,
} from 'react-router-dom';
import { sidebarConfig, SidebarContext } from './config';
const useStyles = makeStyles<BackstageTheme>(theme => {
@@ -147,6 +152,54 @@ function isButtonItem(
return (props as SidebarItemLinkProps).to === undefined;
}
// TODO(Rugvip): Remove this once NavLink is updated in react-router-dom.
// This is needed because react-router doesn't handle the path comparison
// properly yet, matching for example /foobar with /foo.
export const WorkaroundNavLink = React.forwardRef<
HTMLAnchorElement,
NavLinkProps
>(function WorkaroundNavLinkWithRef(
{
to,
end,
style,
className,
activeStyle,
caseSensitive,
activeClassName = 'active',
'aria-current': ariaCurrentProp = 'page',
...rest
},
ref,
) {
let { pathname: locationPathname } = useLocation();
let { pathname: toPathname } = useResolvedPath(to);
if (!caseSensitive) {
locationPathname = locationPathname.toLowerCase();
toPathname = toPathname.toLowerCase();
}
let isActive = locationPathname === toPathname;
if (!isActive && !end) {
// This is the behavior that is different from the original NavLink
isActive = locationPathname.startsWith(`${toPathname}/`);
}
const ariaCurrent = isActive ? ariaCurrentProp : undefined;
return (
<Link
{...rest}
to={to}
ref={ref}
aria-current={ariaCurrent}
style={{ ...style, ...(isActive ? activeStyle : undefined) }}
className={clsx([className, isActive ? activeClassName : undefined])}
/>
);
});
export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
const {
icon: Icon,
@@ -211,7 +264,7 @@ export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
}
return (
<NavLink
<WorkaroundNavLink
{...childProps}
activeClassName={classes.selected}
to={props.to}
@@ -220,7 +273,7 @@ export const SidebarItem = forwardRef<any, SidebarItemProps>((props, ref) => {
{...navLinkProps}
>
{content}
</NavLink>
</WorkaroundNavLink>
);
});