1 | import _extends from "@babel/runtime/helpers/esm/extends";
|
2 | import * as React from 'react';
|
3 | import { unstable_useForkRef as useForkRef } from '@mui/utils';
|
4 | import useList from '../useList';
|
5 | import { useCompoundParent } from '../utils/useCompound';
|
6 | import menuReducer from './menuReducer';
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export default function useMenu(parameters = {}) {
|
19 | const {
|
20 | defaultOpen,
|
21 | listboxRef: listboxRefProp,
|
22 | open: openProp,
|
23 | onOpenChange
|
24 | } = parameters;
|
25 | const listboxRef = React.useRef(null);
|
26 | const handleRef = useForkRef(listboxRef, listboxRefProp);
|
27 | const {
|
28 | subitems,
|
29 | contextValue: compoundComponentContextValue
|
30 | } = useCompoundParent();
|
31 | const subitemKeys = React.useMemo(() => Array.from(subitems.keys()), [subitems]);
|
32 | const getItemDomElement = React.useCallback(itemId => {
|
33 | if (itemId == null) {
|
34 | return null;
|
35 | }
|
36 | return subitems.get(itemId)?.ref.current ?? null;
|
37 | }, [subitems]);
|
38 | const controlledProps = React.useMemo(() => ({
|
39 | open: openProp
|
40 | }), [openProp]);
|
41 | const stateChangeHandler = React.useCallback((event, field, fieldValue, reason, state) => {
|
42 | if (field === 'open') {
|
43 | onOpenChange?.(fieldValue);
|
44 | if (fieldValue === true && state.highlightedValue !== null) {
|
45 | subitems.get(state.highlightedValue)?.ref.current?.focus();
|
46 | }
|
47 | }
|
48 | }, [onOpenChange, subitems]);
|
49 | const {
|
50 | dispatch,
|
51 | getRootProps,
|
52 | contextValue: listContextValue,
|
53 | state: {
|
54 | open,
|
55 | highlightedValue
|
56 | },
|
57 | rootRef: mergedListRef
|
58 | } = useList({
|
59 | controlledProps,
|
60 | disabledItemsFocusable: true,
|
61 | focusManagement: 'DOM',
|
62 | getItemDomElement,
|
63 | getInitialState: () => ({
|
64 | selectedValues: [],
|
65 | highlightedValue: null,
|
66 | open: defaultOpen ?? false
|
67 | }),
|
68 | isItemDisabled: id => subitems?.get(id)?.disabled || false,
|
69 | items: subitemKeys,
|
70 | getItemAsString: id => subitems.get(id)?.label || subitems.get(id)?.ref.current?.innerText,
|
71 | rootRef: handleRef,
|
72 | onStateChange: stateChangeHandler,
|
73 | reducerActionContext: {
|
74 | listboxRef
|
75 | },
|
76 | selectionMode: 'none',
|
77 | stateReducer: menuReducer
|
78 | });
|
79 | React.useEffect(() => {
|
80 | if (open && highlightedValue === subitemKeys[0]) {
|
81 | subitems.get(subitemKeys[0])?.ref?.current?.focus();
|
82 | }
|
83 | }, [open, highlightedValue, subitems, subitemKeys]);
|
84 | React.useEffect(() => {
|
85 |
|
86 | if (listboxRef.current?.contains(document.activeElement) && highlightedValue !== null) {
|
87 | subitems?.get(highlightedValue)?.ref.current?.focus();
|
88 | }
|
89 | }, [highlightedValue, subitems]);
|
90 | const getListboxProps = (otherHandlers = {}) => {
|
91 | const rootProps = getRootProps(otherHandlers);
|
92 | return _extends({}, otherHandlers, rootProps, {
|
93 | role: 'menu'
|
94 | });
|
95 | };
|
96 | React.useDebugValue({
|
97 | subitems,
|
98 | highlightedValue
|
99 | });
|
100 | return {
|
101 | contextValue: _extends({}, compoundComponentContextValue, listContextValue),
|
102 | dispatch,
|
103 | getListboxProps,
|
104 | highlightedValue,
|
105 | listboxRef: mergedListRef,
|
106 | menuItems: subitems,
|
107 | open
|
108 | };
|
109 | } |
\ | No newline at end of file |