import React, { ReactNode, useState, useRef, useEffect } from "react"; import cn from "classnames"; import { NavigationMenuItem, NavigationMenuItemProps, } from "./NavigationMenuItem"; /** * This menu handles the state of the dropdowns being shown, instead of state * being handled within the NavigationItem object, because we want the behaviour * of clicking one menu item with a dropdown to close the already open dropdown * of another menu item. This can only be done if we handle state one level above * the items. */ export interface NavigationMenuProps { /** * Additional Class */ className?: string; /** * Navigation Items */ items: NavigationMenuItemProps[]; /** * If this menu sits within a Navigation.Header */ withinHeader?: boolean; /** * Color theme for the nav bar */ theme?: "transparent" | "light" | "dark"; /** * Search content */ searchContent?: ReactNode; } export const NavigationMenu: React.FC = ({ className, items, withinHeader, theme = "transparent", searchContent, }) => { const [dropdownShown, setDropdownShown] = useState(0); const navRef = useRef(null); const handleClickOutside = (event: any) => { if ( navRef.current && // @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'. !navRef.current.contains(event.target) ) { setDropdownShown(0); } }; useEffect(() => { document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const itemClicked = ( e: React.MouseEvent, item: NavigationMenuItemProps, idx: number, ) => { setDropdownShown(dropdownShown === idx ? 0 : idx); item.onClick && item.onClick(e); }; const wrapMenu = (el: ReactNode) => { if (withinHeader) { return (
{el}
); } return (
{el} {searchContent ? (
{searchContent}
) : null}
); }; return wrapMenu( , ); }; NavigationMenu.Item = NavigationMenuItem;