UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

124 lines (122 loc) 4.25 kB
"use strict"; 'use client'; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.Menubar = void 0; var React = _interopRequireWildcard(require("react")); var _useScrollLock = require("@base-ui-components/utils/useScrollLock"); var _floatingUiReact = require("../floating-ui-react"); var _MenubarContext = require("./MenubarContext"); var _useOpenInteractionType = require("../utils/useOpenInteractionType"); var _CompositeRoot = require("../composite/root/CompositeRoot"); var _useBaseUiId = require("../utils/useBaseUiId"); var _jsxRuntime = require("react/jsx-runtime"); const menubarStateAttributesMapping = { hasSubmenuOpen(value) { return { 'data-has-submenu-open': value ? 'true' : 'false' }; } }; /** * The container for menus. * * Documentation: [Base UI Menubar](https://base-ui.com/react/components/menubar) */ const Menubar = exports.Menubar = /*#__PURE__*/React.forwardRef(function Menubar(props, forwardedRef) { const { orientation = 'horizontal', loopFocus = true, render, className, modal = true, disabled = false, id: idProp, ...elementProps } = props; const [contentElement, setContentElement] = React.useState(null); const [hasSubmenuOpen, setHasSubmenuOpen] = React.useState(false); const { openMethod, triggerProps: interactionTypeProps, reset: resetOpenInteractionType } = (0, _useOpenInteractionType.useOpenInteractionType)(hasSubmenuOpen); React.useEffect(() => { if (!hasSubmenuOpen) { resetOpenInteractionType(); } }, [hasSubmenuOpen, resetOpenInteractionType]); (0, _useScrollLock.useScrollLock)(modal && hasSubmenuOpen && openMethod !== 'touch', contentElement); const id = (0, _useBaseUiId.useBaseUiId)(idProp); const state = React.useMemo(() => ({ orientation, modal, hasSubmenuOpen }), [orientation, modal, hasSubmenuOpen]); const contentRef = React.useRef(null); const allowMouseUpTriggerRef = React.useRef(false); const context = React.useMemo(() => ({ contentElement, setContentElement, setHasSubmenuOpen, hasSubmenuOpen, modal, disabled, orientation, allowMouseUpTriggerRef, rootId: id }), [contentElement, hasSubmenuOpen, modal, disabled, orientation, id]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_MenubarContext.MenubarContext.Provider, { value: context, children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingUiReact.FloatingTree, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(MenubarContent, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CompositeRoot.CompositeRoot, { render: render, className: className, state: state, stateAttributesMapping: menubarStateAttributesMapping, refs: [forwardedRef, setContentElement, contentRef], props: [{ role: 'menubar', id }, interactionTypeProps, elementProps], orientation: orientation, loopFocus: loopFocus, highlightItemOnHover: hasSubmenuOpen }) }) }) }); }); if (process.env.NODE_ENV !== "production") Menubar.displayName = "Menubar"; function MenubarContent(props) { const nodeId = (0, _floatingUiReact.useFloatingNodeId)(); const { events: menuEvents } = (0, _floatingUiReact.useFloatingTree)(); const rootContext = (0, _MenubarContext.useMenubarContext)(); React.useEffect(() => { function onSubmenuOpenChange(details) { if (!details.nodeId || details.parentNodeId !== nodeId) { return; } if (details.open) { if (!rootContext.hasSubmenuOpen) { rootContext.setHasSubmenuOpen(true); } } else if (details.reason !== 'sibling-open' && details.reason !== 'list-navigation') { rootContext.setHasSubmenuOpen(false); } } menuEvents.on('menuopenchange', onSubmenuOpenChange); return () => { menuEvents.off('menuopenchange', onSubmenuOpenChange); }; }, [menuEvents, nodeId, rootContext]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(_floatingUiReact.FloatingNode, { id: nodeId, children: props.children }); }