'use client'; import _extends from "@babel/runtime/helpers/esm/extends"; import * as React from 'react'; import { unstable_useForkRef as useForkRef, unstable_useId as useId, unstable_useEnhancedEffect as useEnhancedEffect } from '@mui/utils'; import { menuReducer } from './menuReducer'; import { DropdownContext } from '../useDropdown/DropdownContext'; import { ListActionTypes, useList } from '../useList'; import { DropdownActionTypes } from '../useDropdown'; import { useCompoundParent } from '../useCompound'; import { combineHooksSlotProps } from '../utils/combineHooksSlotProps'; import { extractEventHandlers } from '../utils/extractEventHandlers'; const FALLBACK_MENU_CONTEXT = { dispatch: () => {}, popupId: '', registerPopup: () => {}, registerTrigger: () => {}, state: { open: true, changeReason: null }, triggerElement: null }; /** * * Demos: * * - [Menu](https://mui.com/base-ui/react-menu/#hooks) * * API: * * - [useMenu API](https://mui.com/base-ui/react-menu/hooks-api/#use-menu) */ export function useMenu(parameters = {}) { var _useId, _React$useContext; const { listboxRef: listboxRefProp, onItemsChange, id: idParam, disabledItemsFocusable = true, disableListWrap = false, autoFocus = true, componentName = 'useMenu' } = parameters; const rootRef = React.useRef(null); const handleRef = useForkRef(rootRef, listboxRefProp); const listboxId = (_useId = useId(idParam)) != null ? _useId : ''; const { state: { open, changeReason }, dispatch: menuDispatch, triggerElement, registerPopup } = (_React$useContext = React.useContext(DropdownContext)) != null ? _React$useContext : FALLBACK_MENU_CONTEXT; // store the initial open state to prevent focus stealing // (the first menu items gets focued only when the menu is opened by the user) const isInitiallyOpen = React.useRef(open); const { subitems, contextValue: compoundComponentContextValue } = useCompoundParent(); const subitemKeys = React.useMemo(() => Array.from(subitems.keys()), [subitems]); const getItemDomElement = React.useCallback(itemId => { var _subitems$get$ref$cur, _subitems$get; if (itemId == null) { return null; } return (_subitems$get$ref$cur = (_subitems$get = subitems.get(itemId)) == null ? void 0 : _subitems$get.ref.current) != null ? _subitems$get$ref$cur : null; }, [subitems]); const isItemDisabled = React.useCallback(id => { var _subitems$get2; return (subitems == null || (_subitems$get2 = subitems.get(id)) == null ? void 0 : _subitems$get2.disabled) || false; }, [subitems]); const getItemAsString = React.useCallback(id => { var _subitems$get3, _subitems$get4; return ((_subitems$get3 = subitems.get(id)) == null ? void 0 : _subitems$get3.label) || ((_subitems$get4 = subitems.get(id)) == null || (_subitems$get4 = _subitems$get4.ref.current) == null ? void 0 : _subitems$get4.innerText); }, [subitems]); const reducerActionContext = React.useMemo(() => ({ listboxRef: rootRef }), [rootRef]); const { dispatch: listDispatch, getRootProps: getListRootProps, contextValue: listContextValue, state: { highlightedValue }, rootRef: mergedListRef } = useList({ disabledItemsFocusable, disableListWrap, focusManagement: 'DOM', getItemDomElement, getInitialState: () => ({ selectedValues: [], highlightedValue: null }), isItemDisabled, items: subitemKeys, getItemAsString, rootRef: handleRef, onItemsChange, reducerActionContext, selectionMode: 'none', stateReducer: menuReducer, componentName }); useEnhancedEffect(() => { registerPopup(listboxId); }, [listboxId, registerPopup]); useEnhancedEffect(() => { if (open && (changeReason == null ? void 0 : changeReason.type) === 'keydown' && changeReason.key === 'ArrowUp') { listDispatch({ type: ListActionTypes.highlightLast, event: changeReason }); } }, [open, changeReason, listDispatch]); React.useEffect(() => { if (open && autoFocus && highlightedValue && !isInitiallyOpen.current) { var _subitems$get5; (_subitems$get5 = subitems.get(highlightedValue)) == null || (_subitems$get5 = _subitems$get5.ref) == null || (_subitems$get5 = _subitems$get5.current) == null || _subitems$get5.focus(); } }, [open, autoFocus, highlightedValue, subitems, subitemKeys]); React.useEffect(() => { var _rootRef$current; // set focus to the highlighted item (but prevent stealing focus from other elements on the page) if ((_rootRef$current = rootRef.current) != null && _rootRef$current.contains(document.activeElement) && highlightedValue !== null) { var _subitems$get6; subitems == null || (_subitems$get6 = subitems.get(highlightedValue)) == null || (_subitems$get6 = _subitems$get6.ref.current) == null || _subitems$get6.focus(); } }, [highlightedValue, subitems]); const createHandleBlur = otherHandlers => event => { var _otherHandlers$onBlur, _rootRef$current2; (_otherHandlers$onBlur = otherHandlers.onBlur) == null || _otherHandlers$onBlur.call(otherHandlers, event); if (event.defaultMuiPrevented) { return; } if ((_rootRef$current2 = rootRef.current) != null && _rootRef$current2.contains(event.relatedTarget) || event.relatedTarget === triggerElement) { return; } menuDispatch({ type: DropdownActionTypes.blur, event }); }; const createHandleKeyDown = otherHandlers => event => { var _otherHandlers$onKeyD; (_otherHandlers$onKeyD = otherHandlers.onKeyDown) == null || _otherHandlers$onKeyD.call(otherHandlers, event); if (event.defaultMuiPrevented) { return; } if (event.key === 'Escape') { menuDispatch({ type: DropdownActionTypes.escapeKeyDown, event }); } }; const getOwnListboxHandlers = (otherHandlers = {}) => ({ onBlur: createHandleBlur(otherHandlers), onKeyDown: createHandleKeyDown(otherHandlers) }); const getListboxProps = (externalProps = {}) => { const getCombinedRootProps = combineHooksSlotProps(getOwnListboxHandlers, getListRootProps); const externalEventHandlers = extractEventHandlers(externalProps); return _extends({}, externalProps, externalEventHandlers, getCombinedRootProps(externalEventHandlers), { id: listboxId, role: 'menu' }); }; React.useDebugValue({ subitems, highlightedValue }); return { contextValue: _extends({}, compoundComponentContextValue, listContextValue), dispatch: listDispatch, getListboxProps, highlightedValue, listboxRef: mergedListRef, menuItems: subitems, open, triggerElement }; }