@itwin/itwinui-react 3.17.1 → 3.17.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/DEV-cjs/core/Dialog/DialogMain.js +1 -1
  3. package/DEV-cjs/core/DropdownMenu/DropdownMenu.js +55 -27
  4. package/DEV-cjs/core/Menu/Menu.js +64 -45
  5. package/DEV-cjs/core/Menu/MenuItem.js +6 -0
  6. package/DEV-cjs/core/Tile/Tile.js +25 -27
  7. package/DEV-cjs/styles.js +1 -1
  8. package/DEV-cjs/utils/components/FocusTrap.js +23 -18
  9. package/DEV-esm/core/Dialog/DialogMain.js +1 -1
  10. package/DEV-esm/core/DropdownMenu/DropdownMenu.js +40 -24
  11. package/DEV-esm/core/Menu/Menu.js +57 -42
  12. package/DEV-esm/core/Menu/MenuItem.js +9 -0
  13. package/DEV-esm/core/Tile/Tile.js +29 -28
  14. package/DEV-esm/styles.js +1 -1
  15. package/DEV-esm/utils/components/FocusTrap.js +23 -18
  16. package/cjs/core/Dialog/DialogMain.js +1 -1
  17. package/cjs/core/DropdownMenu/DropdownMenu.d.ts +10 -0
  18. package/cjs/core/DropdownMenu/DropdownMenu.js +55 -27
  19. package/cjs/core/Menu/Menu.d.ts +9 -1
  20. package/cjs/core/Menu/Menu.js +64 -45
  21. package/cjs/core/Menu/MenuItem.js +6 -0
  22. package/cjs/core/Tile/Tile.js +25 -27
  23. package/cjs/styles.js +1 -1
  24. package/cjs/utils/components/FocusTrap.js +23 -18
  25. package/esm/core/Dialog/DialogMain.js +1 -1
  26. package/esm/core/DropdownMenu/DropdownMenu.d.ts +10 -0
  27. package/esm/core/DropdownMenu/DropdownMenu.js +40 -24
  28. package/esm/core/Menu/Menu.d.ts +9 -1
  29. package/esm/core/Menu/Menu.js +57 -42
  30. package/esm/core/Menu/MenuItem.js +9 -0
  31. package/esm/core/Tile/Tile.js +29 -28
  32. package/esm/styles.js +1 -1
  33. package/esm/utils/components/FocusTrap.js +23 -18
  34. package/package.json +1 -1
  35. package/styles.css +11 -11
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.17.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2452](https://github.com/iTwin/iTwinUI/pull/2452): Fixed bug where nested `MenuItem`s in `Tile.MoreOptions` were not closing when clicked.
8
+ - [#2455](https://github.com/iTwin/iTwinUI/pull/2455): Submenus will now correctly portal to the same place as their parent menu (E.g. `DropdownMenu`, `SplitButton`)
9
+ - [#2457](https://github.com/iTwin/iTwinUI/pull/2457): Fixed bug in `ExpandableBlock` where cursor was `pointer` even when it was disabled.
10
+
11
+ ## 3.17.2
12
+
13
+ ### Patch Changes
14
+
15
+ - [#2442](https://github.com/iTwin/iTwinUI/pull/2442): Removed a leftover `@layer` name, which was originally intended to support _very_ old versions of iTwinUI.
16
+ - [#2443](https://github.com/iTwin/iTwinUI/pull/2443): Fixed bug in `Modal` where focus was sometimes jumping from a modal child to the modal itself.
17
+ - [#2431](https://github.com/iTwin/iTwinUI/pull/2431): Force text wrapping for long words. Affected components: `Text`, `NonIdealState`, `Stepper`, `WorkflowDiagram`.
18
+ - [#2446](https://github.com/iTwin/iTwinUI/pull/2446): Fixed background color in menus when the [theme bridge](https://github.com/iTwin/iTwinUI/wiki/iTwinUI-v5-theme-bridge) is enabled.
19
+
3
20
  ## 3.17.1
4
21
 
5
22
  ### Patch Changes
@@ -107,7 +107,7 @@ const DialogMain = _react.forwardRef((props, ref) => {
107
107
  dialogRef.current?.focus({
108
108
  preventScroll: true,
109
109
  });
110
- }, [dialogRef, previousFocusedElement, setFocus]);
110
+ }, [setFocus]);
111
111
  let beforeClose = _react.useCallback(() => {
112
112
  if (
113
113
  dialogRef.current?.contains(
@@ -2,11 +2,23 @@
2
2
  Object.defineProperty(exports, '__esModule', {
3
3
  value: true,
4
4
  });
5
- Object.defineProperty(exports, 'DropdownMenu', {
6
- enumerable: true,
7
- get: function () {
5
+ function _export(target, all) {
6
+ for (var name in all)
7
+ Object.defineProperty(target, name, {
8
+ enumerable: true,
9
+ get: all[name],
10
+ });
11
+ }
12
+ _export(exports, {
13
+ DropdownMenu: function () {
8
14
  return DropdownMenu;
9
15
  },
16
+ DropdownMenuCloseOnClickContext: function () {
17
+ return DropdownMenuCloseOnClickContext;
18
+ },
19
+ DropdownMenuContext: function () {
20
+ return DropdownMenuContext;
21
+ },
10
22
  });
11
23
  const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
12
24
  const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react'));
@@ -42,34 +54,50 @@ const DropdownMenuContent = _react.forwardRef((props, forwardedRef) => {
42
54
  visibleProp,
43
55
  onVisibleChange,
44
56
  );
57
+ let close = _react.useCallback(() => {
58
+ setVisible(false);
59
+ }, [setVisible]);
45
60
  let menuContent = _react.useMemo(() => {
46
- if ('function' == typeof menuItems)
47
- return menuItems(() => setVisible(false));
61
+ if ('function' == typeof menuItems) return menuItems(close);
48
62
  return menuItems;
49
- }, [menuItems, setVisible]);
63
+ }, [close, menuItems]);
64
+ let dropdownMenuContextValue = _react.useMemo(
65
+ () => ({
66
+ close,
67
+ }),
68
+ [close],
69
+ );
50
70
  return _react.createElement(
51
- _Menu.Menu,
71
+ DropdownMenuContext.Provider,
52
72
  {
53
- trigger: children,
54
- onKeyDown: (0, _index.mergeEventHandlers)(props.onKeyDown, (e) => {
55
- if (e.defaultPrevented) return;
56
- if ('Tab' === e.key) setVisible(false);
57
- }),
58
- role: role,
59
- ref: forwardedRef,
60
- portal: portal,
61
- popoverProps: _react.useMemo(
62
- () => ({
63
- placement,
64
- matchWidth,
65
- visible,
66
- onVisibleChange: setVisible,
67
- middleware,
68
- }),
69
- [matchWidth, middleware, placement, setVisible, visible],
70
- ),
71
- ...rest,
73
+ value: dropdownMenuContextValue,
72
74
  },
73
- menuContent,
75
+ _react.createElement(
76
+ _Menu.Menu,
77
+ {
78
+ trigger: children,
79
+ onKeyDown: (0, _index.mergeEventHandlers)(props.onKeyDown, (e) => {
80
+ if (e.defaultPrevented) return;
81
+ if ('Tab' === e.key) setVisible(false);
82
+ }),
83
+ role: role,
84
+ ref: forwardedRef,
85
+ portal: portal,
86
+ popoverProps: _react.useMemo(
87
+ () => ({
88
+ placement,
89
+ matchWidth,
90
+ visible,
91
+ onVisibleChange: setVisible,
92
+ middleware,
93
+ }),
94
+ [matchWidth, middleware, placement, setVisible, visible],
95
+ ),
96
+ ...rest,
97
+ },
98
+ menuContent,
99
+ ),
74
100
  );
75
101
  });
102
+ const DropdownMenuContext = _react.createContext(void 0);
103
+ const DropdownMenuCloseOnClickContext = _react.createContext(void 0);
@@ -16,6 +16,9 @@ _export(exports, {
16
16
  MenuContext: function () {
17
17
  return MenuContext;
18
18
  },
19
+ MenuPortalContext: function () {
20
+ return MenuPortalContext;
21
+ },
19
22
  });
20
23
  const _interop_require_default = require('@swc/helpers/_/_interop_require_default');
21
24
  const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
@@ -31,11 +34,13 @@ const Menu = _react.forwardRef((props, ref) => {
31
34
  className,
32
35
  trigger,
33
36
  positionReference,
34
- portal = true,
37
+ portal: portalProp,
35
38
  popoverProps: popoverPropsProp,
36
39
  children,
37
40
  ...rest
38
41
  } = props;
42
+ let menuPortalContext = _react.useContext(MenuPortalContext);
43
+ let portal = portalProp ?? menuPortalContext;
39
44
  let tree = (0, _react1.useFloatingTree)();
40
45
  let nodeId = (0, _react1.useFloatingNodeId)();
41
46
  let parentId = (0, _react1.useFloatingParentNodeId)();
@@ -134,35 +139,39 @@ const Menu = _react.forwardRef((props, ref) => {
134
139
  () => void 0,
135
140
  () => void 0,
136
141
  );
137
- let popoverGetItemProps = ({ focusableItemIndex, userProps }) =>
138
- getItemProps({
139
- ...userProps,
140
- tabIndex:
141
- null != activeIndex &&
142
- activeIndex >= 0 &&
143
- null != focusableItemIndex &&
144
- focusableItemIndex >= 0 &&
145
- activeIndex === focusableItemIndex
146
- ? 0
147
- : -1,
148
- onFocus: (0, _index.mergeEventHandlers)(userProps?.onFocus, () => {
149
- queueMicrotask(() => {
150
- setHasFocusedNodeInSubmenu(true);
151
- });
152
- tree?.events.emit('onNodeFocused', {
153
- nodeId: nodeId,
154
- parentId: parentId,
155
- });
142
+ let popoverGetItemProps = _react.useCallback(
143
+ ({ focusableItemIndex, userProps }) =>
144
+ getItemProps({
145
+ ...userProps,
146
+ tabIndex:
147
+ null != activeIndex &&
148
+ activeIndex >= 0 &&
149
+ null != focusableItemIndex &&
150
+ focusableItemIndex >= 0 &&
151
+ activeIndex === focusableItemIndex
152
+ ? 0
153
+ : -1,
154
+ onFocus: (0, _index.mergeEventHandlers)(userProps?.onFocus, () => {
155
+ queueMicrotask(() => {
156
+ setHasFocusedNodeInSubmenu(true);
157
+ });
158
+ tree?.events.emit('onNodeFocused', {
159
+ nodeId: nodeId,
160
+ parentId: parentId,
161
+ });
162
+ }),
163
+ onMouseEnter: (0, _index.mergeEventHandlers)(
164
+ userProps?.onMouseEnter,
165
+ (event) => {
166
+ if (null != focusableItemIndex && focusableItemIndex >= 0)
167
+ setActiveIndex(focusableItemIndex);
168
+ if (event.target === event.currentTarget)
169
+ event.currentTarget.focus();
170
+ },
171
+ ),
156
172
  }),
157
- onMouseEnter: (0, _index.mergeEventHandlers)(
158
- userProps?.onMouseEnter,
159
- (event) => {
160
- if (null != focusableItemIndex && focusableItemIndex >= 0)
161
- setActiveIndex(focusableItemIndex);
162
- if (event.target === event.currentTarget) event.currentTarget.focus();
163
- },
164
- ),
165
- });
173
+ [activeIndex, getItemProps, nodeId, parentId, tree?.events],
174
+ );
166
175
  let reference = (0, _index.cloneElementWithRef)(trigger, (triggerChild) =>
167
176
  getReferenceProps(
168
177
  popover.getReferenceProps({
@@ -201,28 +210,38 @@ const Menu = _react.forwardRef((props, ref) => {
201
210
  _react.createElement(
202
211
  MenuContext.Provider,
203
212
  {
204
- value: {
205
- popoverGetItemProps,
206
- focusableElements,
207
- },
213
+ value: _react.useMemo(
214
+ () => ({
215
+ popoverGetItemProps,
216
+ focusableElements,
217
+ }),
218
+ [focusableElements, popoverGetItemProps],
219
+ ),
208
220
  },
209
221
  _react.createElement(
210
- _Popover.PopoverOpenContext.Provider,
222
+ MenuPortalContext.Provider,
211
223
  {
212
- value: popover.open,
224
+ value: portal,
213
225
  },
214
- reference,
226
+ _react.createElement(
227
+ _Popover.PopoverOpenContext.Provider,
228
+ {
229
+ value: popover.open,
230
+ },
231
+ reference,
232
+ ),
233
+ null != tree
234
+ ? _react.createElement(
235
+ _react1.FloatingNode,
236
+ {
237
+ id: nodeId,
238
+ },
239
+ floating,
240
+ )
241
+ : floating,
215
242
  ),
216
- null != tree
217
- ? _react.createElement(
218
- _react1.FloatingNode,
219
- {
220
- id: nodeId,
221
- },
222
- floating,
223
- )
224
- : floating,
225
243
  ),
226
244
  );
227
245
  });
228
246
  const MenuContext = _react.createContext(void 0);
247
+ const MenuPortalContext = _react.createContext(void 0);
@@ -17,6 +17,7 @@ const _ListItem = require('../List/ListItem.js');
17
17
  const _classnames = /*#__PURE__*/ _interop_require_default._(
18
18
  require('classnames'),
19
19
  );
20
+ const _DropdownMenu = require('../DropdownMenu/DropdownMenu.js');
20
21
  const MenuItem = _react.forwardRef((props, forwardedRef) => {
21
22
  let {
22
23
  className,
@@ -41,6 +42,10 @@ const MenuItem = _react.forwardRef((props, forwardedRef) => {
41
42
  'Passing a non-empty submenuItems array and onClick to MenuItem at the same time is not supported. This is because when a non empty submenuItems array is passed, clicking the MenuItem toggles the submenu visibility.',
42
43
  );
43
44
  let parentMenu = _react.useContext(_Menu.MenuContext);
45
+ let dropdownMenu = _react.useContext(_DropdownMenu.DropdownMenuContext);
46
+ let shouldCloseMenuOnClick = _react.useContext(
47
+ _DropdownMenu.DropdownMenuCloseOnClickContext,
48
+ );
44
49
  let menuItemRef = _react.useRef(null);
45
50
  let submenuId = (0, _index.useId)();
46
51
  let popoverProps = _react.useMemo(
@@ -59,6 +64,7 @@ const MenuItem = _react.forwardRef((props, forwardedRef) => {
59
64
  );
60
65
  let onClick = () => {
61
66
  if (disabled) return;
67
+ if (shouldCloseMenuOnClick) dropdownMenu?.close();
62
68
  onClickProp?.(value);
63
69
  };
64
70
  let handlers = {
@@ -211,41 +211,39 @@ const TileMoreOptions = _react.forwardRef((props, forwardedRef) => {
211
211
  let { className, children = [], buttonProps, ...rest } = props;
212
212
  let [isMenuVisible, setIsMenuVisible] = _react.useState(false);
213
213
  return _react.createElement(
214
- _index.Box,
214
+ _DropdownMenu.DropdownMenuCloseOnClickContext.Provider,
215
215
  {
216
- className: (0, _classnames.default)(
217
- 'iui-tile-more-options',
218
- {
219
- 'iui-visible': isMenuVisible,
220
- },
221
- className,
222
- ),
223
- ref: forwardedRef,
224
- ...rest,
216
+ value: true,
225
217
  },
226
218
  _react.createElement(
227
- _DropdownMenu.DropdownMenu,
219
+ _index.Box,
228
220
  {
229
- onVisibleChange: setIsMenuVisible,
230
- menuItems: (close) =>
231
- children?.map((option) =>
232
- _react.cloneElement(option, {
233
- onClick: (value) => {
234
- close();
235
- option.props.onClick?.(value);
236
- },
237
- }),
238
- ),
221
+ className: (0, _classnames.default)(
222
+ 'iui-tile-more-options',
223
+ {
224
+ 'iui-visible': isMenuVisible,
225
+ },
226
+ className,
227
+ ),
228
+ ref: forwardedRef,
229
+ ...rest,
239
230
  },
240
231
  _react.createElement(
241
- _IconButton.IconButton,
232
+ _DropdownMenu.DropdownMenu,
242
233
  {
243
- styleType: 'borderless',
244
- size: 'small',
245
- 'aria-label': 'More options',
246
- ...buttonProps,
234
+ onVisibleChange: setIsMenuVisible,
235
+ menuItems: children,
247
236
  },
248
- _react.createElement(_index.SvgMore, null),
237
+ _react.createElement(
238
+ _IconButton.IconButton,
239
+ {
240
+ styleType: 'borderless',
241
+ size: 'small',
242
+ 'aria-label': 'More options',
243
+ ...buttonProps,
244
+ },
245
+ _react.createElement(_index.SvgMore, null),
246
+ ),
249
247
  ),
250
248
  ),
251
249
  );
package/DEV-cjs/styles.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3
- const e = '3.17.1';
3
+ const e = '3.17.3';
4
4
  const u = new Proxy(
5
5
  {},
6
6
  {
@@ -11,37 +11,42 @@ Object.defineProperty(exports, 'FocusTrap', {
11
11
  const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
12
12
  const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react'));
13
13
  const _focusable = require('../functions/focusable.js');
14
- const _react1 = require('../functions/react.js');
15
14
  const FocusTrap = (props) => {
16
15
  let { children } = props;
17
- let childRef = _react.useRef(void 0);
18
- let getFirstLastFocusables = () => {
19
- let elements = (0, _focusable.getTabbableElements)(childRef.current);
16
+ let firstFocusTrapRef = _react.useRef(null);
17
+ let getFirstLastFocusables = _react.useCallback(() => {
18
+ let childrenElement = firstFocusTrapRef.current?.nextElementSibling;
19
+ let elements = (0, _focusable.getTabbableElements)(childrenElement);
20
20
  let firstElement = elements[0];
21
21
  let lastElement = elements[(elements.length || 1) - 1];
22
22
  return [firstElement, lastElement];
23
- };
24
- let onFirstFocus = (event) => {
25
- let [firstElement, lastElement] = getFirstLastFocusables();
26
- if (event.relatedTarget === firstElement) lastElement?.focus();
27
- else firstElement?.focus();
28
- };
29
- let onLastFocus = (event) => {
30
- let [firstElement, lastElement] = getFirstLastFocusables();
31
- if (event.relatedTarget === lastElement) firstElement?.focus();
32
- else lastElement?.focus();
33
- };
23
+ }, []);
24
+ let onFirstFocus = _react.useCallback(
25
+ (event) => {
26
+ let [firstElement, lastElement] = getFirstLastFocusables();
27
+ if (event.relatedTarget === firstElement) lastElement?.focus();
28
+ else firstElement?.focus();
29
+ },
30
+ [getFirstLastFocusables],
31
+ );
32
+ let onLastFocus = _react.useCallback(
33
+ (event) => {
34
+ let [firstElement, lastElement] = getFirstLastFocusables();
35
+ if (event.relatedTarget === lastElement) firstElement?.focus();
36
+ else lastElement?.focus();
37
+ },
38
+ [getFirstLastFocusables],
39
+ );
34
40
  return _react.createElement(
35
41
  _react.Fragment,
36
42
  null,
37
43
  _react.createElement('div', {
44
+ ref: firstFocusTrapRef,
38
45
  tabIndex: 0,
39
46
  onFocus: onFirstFocus,
40
47
  'aria-hidden': true,
41
48
  }),
42
- (0, _react1.cloneElementWithRef)(children, () => ({
43
- ref: childRef,
44
- })),
49
+ children,
45
50
  _react.createElement('div', {
46
51
  tabIndex: 0,
47
52
  onFocus: onLastFocus,
@@ -101,7 +101,7 @@ export const DialogMain = React.forwardRef((props, ref) => {
101
101
  dialogRef.current?.focus({
102
102
  preventScroll: true,
103
103
  });
104
- }, [dialogRef, previousFocusedElement, setFocus]);
104
+ }, [setFocus]);
105
105
  let beforeClose = React.useCallback(() => {
106
106
  if (
107
107
  dialogRef.current?.contains(
@@ -31,34 +31,50 @@ let DropdownMenuContent = React.forwardRef((props, forwardedRef) => {
31
31
  visibleProp,
32
32
  onVisibleChange,
33
33
  );
34
+ let close = React.useCallback(() => {
35
+ setVisible(false);
36
+ }, [setVisible]);
34
37
  let menuContent = React.useMemo(() => {
35
- if ('function' == typeof menuItems)
36
- return menuItems(() => setVisible(false));
38
+ if ('function' == typeof menuItems) return menuItems(close);
37
39
  return menuItems;
38
- }, [menuItems, setVisible]);
40
+ }, [close, menuItems]);
41
+ let dropdownMenuContextValue = React.useMemo(
42
+ () => ({
43
+ close,
44
+ }),
45
+ [close],
46
+ );
39
47
  return React.createElement(
40
- Menu,
48
+ DropdownMenuContext.Provider,
41
49
  {
42
- trigger: children,
43
- onKeyDown: mergeEventHandlers(props.onKeyDown, (e) => {
44
- if (e.defaultPrevented) return;
45
- if ('Tab' === e.key) setVisible(false);
46
- }),
47
- role: role,
48
- ref: forwardedRef,
49
- portal: portal,
50
- popoverProps: React.useMemo(
51
- () => ({
52
- placement,
53
- matchWidth,
54
- visible,
55
- onVisibleChange: setVisible,
56
- middleware,
57
- }),
58
- [matchWidth, middleware, placement, setVisible, visible],
59
- ),
60
- ...rest,
50
+ value: dropdownMenuContextValue,
61
51
  },
62
- menuContent,
52
+ React.createElement(
53
+ Menu,
54
+ {
55
+ trigger: children,
56
+ onKeyDown: mergeEventHandlers(props.onKeyDown, (e) => {
57
+ if (e.defaultPrevented) return;
58
+ if ('Tab' === e.key) setVisible(false);
59
+ }),
60
+ role: role,
61
+ ref: forwardedRef,
62
+ portal: portal,
63
+ popoverProps: React.useMemo(
64
+ () => ({
65
+ placement,
66
+ matchWidth,
67
+ visible,
68
+ onVisibleChange: setVisible,
69
+ middleware,
70
+ }),
71
+ [matchWidth, middleware, placement, setVisible, visible],
72
+ ),
73
+ ...rest,
74
+ },
75
+ menuContent,
76
+ ),
63
77
  );
64
78
  });
79
+ export const DropdownMenuContext = React.createContext(void 0);
80
+ export const DropdownMenuCloseOnClickContext = React.createContext(void 0);
@@ -25,11 +25,13 @@ export const Menu = React.forwardRef((props, ref) => {
25
25
  className,
26
26
  trigger,
27
27
  positionReference,
28
- portal = true,
28
+ portal: portalProp,
29
29
  popoverProps: popoverPropsProp,
30
30
  children,
31
31
  ...rest
32
32
  } = props;
33
+ let menuPortalContext = React.useContext(MenuPortalContext);
34
+ let portal = portalProp ?? menuPortalContext;
33
35
  let tree = useFloatingTree();
34
36
  let nodeId = useFloatingNodeId();
35
37
  let parentId = useFloatingParentNodeId();
@@ -125,32 +127,35 @@ export const Menu = React.forwardRef((props, ref) => {
125
127
  () => void 0,
126
128
  () => void 0,
127
129
  );
128
- let popoverGetItemProps = ({ focusableItemIndex, userProps }) =>
129
- getItemProps({
130
- ...userProps,
131
- tabIndex:
132
- null != activeIndex &&
133
- activeIndex >= 0 &&
134
- null != focusableItemIndex &&
135
- focusableItemIndex >= 0 &&
136
- activeIndex === focusableItemIndex
137
- ? 0
138
- : -1,
139
- onFocus: mergeEventHandlers(userProps?.onFocus, () => {
140
- queueMicrotask(() => {
141
- setHasFocusedNodeInSubmenu(true);
142
- });
143
- tree?.events.emit('onNodeFocused', {
144
- nodeId: nodeId,
145
- parentId: parentId,
146
- });
130
+ let popoverGetItemProps = React.useCallback(
131
+ ({ focusableItemIndex, userProps }) =>
132
+ getItemProps({
133
+ ...userProps,
134
+ tabIndex:
135
+ null != activeIndex &&
136
+ activeIndex >= 0 &&
137
+ null != focusableItemIndex &&
138
+ focusableItemIndex >= 0 &&
139
+ activeIndex === focusableItemIndex
140
+ ? 0
141
+ : -1,
142
+ onFocus: mergeEventHandlers(userProps?.onFocus, () => {
143
+ queueMicrotask(() => {
144
+ setHasFocusedNodeInSubmenu(true);
145
+ });
146
+ tree?.events.emit('onNodeFocused', {
147
+ nodeId: nodeId,
148
+ parentId: parentId,
149
+ });
150
+ }),
151
+ onMouseEnter: mergeEventHandlers(userProps?.onMouseEnter, (event) => {
152
+ if (null != focusableItemIndex && focusableItemIndex >= 0)
153
+ setActiveIndex(focusableItemIndex);
154
+ if (event.target === event.currentTarget) event.currentTarget.focus();
155
+ }),
147
156
  }),
148
- onMouseEnter: mergeEventHandlers(userProps?.onMouseEnter, (event) => {
149
- if (null != focusableItemIndex && focusableItemIndex >= 0)
150
- setActiveIndex(focusableItemIndex);
151
- if (event.target === event.currentTarget) event.currentTarget.focus();
152
- }),
153
- });
157
+ [activeIndex, getItemProps, nodeId, parentId, tree?.events],
158
+ );
154
159
  let reference = cloneElementWithRef(trigger, (triggerChild) =>
155
160
  getReferenceProps(
156
161
  popover.getReferenceProps({
@@ -189,28 +194,38 @@ export const Menu = React.forwardRef((props, ref) => {
189
194
  React.createElement(
190
195
  MenuContext.Provider,
191
196
  {
192
- value: {
193
- popoverGetItemProps,
194
- focusableElements,
195
- },
197
+ value: React.useMemo(
198
+ () => ({
199
+ popoverGetItemProps,
200
+ focusableElements,
201
+ }),
202
+ [focusableElements, popoverGetItemProps],
203
+ ),
196
204
  },
197
205
  React.createElement(
198
- PopoverOpenContext.Provider,
206
+ MenuPortalContext.Provider,
199
207
  {
200
- value: popover.open,
208
+ value: portal,
201
209
  },
202
- reference,
210
+ React.createElement(
211
+ PopoverOpenContext.Provider,
212
+ {
213
+ value: popover.open,
214
+ },
215
+ reference,
216
+ ),
217
+ null != tree
218
+ ? React.createElement(
219
+ FloatingNode,
220
+ {
221
+ id: nodeId,
222
+ },
223
+ floating,
224
+ )
225
+ : floating,
203
226
  ),
204
- null != tree
205
- ? React.createElement(
206
- FloatingNode,
207
- {
208
- id: nodeId,
209
- },
210
- floating,
211
- )
212
- : floating,
213
227
  ),
214
228
  );
215
229
  });
216
230
  export const MenuContext = React.createContext(void 0);
231
+ export const MenuPortalContext = React.createContext(void 0);