UNPKG

@szhsin/react-menu

Version:

React component for building accessible menu, dropdown, submenu, context menu, and more

101 lines (98 loc) 2.87 kB
import { forwardRef, useRef, useMemo } from 'react'; import { createPortal } from 'react-dom'; import { MenuList } from './MenuList.mjs'; import { jsx } from 'react/jsx-runtime'; import { safeCall } from '../utils/utils.mjs'; import { SettingsContext, EventHandlersContext, CloseReason, Keys } from '../utils/constants.mjs'; const ControlledMenu = /*#__PURE__*/forwardRef(function ControlledMenu({ 'aria-label': ariaLabel, className, containerProps, initialMounted, unmountOnClose, transition, transitionTimeout, boundingBoxRef, boundingBoxPadding, reposition = 'auto', submenuOpenDelay = 300, submenuCloseDelay = 150, viewScroll = 'initial', portal, theming, onItemClick, ...restProps }, externalRef) { const containerRef = useRef(null); const scrollNodesRef = useRef({}); const { anchorRef, state, onClose } = restProps; const settings = useMemo(() => ({ initialMounted, unmountOnClose, transition, transitionTimeout, boundingBoxRef, boundingBoxPadding, rootMenuRef: containerRef, rootAnchorRef: anchorRef, scrollNodesRef, reposition, viewScroll, submenuOpenDelay, submenuCloseDelay }), [initialMounted, unmountOnClose, transition, transitionTimeout, anchorRef, boundingBoxRef, boundingBoxPadding, reposition, viewScroll, submenuOpenDelay, submenuCloseDelay]); const eventHandlers = useMemo(() => ({ handleClick(event, isCheckorRadio) { if (!event.stopPropagation) safeCall(onItemClick, event); let keepOpen = event.keepOpen; if (keepOpen === undefined) { keepOpen = isCheckorRadio && event.key === Keys.SPACE; } if (!keepOpen) { safeCall(onClose, { value: event.value, key: event.key, reason: CloseReason.CLICK }); } }, handleClose(key) { safeCall(onClose, { key, reason: CloseReason.CLICK }); } }), [onItemClick, onClose]); if (!state) return null; const menuList = /*#__PURE__*/jsx(SettingsContext.Provider, { value: settings, children: /*#__PURE__*/jsx(EventHandlersContext.Provider, { value: eventHandlers, children: /*#__PURE__*/jsx(MenuList, { ...restProps, ariaLabel: ariaLabel || 'Menu', externalRef: externalRef, containerRef: containerRef, containerProps: { className, containerRef, containerProps, theming, transition, onClose } }) }) }); if (portal === true && typeof document !== 'undefined') { return /*#__PURE__*/createPortal(menuList, document.body); } else if (portal) { return portal.target ? /*#__PURE__*/createPortal(menuList, portal.target) : portal.stablePosition ? null : menuList; } return menuList; }); export { ControlledMenu };