UNPKG

@szhsin/react-menu

Version:

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

81 lines (77 loc) 2.55 kB
'use strict'; var react = require('react'); var ControlledMenu = require('./ControlledMenu.cjs'); var jsxRuntime = require('react/jsx-runtime'); var useMenuStateAndFocus = require('../hooks/useMenuStateAndFocus.cjs'); var useClick = require('../hooks/useClick.cjs'); var useCombinedRef = require('../hooks/useCombinedRef.cjs'); var utils = require('../utils/utils.cjs'); var constants = require('../utils/constants.cjs'); const isLegacyReact = parseInt(react.version) < 19; const Menu = /*#__PURE__*/react.forwardRef(function Menu({ 'aria-label': ariaLabel, captureFocus: _, initialOpen: _1, menuButton, instanceRef, onMenuChange, ...restProps }, externalRef) { const [stateProps, toggleMenu, openMenu] = useMenuStateAndFocus.useMenuStateAndFocus({ ...restProps, onMenuChange }); const { state } = stateProps; const isOpen = utils.isMenuOpen(state); const buttonRef = react.useRef(null); const anchorProps = useClick.useClick(state, (_, e) => openMenu(!e.detail ? constants.FocusPositions.FIRST : undefined)); const handleClose = react.useCallback(e => { toggleMenu(false); if (e.key) buttonRef.current.focus(); }, [toggleMenu]); const onKeyDown = e => { switch (e.key) { case constants.Keys.UP: openMenu(constants.FocusPositions.LAST); break; case constants.Keys.DOWN: openMenu(constants.FocusPositions.FIRST); break; default: return; } e.preventDefault(); }; const button = utils.safeCall(menuButton, { open: isOpen }); if (!button || !button.type) throw new Error('Menu requires a menuButton prop.'); const buttonProps = { ...utils.mergeProps({ onKeyDown, ...anchorProps }, button.props), ref: useCombinedRef.useCombinedRef(isLegacyReact ? button.ref : button.props.ref, buttonRef) }; if (utils.getName(button.type) === 'MenuButton') { buttonProps.isOpen = isOpen; } const renderButton = /*#__PURE__*/react.cloneElement(button, buttonProps); react.useImperativeHandle(instanceRef, () => ({ openMenu, closeMenu: () => toggleMenu(false) })); return /*#__PURE__*/jsxRuntime.jsxs(react.Fragment, { children: [renderButton, /*#__PURE__*/jsxRuntime.jsx(ControlledMenu.ControlledMenu, { ...restProps, ...stateProps, "aria-label": ariaLabel || (typeof button.props.children === 'string' ? button.props.children : 'Menu'), anchorRef: buttonRef, ref: externalRef, onClose: handleClose })] }); }); exports.Menu = Menu;