/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import * as React from "react"; import { useMemo, useEffect, useRef, useState } from "react"; import { useConfig, usePrevious } from "../../../../docz-lib/docz/dist"; //import { MenuItem } from "./Menu"; import styled, { css } from "styled-components"; import _isArray from "lodash/fp/isArray"; import { MenuHeadings } from "./MenuHeadings"; import { get } from "../../../utils/theme"; export const MenuItem = { id: "", name: "", route: "", href: "", menu: [], order: Number, parent: "" }; const WrapperProps = { active: false, theme: null }; const hrefLinks = css` font-weight: normal !important; color: #807e7e !important; &:hover, &.active { color: ${p => get("colors.sidebarPrimary")(p) || get("colors.primary")(p)} !important; } `; const activeWrapper = css` padding-left: 0; &:after { width: 1px; } `; const Wrapper = styled.div` position: relative; transition: padding 0.2s; &:after { position: absolute; display: block; content: ""; top: 30px; left: 24px; width: 0; height: calc(100% - 36px); border-left: 1px dashed ${get("colors.sidebarBorder")}; transition: width 0.2s; } ${p => p.active && activeWrapper}; `; Wrapper.defaultProps = WrapperProps; export const createLink = Link => styled(Link)` position: relative; display: block; padding: 4px 15px; font-weight: 600; font-size: 18px; letter-spacing: -0.02em; color: ${get("colors.sidebarText")}; text-decoration: none; transition: color 0.2s; &:hover, &:visited { color: ${get("colors.sidebarText")}; } &:hover, &.active { color: ${p => get("colors.sidebarPrimary")(p) || get("colors.primary")(p)}; font-weight: 600; } ${p => { return checkChildMenu(p) ? hrefLinks : ""; }} `; const checkChildMenu = obj => { const { partiallyActive, to, children } = obj; return partiallyActive && !`REST API,ASF`.includes(children.trim()); }; const LinkAnchor = createLink(styled.a``); const getActiveByLocation = route => { if (typeof window === "undefined") return; return location.pathname.slice(0, location.pathname.length - 1) === route; }; const getActiveFromClass = (el = null, route = undefined) => { const activeByClass = el && el.classList.contains("active"); const activeByLocation = route && getActiveByLocation(route); return Boolean(activeByClass || activeByLocation); }; const checkActiveClass = ($el, isActive) => { if (!isActive) return; if (isActive && !$el.classList.contains("active")) { $el.classList.add("active"); } }; const LinkProps = { item: MenuItem, onClick: React.MouseEventHandler, className: "", innerRef: node => null, children: React.ReactNode, onActiveChange: active => null }; export const MenuLink = React.forwardRef( ({ item, children, onClick, onActiveChange }, ref) => { const { linkComponent } = useConfig(); const [active, setActive] = useState(false); const prevActive = usePrevious(active); const $el = useRef(ref); const Link = useMemo(() => createLink(linkComponent), [linkComponent]); const linkProps = { children, onClick }; useEffect(() => { const isActive = getActiveFromClass($el.current, item.route); if (prevActive !== isActive) { setActive(isActive); $el && checkActiveClass($el.current, isActive); //isActive && onActiveChange && onActiveChange(item.name); } }); return ( <Wrapper active={active}> {item.route ? ( <Link {...linkProps} to={item.route} innerRef={$el} activeClassName="active" partiallyActive={true} /> ) : ( <LinkAnchor {...linkProps} ref={$el} href={item.href || "#"} target={item.href ? "_blank" : "_self"} {...(!item.href && { onClick: ev => { ev.preventDefault(); linkProps.onClick && linkProps.onClick(ev); } })} /> )} {active && item.route && <MenuHeadings route={item.route} />} </Wrapper> ); } ); MenuLink.displayName = "MenuLink";