import React, { useEffect, useRef, useState, type SyntheticEvent } from 'react' import ReactDOM from 'react-dom' import { MenuDropdown } from '../MenuDropdown' import styles from './StatelessMenu.module.scss' export type StatelessMenuProps = { /** * Whether the menu is to be used on the left or right * side of the viewport. If left, the left of the dropdown * is aligned to the left of the button (and vice versa) * @default "left" */ 'align'?: 'left' | 'right' /** * The width of the dropdown. * "default": a fixed width of 248px * "contain": contain the children's width (will be same width as children) * @default "default" */ 'dropdownWidth'?: 'default' | 'contain' 'data-testid'?: string 'dropdownId'?: string /** * Determines when the menu should automatically hide. * @default: "on" */ 'autoHide'?: 'on' | 'outside-click-only' | 'off' /** * The content to appear inside the dropdown when it is open */ 'children': React.ReactNode /** * Render the tooltip inside a react portal, given the CSS selector. * This is typically used for instances where the menu is a descendant of an * `overflow: scroll` or `overflow: hidden` element. */ 'portalSelector'?: string 'isMenuVisible': boolean 'toggleMenuDropdown': () => void 'hideMenuDropdown': () => void 'renderButton': (args: { 'onClick': (e: any) => void 'onMouseDown': (e: any) => void 'aria-expanded': boolean }) => React.ReactElement 'onClick'?: (event: SyntheticEvent) => void } export const StatelessMenu = ({ align = 'left', dropdownWidth = 'default', autoHide = 'on', 'data-testid': dataTestId, dropdownId, children, portalSelector, isMenuVisible, toggleMenuDropdown, hideMenuDropdown, renderButton, onClick, }: StatelessMenuProps): JSX.Element => { const [referenceElement, setReferenceElement] = useState(null) const portalSelectorElementRef = useRef(null) const menuButton = renderButton({ 'onClick': (e: React.MouseEvent) => { e.preventDefault() e.stopPropagation() toggleMenuDropdown() }, 'onMouseDown': (e: React.MouseEvent) => e.preventDefault(), 'aria-expanded': isMenuVisible, }) useEffect(() => { portalSelectorElementRef.current = portalSelector ? document.querySelector(portalSelector) : null }, [portalSelector]) useEffect(() => { if (portalSelector && !portalSelectorElementRef.current) { // eslint-disable-next-line no-console console.warn('The portal could not be created using the selector: ' + portalSelector) } }, [portalSelectorElementRef, portalSelector]) const menu = isMenuVisible ? ( {children} ) : null return ( // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
{menuButton}
{portalSelector && portalSelectorElementRef.current ? ReactDOM.createPortal(menu, portalSelectorElementRef.current) : menu}
) } StatelessMenu.displayName = 'StatelessMenu'