UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

203 lines (202 loc) 7.51 kB
"use strict"; "use client"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = MenuRoot; var _push = _interopRequireDefault(require("core-js-pure/stable/instance/push.js")); var _react = _interopRequireWildcard(require("react")); var _clsx = _interopRequireDefault(require("clsx")); var _Popover = _interopRequireDefault(require("../popover/Popover.js")); var _MenuContext2 = require("./MenuContext.js"); var _withComponentMarkers = _interopRequireDefault(require("../../shared/helpers/withComponentMarkers.js")); var _whatInput = _interopRequireDefault(require("../../shared/helpers/whatInput.js")); var _MenuButton = _interopRequireDefault(require("./MenuButton.js")); var _MenuAction = _interopRequireDefault(require("./MenuAction.js")); var _useIsomorphicLayoutEffect = _interopRequireDefault(require("../../shared/helpers/useIsomorphicLayoutEffect.js")); var _jsxRuntime = require("react/jsx-runtime"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } function MenuRoot(props) { var _MenuContext; const { id, className, children, placement = 'bottom', arrowPosition = 'center', open, onOpenChange, skipPortal = false, noAnimation = false, autoAlignMode = 'initial' } = props; let triggerChild = null; const contentChildren = []; _react.default.Children.forEach(children, child => { if (!triggerChild && _react.default.isValidElement(child) && (child.type === _MenuButton.default || child.type === _MenuAction.default)) { triggerChild = child; } else { (0, _push.default)(contentChildren).call(contentChildren, child); } }); const parentContext = (0, _MenuContext2.useMenuContext)(); const level = parentContext ? parentContext.level + 1 : 0; const activeIndexRef = (0, _react.useRef)(-1); const [activeIndex, setActiveIndexState] = (0, _react.useState)(-1); const itemRefsRef = (0, _react.useRef)([]); const nextIndexRef = (0, _react.useRef)(0); const menuRef = (0, _react.useRef)(null); const [isOpenInternal, setIsOpenInternal] = (0, _react.useState)(false); const isControlled = typeof open === 'boolean'; const isOpen = isControlled ? open : isOpenInternal; const popoverCloseRef = (0, _react.useRef)(null); const setOpenState = (0, _react.useCallback)(next => { if (!isControlled) { setIsOpenInternal(next); } onOpenChange === null || onOpenChange === void 0 || onOpenChange(next); }, [isControlled, onOpenChange]); const closeAll = (0, _react.useCallback)(() => { if (popoverCloseRef.current) { popoverCloseRef.current(); } else { setOpenState(false); } parentContext === null || parentContext === void 0 || parentContext.closeAll(); }, [setOpenState, parentContext]); const closeSelf = (0, _react.useCallback)(() => { if (popoverCloseRef.current) { popoverCloseRef.current(); } else { setOpenState(false); } }, [setOpenState]); const setActiveIndex = (0, _react.useCallback)(index => { activeIndexRef.current = index; setActiveIndexState(index); }, []); const registerItem = (0, _react.useCallback)(ref => { const index = nextIndexRef.current; nextIndexRef.current += 1; itemRefsRef.current[index] = ref; return index; }, []); const unregisterItem = (0, _react.useCallback)(index => { itemRefsRef.current[index] = undefined; }, []); const contextValue = (0, _react.useMemo)(() => ({ level, closeAll, closeSelf, activeIndex, setActiveIndex, registerItem, unregisterItem, itemRefs: itemRefsRef, menuRef, isOpen }), [level, closeAll, closeSelf, activeIndex, setActiveIndex, registerItem, unregisterItem, isOpen]); (0, _react.useEffect)(() => { if (!isOpen) { nextIndexRef.current = 0; itemRefsRef.current = []; setActiveIndex(-1); } }, [isOpen, setActiveIndex]); (0, _useIsomorphicLayoutEffect.default)(() => { if (isOpen) { _whatInput.default.specificKeys([9, 37, 38, 39, 40, 33, 34, 35, 36]); } return () => { _whatInput.default.specificKeys([9]); }; }, [isOpen]); const focusOnOpenElement = (0, _react.useCallback)(() => { var _menuRef$current; return (_menuRef$current = menuRef.current) !== null && _menuRef$current !== void 0 ? _menuRef$current : null; }, []); const handleFocusComplete = (0, _react.useCallback)(() => { if (level === 0) { return; } const firstRef = itemRefsRef.current[0]; if (firstRef !== null && firstRef !== void 0 && firstRef.current) { firstRef.current.focus(); setActiveIndex(0); } }, [level, setActiveIndex]); const handleOpenChange = (0, _react.useCallback)(next => { setOpenState(next); }, [setOpenState]); const handleTriggerKeyDown = (0, _react.useCallback)(event => { if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'ArrowRight') { event.preventDefault(); if (!isOpen) { handleOpenChange(true); } requestAnimationFrame(() => { const firstRef = itemRefsRef.current[0]; if (firstRef !== null && firstRef !== void 0 && firstRef.current) { firstRef.current.focus(); setActiveIndex(0); } }); } }, [isOpen, handleOpenChange, setActiveIndex]); const resolvedTrigger = triggerChild ? renderProps => { const domProps = { ...renderProps }; const { active, open: openFn, close: closeFn, toggle: toggleFn } = renderProps; return (0, _jsxRuntime.jsx)(_MenuContext2.MenuTriggerContext, { value: { active, triggerProps: domProps, open: openFn, close: closeFn, toggle: toggleFn }, children: triggerChild }); } : undefined; return (0, _jsxRuntime.jsx)(_Popover.default, { id: id, className: (0, _clsx.default)('dnb-menu', className), trigger: resolvedTrigger, triggerAttributes: { 'aria-haspopup': 'menu', onKeyDown: handleTriggerKeyDown }, placement: placement, open: isOpen, onOpenChange: handleOpenChange, skipPortal: level > 0 ? true : skipPortal, autoAlignMode: autoAlignMode, arrowPosition: arrowPosition, noAnimation: noAnimation, hideCloseButton: true, noInnerSpace: true, focusOnOpenElement: focusOnOpenElement, onFocusComplete: handleFocusComplete, contentClassName: "dnb-menu__popover-content", children: ({ close }) => { popoverCloseRef.current = close; return _MenuContext || (_MenuContext = (0, _jsxRuntime.jsx)(_MenuContext2.MenuContext, { value: contextValue, children: contentChildren })); } }); } (0, _withComponentMarkers.default)(MenuRoot, { _supportsSpacingProps: true }); //# sourceMappingURL=MenuRoot.js.map