@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
JavaScript
;
'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
});
}