@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.
140 lines (139 loc) • 5.66 kB
JavaScript
"use strict";
'use client';
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MenuSubmenuTrigger = void 0;
var _formatErrorMessage2 = _interopRequireDefault(require("@base-ui-components/utils/formatErrorMessage"));
var React = _interopRequireWildcard(require("react"));
var _floatingUiReact = require("../../floating-ui-react");
var _MenuRootContext = require("../root/MenuRootContext");
var _useBaseUiId = require("../../utils/useBaseUiId");
var _popupStateMapping = require("../../utils/popupStateMapping");
var _useCompositeListItem = require("../../composite/list/useCompositeListItem");
var _useMenuItem = require("../item/useMenuItem");
var _useRenderElement = require("../../utils/useRenderElement");
var _MenuPositionerContext = require("../positioner/MenuPositionerContext");
var _popups = require("../../utils/popups");
var _MenuSubmenuRootContext = require("../submenu-root/MenuSubmenuRootContext");
/**
* A menu item that opens a submenu.
* Renders a `<div>` element.
*
* Documentation: [Base UI Menu](https://base-ui.com/react/components/menu)
*/
const MenuSubmenuTrigger = exports.MenuSubmenuTrigger = /*#__PURE__*/React.forwardRef(function SubmenuTriggerComponent(componentProps, forwardedRef) {
const {
render,
className,
label,
id: idProp,
nativeButton = false,
openOnHover = true,
delay = 100,
closeDelay = 0,
disabled: disabledProp = false,
...elementProps
} = componentProps;
const listItem = (0, _useCompositeListItem.useCompositeListItem)();
const menuPositionerContext = (0, _MenuPositionerContext.useMenuPositionerContext)();
const {
store
} = (0, _MenuRootContext.useMenuRootContext)();
const thisTriggerId = (0, _useBaseUiId.useBaseUiId)(idProp);
const open = store.useState('open');
const floatingRootContext = store.useState('floatingRootContext');
const floatingTreeRoot = store.useState('floatingTreeRoot');
const baseRegisterTrigger = (0, _popups.useTriggerRegistration)(thisTriggerId, store);
const registerTrigger = React.useCallback(element => {
const cleanup = baseRegisterTrigger(element);
if (element !== null && store.select('open') && store.select('activeTriggerId') == null) {
store.update({
activeTriggerId: thisTriggerId,
activeTriggerElement: element,
closeDelay
});
}
return cleanup;
}, [baseRegisterTrigger, closeDelay, store, thisTriggerId]);
const [triggerElement, setTriggerElement] = React.useState(null);
const submenuRootContext = (0, _MenuSubmenuRootContext.useMenuSubmenuRootContext)();
if (!submenuRootContext?.parentMenu) {
throw /* FIXME (minify-errors-in-prod): Unminifyable error in production! */new Error(process.env.NODE_ENV !== "production" ? 'Base UI: <Menu.SubmenuTrigger> must be placed in <Menu.SubmenuRoot>.' : (0, _formatErrorMessage2.default)(37));
}
store.useSyncedValues({
closeDelay,
activeTriggerElement: triggerElement
});
const parentMenuStore = submenuRootContext.parentMenu;
const itemProps = parentMenuStore.useState('itemProps');
const highlighted = parentMenuStore.useState('isActive', listItem.index);
const itemMetadata = React.useMemo(() => ({
type: 'submenu-trigger',
setActive: () => parentMenuStore.set('activeIndex', listItem.index)
}), [parentMenuStore, listItem.index]);
const rootDisabled = store.useState('disabled');
const disabled = disabledProp || rootDisabled;
const {
getItemProps,
itemRef
} = (0, _useMenuItem.useMenuItem)({
closeOnClick: false,
disabled,
highlighted,
id: thisTriggerId,
store,
nativeButton,
itemMetadata,
nodeId: menuPositionerContext?.nodeId
});
const hoverEnabled = store.useState('hoverEnabled');
const allowMouseEnter = store.useState('allowMouseEnter');
const hoverProps = (0, _floatingUiReact.useHoverReferenceInteraction)(floatingRootContext, {
enabled: hoverEnabled && openOnHover && !disabled,
handleClose: (0, _floatingUiReact.safePolygon)({
blockPointerEvents: true
}),
mouseOnly: true,
move: true,
restMs: allowMouseEnter ? delay : undefined,
delay: {
open: allowMouseEnter ? delay : 10 ** 10,
close: closeDelay
},
triggerElement,
externalTree: floatingTreeRoot
});
const click = (0, _floatingUiReact.useClick)(floatingRootContext, {
enabled: !disabled,
event: 'mousedown',
toggle: !openOnHover,
ignoreMouse: openOnHover,
stickIfOpen: false
});
const localInteractionProps = (0, _floatingUiReact.useInteractions)([click]);
const rootTriggerProps = store.useState('triggerProps', true);
delete rootTriggerProps.id;
const state = React.useMemo(() => ({
disabled,
highlighted,
open
}), [disabled, highlighted, open]);
const element = (0, _useRenderElement.useRenderElement)('div', componentProps, {
state,
stateAttributesMapping: _popupStateMapping.triggerOpenStateMapping,
props: [localInteractionProps.getReferenceProps(), hoverProps, rootTriggerProps, itemProps, {
tabIndex: open || highlighted ? 0 : -1,
onBlur() {
if (highlighted) {
parentMenuStore.set('activeIndex', null);
}
}
}, elementProps, getItemProps],
ref: [forwardedRef, listItem.ref, itemRef, registerTrigger, setTriggerElement]
});
return element;
});
if (process.env.NODE_ENV !== "production") MenuSubmenuTrigger.displayName = "MenuSubmenuTrigger";