fixed active state of sub navigation items, which are using activeWhenMatch

This commit is contained in:
Sebastian Sdorra
2020-06-17 14:49:54 +02:00
committed by René Pfeuffer
parent 91aca71591
commit dcac6b3f22
6 changed files with 143 additions and 18 deletions

View File

@@ -40777,6 +40777,68 @@ exports[`Storyshots Modal|Modal Default 1`] = `
</div>
`;
exports[`Storyshots Navigation|Secondary Active when match 1`] = `
<div
className="SecondaryNavigationstories__Columns-fdxo4w-0 iEPunq columns"
>
<div
className="column is-3"
>
<aside
className="SecondaryNavigation__SectionContainer-sc-8p1rgi-0 cpLxdt menu"
>
<div>
<p
className="SecondaryNavigation__MenuLabel-sc-8p1rgi-2 bzrEDi menu-label"
onClick={[Function]}
>
<i
className="SecondaryNavigation__Icon-sc-8p1rgi-1 djTcfn is-medium"
color="info"
>
<i
className="fas fa-caret-right"
/>
</i>
Hitchhiker
</p>
<ul
className="menu-list"
onClick={[Function]}
>
<li>
<a
className=""
href="/42"
onClick={[Function]}
>
<i
className="fas fa-puzzle-piece fa-fw"
/>
Puzzle 42
</a>
</li>
<li>
<a
className="is-active"
href="/heart-of-gold"
onClick={[Function]}
>
<i
className="fas fa-star fa-fw"
/>
Heart Of Gold
</a>
</li>
</ul>
</div>
</aside>
</div>
</div>
`;
exports[`Storyshots Navigation|Secondary Default 1`] = `
<div
className="SecondaryNavigationstories__Columns-fdxo4w-0 iEPunq columns"

View File

@@ -27,6 +27,7 @@ import { Link, useRouteMatch } from "react-router-dom";
import { RoutingProps } from "./RoutingProps";
import { FC } from "react";
import useMenuContext from "./MenuContext";
import useActiveMatch from "./useActiveMatch";
type Props = RoutingProps & {
label: string;
@@ -34,11 +35,8 @@ type Props = RoutingProps & {
icon?: string;
};
const NavLink: FC<Props> = ({ to, activeOnlyWhenExact, icon, label, title }) => {
const match = useRouteMatch({
path: to,
exact: activeOnlyWhenExact
});
const NavLink: FC<Props> = ({ to, activeWhenMatch, activeOnlyWhenExact, icon, label, title }) => {
const active = useActiveMatch({to, activeWhenMatch, activeOnlyWhenExact});
const context = useMenuContext();
const collapsed = context.isCollapsed();
@@ -54,7 +52,7 @@ const NavLink: FC<Props> = ({ to, activeOnlyWhenExact, icon, label, title }) =>
return (
<li title={collapsed ? title : undefined}>
<Link className={classNames(!!match ? "is-active" : "", collapsed ? "has-text-centered" : "")} to={to}>
<Link className={classNames(active ? "is-active" : "", collapsed ? "has-text-centered" : "")} to={to}>
{showIcon}
{collapsed ? null : label}
</Link>

View File

@@ -86,4 +86,18 @@ storiesOf("Navigation|Secondary", module)
</SecondaryNavigation>
</BinderContext.Provider>
);
});
})
.add("Active when match", () =>
withRoute("/hog")(
<SecondaryNavigation label="Hitchhiker">
<SecondaryNavigationItem to="/42" icon="fas fa-puzzle-piece" label="Puzzle 42" title="Puzzle 42" />
<SecondaryNavigationItem
activeWhenMatch={route => route.location.pathname === "/hog"}
to="/heart-of-gold"
icon="fas fa-star"
label="Heart Of Gold"
title="Heart Of Gold"
/>
</SecondaryNavigation>
)
);

View File

@@ -22,10 +22,11 @@
* SOFTWARE.
*/
import React, { FC, useContext } from "react";
import { Link, useRouteMatch } from "react-router-dom";
import { Link, useRouteMatch, useLocation } from "react-router-dom";
import classNames from "classnames";
import useMenuContext, { MenuContext } from "./MenuContext";
import { RoutingProps } from "./RoutingProps";
import useActiveMatch from "./useActiveMatch";
type Props = RoutingProps & {
label: string;
@@ -33,18 +34,19 @@ type Props = RoutingProps & {
icon?: string;
};
const SubNavigation: FC<Props> = ({ to, activeOnlyWhenExact, icon, title, label, children }) => {
const SubNavigation: FC<Props> = ({ to, activeOnlyWhenExact, activeWhenMatch, icon, title, label, children }) => {
const context = useMenuContext();
const collapsed = context.isCollapsed();
const parents = to.split("/");
parents.splice(-1, 1);
const parent = parents.join("/");
const match = useRouteMatch({
path: parent,
exact: activeOnlyWhenExact
});
const context = useMenuContext();
const collapsed = context.isCollapsed();
const active = useActiveMatch({
to: parent,
activeOnlyWhenExact,
activeWhenMatch
})
let defaultIcon = "fas fa-cog";
if (icon) {
@@ -52,13 +54,13 @@ const SubNavigation: FC<Props> = ({ to, activeOnlyWhenExact, icon, title, label,
}
let childrenList = null;
if (match && !collapsed) {
if (active && !collapsed) {
childrenList = <ul className="sub-menu">{children}</ul>;
}
return (
<li title={collapsed ? title : undefined}>
<Link className={classNames(match != null ? "is-active" : "", collapsed ? "has-text-centered" : "")} to={to}>
<Link className={classNames(active ? "is-active" : "", collapsed ? "has-text-centered" : "")} to={to}>
<i className={classNames(defaultIcon, "fa-fw")} /> {collapsed ? "" : label}
</Link>
{childrenList}

View File

@@ -0,0 +1,48 @@
/*
* MIT License
*
* Copyright (c) 2020-present Cloudogu GmbH and Contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import {useLocation, useRouteMatch} from "react-router-dom";
import {RoutingProps} from "./RoutingProps";
const useActiveMatch = ({to, activeOnlyWhenExact, activeWhenMatch}: RoutingProps) => {
const match = useRouteMatch({
path: to,
exact: activeOnlyWhenExact
});
const location = useLocation();
const isActiveWhenMatch = () => {
if (activeWhenMatch) {
return activeWhenMatch({
location
});
}
return false;
};
return !!match || isActiveWhenMatch();
};
export default useActiveMatch;