import { useRef, useState, useCallback } from 'react'; import { Menu, DropdownItem } from '@patternfly/react-core'; import AngleRightIcon from '@patternfly/react-icons/dist/esm/icons/angle-right-icon'; import { css } from '@patternfly/react-styles'; import topologyStyles from '../../css/topology-components'; // FIXME fully qualified due to the effect of long build times on storybook import Popper from '../popper/Popper'; interface ContextSubMenuItemProps { label: React.ReactNode; children: React.ReactNode[]; } /** * Check if an event target implements the [DOM Node interface][1]. * Needed to prevent runtime errors where the event target is not a DOM node, * but `contains` is still called on it. * * [1]: https://developer.mozilla.org/en-US/docs/Web/API/Node */ const implementsDOMNode = (node: any): node is Node => { return node && typeof node === 'object' && node.nodeType && node.nodeName; }; const ContextSubMenuItem: React.FunctionComponent = ({ label, children, ...other }) => { const nodeRef = useRef(null); const subMenuRef = useRef(null); const [open, setOpen] = useState(false); const referenceCb = useCallback(() => nodeRef.current || { x: 0, y: 0 }, []); return ( <> e.stopPropagation()} // mouse enter will open the sub menu onMouseEnter={() => setOpen(true)} onMouseLeave={(e) => { // if the mouse leaves this item, close the sub menu only if the mouse did not enter the sub menu itself if ( !subMenuRef.current || (implementsDOMNode(e.relatedTarget) && !subMenuRef.current.contains(e.relatedTarget)) ) { setOpen(false); } }} onKeyDown={(e) => { // open the sub menu on enter or right arrow if (e.key === 'ArrowRight' || e.key === 'Enter') { setOpen(true); e.stopPropagation(); } }} > {label} { // only close the sub menu if clicking anywhere outside the menu item that owns the sub menu if (!e || !nodeRef.current || (implementsDOMNode(e.target) && !nodeRef.current.contains(e.target))) { setOpen(false); } }} reference={referenceCb} container={nodeRef.current?.closest('.pf-v6-c-menu__content')} returnFocus > { // only close the sub menu if the mouse does not enter the item if ( !nodeRef.current || (implementsDOMNode(e.relatedTarget) && !nodeRef.current.contains(e.relatedTarget)) ) { setOpen(false); } }} onKeyDown={(e) => { // close the sub menu on left arrow if (e.key === 'ArrowLeft') { setOpen(false); e.stopPropagation(); } }} ref={subMenuRef} role="presentation" isNavFlyout > {children} ); }; export default ContextSubMenuItem;