@carbon/react 1.78.2 → 1.79.0

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 (253) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +882 -882
  2. package/es/components/Accordion/AccordionItem.js +2 -2
  3. package/es/components/Button/Button.d.ts +2 -3
  4. package/es/components/Button/Button.js +29 -19
  5. package/es/components/Button/ButtonBase.js +3 -1
  6. package/es/components/ChatButton/ChatButton.d.ts +2 -3
  7. package/es/components/ChatButton/ChatButton.js +1 -2
  8. package/es/components/ComboBox/ComboBox.js +34 -24
  9. package/es/components/ComposedModal/ComposedModal.js +65 -51
  10. package/es/components/ContainedList/ContainedListItem/ContainedListItem.d.ts +2 -2
  11. package/es/components/ContainedList/ContainedListItem/ContainedListItem.js +1 -1
  12. package/es/components/ContentSwitcher/ContentSwitcher.js +3 -3
  13. package/es/components/DataTable/TableBatchAction.d.ts +3 -3
  14. package/es/components/DataTable/TableBatchAction.js +1 -1
  15. package/es/components/DataTable/TableContainer.d.ts +1 -1
  16. package/es/components/DataTable/TableContainer.js +5 -4
  17. package/es/components/DataTable/TableExpandHeader.d.ts +6 -5
  18. package/es/components/DataTable/TableToolbarMenu.d.ts +2 -2
  19. package/es/components/DataTable/TableToolbarMenu.js +1 -1
  20. package/es/components/DatePicker/DatePicker.js +2 -2
  21. package/es/components/DatePicker/plugins/fixEventsPlugin.js +1 -1
  22. package/es/components/Dialog/index.d.ts +42 -4
  23. package/es/components/Dialog/index.js +177 -0
  24. package/es/components/ExpandableSearch/ExpandableSearch.js +2 -2
  25. package/es/components/FeatureFlags/index.d.ts +3 -1
  26. package/es/components/FeatureFlags/index.js +3 -0
  27. package/es/components/FileUploader/FileUploader.d.ts +1 -1
  28. package/es/components/FileUploader/FileUploader.js +2 -2
  29. package/es/components/FileUploader/FileUploaderButton.js +2 -2
  30. package/es/components/FileUploader/FileUploaderDropContainer.d.ts +1 -1
  31. package/es/components/FileUploader/FileUploaderDropContainer.js +6 -4
  32. package/es/components/FileUploader/FileUploaderItem.d.ts +1 -1
  33. package/es/components/FileUploader/FileUploaderItem.js +2 -2
  34. package/es/components/Grid/CSSGrid.js +18 -14
  35. package/es/components/Grid/Column.d.ts +2 -2
  36. package/es/components/Grid/Column.js +7 -8
  37. package/es/components/Grid/FlexGrid.js +7 -6
  38. package/es/components/Grid/GridTypes.d.ts +5 -3
  39. package/es/components/IconButton/index.d.ts +2 -2
  40. package/es/components/IconButton/index.js +4 -4
  41. package/es/components/Layer/index.d.ts +4 -6
  42. package/es/components/Layer/index.js +5 -6
  43. package/es/components/Link/Link.d.ts +2 -3
  44. package/es/components/Link/Link.js +1 -2
  45. package/es/components/ListBox/ListBoxMenuItem.d.ts +3 -3
  46. package/es/components/ListBox/ListBoxMenuItem.js +37 -15
  47. package/es/components/Menu/Menu.js +2 -2
  48. package/es/components/Menu/MenuItem.d.ts +2 -2
  49. package/es/components/Menu/MenuItem.js +3 -3
  50. package/es/components/Modal/Modal.js +121 -49
  51. package/es/components/ModalWrapper/ModalWrapper.js +1 -1
  52. package/es/components/MultiSelect/FilterableMultiSelect.js +3 -3
  53. package/es/components/MultiSelect/MultiSelect.js +2 -2
  54. package/es/components/MultiSelect/index.d.ts +1 -1
  55. package/es/components/MultiSelect/index.js +1 -8
  56. package/es/components/Notification/Notification.d.ts +5 -13
  57. package/es/components/Notification/Notification.js +3 -4
  58. package/es/components/OverflowMenu/OverflowMenu.d.ts +22 -201
  59. package/es/components/OverflowMenu/OverflowMenu.js +269 -338
  60. package/es/components/OverflowMenu/index.d.ts +5 -5
  61. package/es/components/OverflowMenu/index.js +2 -2
  62. package/es/components/OverflowMenu/next/index.d.ts +4 -4
  63. package/es/components/OverflowMenu/next/index.js +1 -1
  64. package/es/components/OverflowMenuItem/OverflowMenuItem.js +2 -2
  65. package/es/components/ProgressIndicator/ProgressIndicator.js +2 -2
  66. package/es/components/RadioTile/RadioTile.js +2 -2
  67. package/es/components/Search/Search.d.ts +2 -3
  68. package/es/components/Search/Search.js +4 -6
  69. package/es/components/Slider/Slider.d.ts +39 -44
  70. package/es/components/Slider/Slider.js +57 -59
  71. package/es/components/Tabs/Tabs.d.ts +3 -6
  72. package/es/components/Tabs/Tabs.js +16 -18
  73. package/es/components/Tag/DismissibleTag.d.ts +3 -5
  74. package/es/components/Tag/DismissibleTag.js +1 -2
  75. package/es/components/Tag/OperationalTag.d.ts +2 -3
  76. package/es/components/Tag/OperationalTag.js +1 -2
  77. package/es/components/Tag/SelectableTag.d.ts +3 -5
  78. package/es/components/Tag/SelectableTag.js +1 -2
  79. package/es/components/Tag/Tag.d.ts +2 -3
  80. package/es/components/Tag/Tag.js +1 -2
  81. package/es/components/Tile/Tile.d.ts +3 -5
  82. package/es/components/Tile/Tile.js +16 -10
  83. package/es/components/Toggletip/index.js +2 -2
  84. package/es/components/Tooltip/DefinitionTooltip.js +2 -2
  85. package/es/components/Tooltip/Tooltip.d.ts +1 -1
  86. package/es/components/Tooltip/Tooltip.js +2 -2
  87. package/es/components/TreeView/TreeNode.d.ts +3 -5
  88. package/es/components/TreeView/TreeNode.js +3 -4
  89. package/es/components/TreeView/TreeView.js +2 -2
  90. package/es/components/UIShell/HeaderContainer.js +2 -2
  91. package/es/components/UIShell/HeaderMenu.js +2 -2
  92. package/es/components/UIShell/HeaderPanel.js +2 -2
  93. package/es/components/UIShell/SideNav.d.ts +1 -1
  94. package/es/components/UIShell/SideNav.js +2 -2
  95. package/es/components/UIShell/SideNavHeader.d.ts +2 -3
  96. package/es/components/UIShell/SideNavHeader.js +1 -2
  97. package/es/components/UIShell/SideNavLink.d.ts +2 -2
  98. package/es/components/UIShell/SideNavLink.js +1 -1
  99. package/es/components/UIShell/SideNavMenu.d.ts +2 -2
  100. package/es/components/UIShell/SideNavMenu.js +3 -3
  101. package/es/components/UIShell/SwitcherItem.js +2 -2
  102. package/es/index.js +1 -1
  103. package/es/internal/FloatingMenu.d.ts +2 -2
  104. package/es/internal/FloatingMenu.js +8 -5
  105. package/es/internal/OptimizedResize.d.ts +18 -0
  106. package/es/internal/OptimizedResize.js +21 -24
  107. package/es/internal/createClassWrapper.d.ts +3 -3
  108. package/es/internal/createClassWrapper.js +4 -4
  109. package/es/internal/keyboard/index.d.ts +9 -0
  110. package/es/internal/keyboard/keys.d.ts +23 -0
  111. package/es/internal/keyboard/keys.js +2 -2
  112. package/es/internal/keyboard/match.d.ts +26 -0
  113. package/es/internal/keyboard/match.js +17 -41
  114. package/es/internal/keyboard/navigation.d.ts +37 -0
  115. package/es/internal/keyboard/navigation.js +15 -27
  116. package/es/internal/useIsomorphicEffect.d.ts +10 -0
  117. package/es/internal/useIsomorphicEffect.js +2 -3
  118. package/es/internal/useMatchMedia.d.ts +8 -0
  119. package/es/internal/useMatchMedia.js +10 -20
  120. package/es/internal/useMergedRefs.js +3 -0
  121. package/es/internal/useNormalizedInputProps.d.ts +52 -0
  122. package/es/internal/useNormalizedInputProps.js +9 -36
  123. package/lib/components/Accordion/AccordionItem.js +2 -2
  124. package/lib/components/Button/Button.d.ts +2 -3
  125. package/lib/components/Button/Button.js +29 -19
  126. package/lib/components/Button/ButtonBase.js +3 -1
  127. package/lib/components/ChatButton/ChatButton.d.ts +2 -3
  128. package/lib/components/ChatButton/ChatButton.js +1 -2
  129. package/lib/components/ComboBox/ComboBox.js +34 -24
  130. package/lib/components/ComposedModal/ComposedModal.js +64 -50
  131. package/lib/components/ContainedList/ContainedListItem/ContainedListItem.d.ts +2 -2
  132. package/lib/components/ContainedList/ContainedListItem/ContainedListItem.js +1 -1
  133. package/lib/components/ContentSwitcher/ContentSwitcher.js +3 -3
  134. package/lib/components/DataTable/TableBatchAction.d.ts +3 -3
  135. package/lib/components/DataTable/TableBatchAction.js +1 -1
  136. package/lib/components/DataTable/TableContainer.d.ts +1 -1
  137. package/lib/components/DataTable/TableContainer.js +5 -4
  138. package/lib/components/DataTable/TableExpandHeader.d.ts +6 -5
  139. package/lib/components/DataTable/TableToolbarMenu.d.ts +2 -2
  140. package/lib/components/DataTable/TableToolbarMenu.js +1 -1
  141. package/lib/components/DatePicker/DatePicker.js +2 -2
  142. package/lib/components/DatePicker/plugins/fixEventsPlugin.js +1 -1
  143. package/lib/components/Dialog/index.d.ts +42 -4
  144. package/lib/components/Dialog/index.js +190 -0
  145. package/lib/components/ExpandableSearch/ExpandableSearch.js +2 -2
  146. package/lib/components/FeatureFlags/index.d.ts +3 -1
  147. package/lib/components/FeatureFlags/index.js +3 -0
  148. package/lib/components/FileUploader/FileUploader.d.ts +1 -1
  149. package/lib/components/FileUploader/FileUploader.js +2 -2
  150. package/lib/components/FileUploader/FileUploaderButton.js +2 -2
  151. package/lib/components/FileUploader/FileUploaderDropContainer.d.ts +1 -1
  152. package/lib/components/FileUploader/FileUploaderDropContainer.js +6 -4
  153. package/lib/components/FileUploader/FileUploaderItem.d.ts +1 -1
  154. package/lib/components/FileUploader/FileUploaderItem.js +2 -2
  155. package/lib/components/Grid/CSSGrid.js +18 -14
  156. package/lib/components/Grid/Column.d.ts +2 -2
  157. package/lib/components/Grid/Column.js +7 -8
  158. package/lib/components/Grid/FlexGrid.js +7 -6
  159. package/lib/components/Grid/GridTypes.d.ts +5 -3
  160. package/lib/components/IconButton/index.d.ts +2 -2
  161. package/lib/components/IconButton/index.js +4 -4
  162. package/lib/components/Layer/index.d.ts +4 -6
  163. package/lib/components/Layer/index.js +5 -6
  164. package/lib/components/Link/Link.d.ts +2 -3
  165. package/lib/components/Link/Link.js +1 -2
  166. package/lib/components/ListBox/ListBoxMenuItem.d.ts +3 -3
  167. package/lib/components/ListBox/ListBoxMenuItem.js +36 -14
  168. package/lib/components/Menu/Menu.js +2 -2
  169. package/lib/components/Menu/MenuItem.d.ts +2 -2
  170. package/lib/components/Menu/MenuItem.js +3 -3
  171. package/lib/components/Modal/Modal.js +123 -51
  172. package/lib/components/ModalWrapper/ModalWrapper.js +1 -1
  173. package/lib/components/MultiSelect/FilterableMultiSelect.js +3 -3
  174. package/lib/components/MultiSelect/MultiSelect.js +2 -2
  175. package/lib/components/MultiSelect/index.d.ts +1 -1
  176. package/lib/components/MultiSelect/index.js +1 -8
  177. package/lib/components/Notification/Notification.d.ts +5 -13
  178. package/lib/components/Notification/Notification.js +3 -4
  179. package/lib/components/OverflowMenu/OverflowMenu.d.ts +22 -201
  180. package/lib/components/OverflowMenu/OverflowMenu.js +268 -336
  181. package/lib/components/OverflowMenu/index.d.ts +5 -5
  182. package/lib/components/OverflowMenu/index.js +2 -2
  183. package/lib/components/OverflowMenu/next/index.d.ts +4 -4
  184. package/lib/components/OverflowMenu/next/index.js +1 -1
  185. package/lib/components/OverflowMenuItem/OverflowMenuItem.js +2 -2
  186. package/lib/components/ProgressIndicator/ProgressIndicator.js +2 -2
  187. package/lib/components/RadioTile/RadioTile.js +2 -2
  188. package/lib/components/Search/Search.d.ts +2 -3
  189. package/lib/components/Search/Search.js +4 -6
  190. package/lib/components/Slider/Slider.d.ts +39 -44
  191. package/lib/components/Slider/Slider.js +57 -59
  192. package/lib/components/Tabs/Tabs.d.ts +3 -6
  193. package/lib/components/Tabs/Tabs.js +16 -18
  194. package/lib/components/Tag/DismissibleTag.d.ts +3 -5
  195. package/lib/components/Tag/DismissibleTag.js +1 -2
  196. package/lib/components/Tag/OperationalTag.d.ts +2 -3
  197. package/lib/components/Tag/OperationalTag.js +1 -2
  198. package/lib/components/Tag/SelectableTag.d.ts +3 -5
  199. package/lib/components/Tag/SelectableTag.js +1 -2
  200. package/lib/components/Tag/Tag.d.ts +2 -3
  201. package/lib/components/Tag/Tag.js +1 -2
  202. package/lib/components/Tile/Tile.d.ts +3 -5
  203. package/lib/components/Tile/Tile.js +16 -10
  204. package/lib/components/Toggletip/index.js +2 -2
  205. package/lib/components/Tooltip/DefinitionTooltip.js +2 -2
  206. package/lib/components/Tooltip/Tooltip.d.ts +1 -1
  207. package/lib/components/Tooltip/Tooltip.js +2 -2
  208. package/lib/components/TreeView/TreeNode.d.ts +3 -5
  209. package/lib/components/TreeView/TreeNode.js +3 -4
  210. package/lib/components/TreeView/TreeView.js +2 -2
  211. package/lib/components/UIShell/HeaderContainer.js +2 -2
  212. package/lib/components/UIShell/HeaderMenu.js +2 -2
  213. package/lib/components/UIShell/HeaderPanel.js +2 -2
  214. package/lib/components/UIShell/SideNav.d.ts +1 -1
  215. package/lib/components/UIShell/SideNav.js +2 -2
  216. package/lib/components/UIShell/SideNavHeader.d.ts +2 -3
  217. package/lib/components/UIShell/SideNavHeader.js +1 -2
  218. package/lib/components/UIShell/SideNavLink.d.ts +2 -2
  219. package/lib/components/UIShell/SideNavLink.js +1 -1
  220. package/lib/components/UIShell/SideNavMenu.d.ts +2 -2
  221. package/lib/components/UIShell/SideNavMenu.js +3 -3
  222. package/lib/components/UIShell/SwitcherItem.js +2 -2
  223. package/lib/index.js +2 -2
  224. package/lib/internal/FloatingMenu.d.ts +2 -2
  225. package/lib/internal/FloatingMenu.js +9 -6
  226. package/lib/internal/OptimizedResize.d.ts +18 -0
  227. package/lib/internal/OptimizedResize.js +21 -24
  228. package/lib/internal/createClassWrapper.d.ts +3 -3
  229. package/lib/internal/createClassWrapper.js +4 -4
  230. package/lib/internal/keyboard/index.d.ts +9 -0
  231. package/lib/internal/keyboard/keys.d.ts +23 -0
  232. package/lib/internal/keyboard/keys.js +2 -2
  233. package/lib/internal/keyboard/match.d.ts +26 -0
  234. package/lib/internal/keyboard/match.js +17 -41
  235. package/lib/internal/keyboard/navigation.d.ts +37 -0
  236. package/lib/internal/keyboard/navigation.js +15 -27
  237. package/lib/internal/useIsomorphicEffect.d.ts +10 -0
  238. package/lib/internal/useIsomorphicEffect.js +2 -3
  239. package/lib/internal/useMatchMedia.d.ts +8 -0
  240. package/lib/internal/useMatchMedia.js +10 -20
  241. package/lib/internal/useMergedRefs.js +3 -0
  242. package/lib/internal/useNormalizedInputProps.d.ts +52 -0
  243. package/lib/internal/useNormalizedInputProps.js +9 -36
  244. package/package.json +6 -6
  245. package/scss/components/dialog/_dialog.scss +9 -0
  246. package/scss/components/dialog/_index.scss +9 -0
  247. package/telemetry.yml +1 -0
  248. package/es/components/Modal/next/index.d.ts +0 -171
  249. package/es/internal/focus/index.js +0 -15
  250. package/es/internal/useEffectOnce.js +0 -30
  251. package/lib/components/Modal/next/index.d.ts +0 -171
  252. package/lib/internal/focus/index.js +0 -19
  253. package/lib/internal/useEffectOnce.js +0 -34
@@ -5,32 +5,32 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import { defineProperty as _defineProperty, extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import { FloatingMenu, DIRECTION_TOP, DIRECTION_BOTTOM } from '../../internal/FloatingMenu.js';
10
- import React__default from 'react';
11
- import ClickListener from '../../internal/ClickListener.js';
12
- import { IconButton } from '../IconButton/index.js';
8
+ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
+ import React__default, { forwardRef, useContext, useState, useRef, useEffect, useCallback, Children, isValidElement, cloneElement } from 'react';
13
10
  import { OverflowMenuVertical } from '@carbon/icons-react';
14
- import { PrefixContext } from '../../internal/usePrefix.js';
15
- import PropTypes from 'prop-types';
16
11
  import cx from 'classnames';
17
- import deprecate from '../../prop-types/deprecate.js';
18
12
  import invariant from 'invariant';
19
- import mergeRefs from '../../tools/mergeRefs.js';
13
+ import PropTypes from 'prop-types';
14
+ import ClickListener from '../../internal/ClickListener.js';
15
+ import { DIRECTION_TOP, DIRECTION_BOTTOM, FloatingMenu } from '../../internal/FloatingMenu.js';
16
+ import { ArrowUp, ArrowRight, ArrowDown, ArrowLeft, Escape } from '../../internal/keyboard/keys.js';
17
+ import { matches } from '../../internal/keyboard/match.js';
20
18
  import { noopFn } from '../../internal/noopFn.js';
19
+ import { PrefixContext } from '../../internal/usePrefix.js';
20
+ import deprecate from '../../prop-types/deprecate.js';
21
+ import mergeRefs from '../../tools/mergeRefs.js';
21
22
  import setupGetInstanceId from '../../tools/setupGetInstanceId.js';
22
- import { matches } from '../../internal/keyboard/match.js';
23
- import { ArrowUp, ArrowRight, ArrowDown, ArrowLeft, Escape } from '../../internal/keyboard/keys.js';
23
+ import { IconButton } from '../IconButton/index.js';
24
24
 
25
25
  const getInstanceId = setupGetInstanceId();
26
- const on = function (element) {
26
+ const on = function (target) {
27
27
  for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
28
28
  args[_key - 1] = arguments[_key];
29
29
  }
30
- element.addEventListener(...args);
30
+ target.addEventListener(...args);
31
31
  return {
32
32
  release() {
33
- element.removeEventListener(...args);
33
+ target.removeEventListener(...args);
34
34
  return null;
35
35
  }
36
36
  };
@@ -38,7 +38,6 @@ const on = function (element) {
38
38
 
39
39
  /**
40
40
  * The CSS property names of the arrow keyed by the floating menu direction.
41
- * @type {[key: string]: string}
42
41
  */
43
42
  const triggerButtonPositionProps = {
44
43
  [DIRECTION_TOP]: 'bottom',
@@ -46,13 +45,22 @@ const triggerButtonPositionProps = {
46
45
  };
47
46
 
48
47
  /**
49
- * Determines how the position of arrow should affect the floating menu position.
50
- * @type {[key: string]: number}
48
+ * Determines how the position of the arrow should affect the floating menu
49
+ * position.
51
50
  */
52
51
  const triggerButtonPositionFactors = {
53
52
  [DIRECTION_TOP]: -2,
54
53
  [DIRECTION_BOTTOM]: -1
55
54
  };
55
+
56
+ /**
57
+ * Calculates the offset for the floating menu.
58
+ *
59
+ * @param menuBody - The menu body with the menu arrow.
60
+ * @param direction - The floating menu direction.
61
+ * @returns The adjustment of the floating menu position, upon the position of
62
+ * the menu arrow.
63
+ */
56
64
  const getMenuOffset = (menuBody, direction, trigger, flip) => {
57
65
  const triggerButtonPositionProp = triggerButtonPositionProps[direction];
58
66
  const triggerButtonPositionFactor = triggerButtonPositionFactors[direction];
@@ -81,324 +89,254 @@ const getMenuOffset = (menuBody, direction, trigger, flip) => {
81
89
  };
82
90
  }
83
91
  };
84
- class OverflowMenu extends React__default.Component {
85
- constructor() {
86
- super(...arguments);
87
- _defineProperty(this, "state", {
88
- open: false,
89
- // Set a default value for 'open'
90
- hasMountedTrigger: false,
91
- // Set a default value for 'hasMountedTrigger'
92
- click: false // Set a default value for 'click'
93
- });
94
- _defineProperty(this, "instanceId", getInstanceId());
95
- /**
96
- * The handle of `onfocusin` or `focus` event handler.
97
- * @private
98
- */
99
- _defineProperty(this, "_hFocusIn", null);
100
- /**
101
- * The timeout handle for handling `blur` event.
102
- * @private
103
- */
104
- _defineProperty(this, "_hBlurTimeout", void 0);
105
- /**
106
- * The element ref of the tooltip's trigger button.
107
- * @type {React.RefObject<HTMLElement>}
108
- * @private
109
- */
110
- _defineProperty(this, "_triggerRef", /*#__PURE__*/React__default.createRef());
111
- _defineProperty(this, "handleClick", evt => {
112
- const {
113
- onClick = noopFn
114
- } = this.props;
115
- this.setState({
116
- click: true
117
- });
118
- if (!this._menuBody || !this._menuBody.contains(evt.target)) {
119
- this.setState({
120
- open: !this.state.open
121
- });
122
- onClick(evt);
123
- }
124
- });
125
- _defineProperty(this, "closeMenuAndFocus", () => {
126
- const wasClicked = this.state.click;
127
- const wasOpen = this.state.open;
128
- this.closeMenu(() => {
129
- if (wasOpen && !wasClicked) {
130
- this.focusMenuEl();
131
- }
132
- });
133
- });
134
- _defineProperty(this, "closeMenuOnEscape", () => {
135
- const wasOpen = this.state.open;
136
- this.closeMenu(() => {
137
- if (wasOpen) {
138
- this.focusMenuEl();
139
- }
140
- });
141
- });
142
- _defineProperty(this, "handleKeyPress", evt => {
143
- if (this.state.open && matches(evt, [ArrowUp, ArrowRight, ArrowDown, ArrowLeft])) {
144
- evt.preventDefault();
145
- }
92
+ const OverflowMenu = /*#__PURE__*/forwardRef((_ref, ref) => {
93
+ let {
94
+ ['aria-label']: ariaLabel = null,
95
+ ariaLabel: deprecatedAriaLabel,
96
+ children,
97
+ className,
98
+ direction = DIRECTION_BOTTOM,
99
+ flipped = false,
100
+ focusTrap = true,
101
+ iconClass,
102
+ iconDescription = 'Options',
103
+ id,
104
+ light,
105
+ menuOffset = getMenuOffset,
106
+ menuOffsetFlip = getMenuOffset,
107
+ menuOptionsClass,
108
+ onClick = noopFn,
109
+ onClose = noopFn,
110
+ onOpen = noopFn,
111
+ open: openProp,
112
+ renderIcon: IconElement = OverflowMenuVertical,
113
+ selectorPrimaryFocus = '[data-floating-menu-primary-focus]',
114
+ size = 'md',
115
+ ...other
116
+ } = _ref;
117
+ const prefix = useContext(PrefixContext);
118
+ const [open, setOpen] = useState(openProp ?? false);
119
+ const [click, setClick] = useState(false);
120
+ const [hasMountedTrigger, setHasMountedTrigger] = useState(false);
121
+ /** The handle of `onfocusin` or `focus` event handler. */
122
+ const hFocusIn = useRef(null);
123
+ const instanceId = useRef(getInstanceId());
124
+ const menuBodyRef = useRef(null);
125
+ const menuItemRefs = useRef({});
126
+ const prevOpenProp = useRef(openProp);
127
+ const prevOpenState = useRef(open);
128
+ /** The element ref of the tooltip's trigger button. */
129
+ const triggerRef = useRef(null);
146
130
 
147
- // Close the overflow menu on escape
148
- if (matches(evt, [Escape])) {
149
- this.closeMenuOnEscape();
131
+ // Sync open prop changes.
132
+ useEffect(() => {
133
+ if (prevOpenProp.current !== openProp) {
134
+ setOpen(!!openProp);
135
+ prevOpenProp.current = openProp;
136
+ }
137
+ }, [openProp]);
150
138
 
151
- // Stop the esc keypress from bubbling out and closing something it shouldn't
152
- evt.stopPropagation();
153
- }
154
- });
155
- _defineProperty(this, "handleClickOutside", evt => {
156
- if (this.state.open && (!this._menuBody || !this._menuBody.contains(evt.target))) {
157
- this.closeMenu();
139
+ // Mark trigger as mounted.
140
+ useEffect(() => {
141
+ if (triggerRef.current) {
142
+ setHasMountedTrigger(true);
143
+ }
144
+ }, []);
145
+
146
+ // Call `onClose` when menu closes.
147
+ useEffect(() => {
148
+ if (!open && prevOpenState.current) {
149
+ onClose();
150
+ }
151
+ prevOpenState.current = open;
152
+ }, [open, onClose]);
153
+ const focusMenuEl = useCallback(() => {
154
+ if (triggerRef.current) {
155
+ triggerRef.current.focus();
156
+ }
157
+ }, []);
158
+ const closeMenu = useCallback(onCloseMenu => {
159
+ setOpen(false);
160
+ // Optional callback to be executed after the state as been set to close
161
+ if (onCloseMenu) {
162
+ onCloseMenu();
163
+ }
164
+ onClose();
165
+ }, [onClose]);
166
+ const closeMenuAndFocus = useCallback(() => {
167
+ const wasClicked = click;
168
+ const wasOpen = open;
169
+ closeMenu(() => {
170
+ if (wasOpen && !wasClicked) {
171
+ focusMenuEl();
158
172
  }
159
173
  });
160
- _defineProperty(this, "closeMenu", onCloseMenu => {
161
- const {
162
- onClose = noopFn
163
- } = this.props;
164
- this.setState({
165
- open: false
166
- }, () => {
167
- // Optional callback to be executed after the state as been set to close
168
- if (onCloseMenu) {
169
- onCloseMenu();
170
- }
171
- onClose();
172
- });
173
- });
174
- _defineProperty(this, "focusMenuEl", () => {
175
- const {
176
- current: triggerEl
177
- } = this._triggerRef;
178
- if (triggerEl) {
179
- triggerEl.focus();
174
+ }, [click, open, closeMenu, focusMenuEl]);
175
+ const closeMenuOnEscape = useCallback(() => {
176
+ const wasOpen = open;
177
+ closeMenu(() => {
178
+ if (wasOpen) {
179
+ focusMenuEl();
180
180
  }
181
181
  });
182
- /**
183
- * Focuses the next enabled overflow menu item given the currently focused
184
- * item index and direction to move
185
- * @param {object} params
186
- * @param {number} params.currentIndex - the index of the currently focused
187
- * overflow menu item in the list of overflow menu items
188
- * @param {number} params.direction - number denoting the direction to move
189
- * focus (1 for forwards, -1 for backwards)
190
- */
191
- _defineProperty(this, "handleOverflowMenuItemFocus", _ref => {
192
- let {
193
- currentIndex,
194
- direction
195
- } = _ref;
196
- const enabledIndices = React__default.Children.toArray(this.props.children).reduce((acc, curr, i) => {
197
- if (/*#__PURE__*/React__default.isValidElement(curr) && !curr.props.disabled) {
198
- acc.push(i);
199
- }
200
- return acc;
201
- }, []);
202
- const nextValidIndex = (() => {
203
- const nextIndex = enabledIndices.indexOf(currentIndex) + direction;
204
- switch (nextIndex) {
205
- case -1:
206
- return enabledIndices.length - 1;
207
- case enabledIndices.length:
208
- return 0;
209
- default:
210
- return nextIndex;
211
- }
212
- })();
213
- const overflowMenuItem = this[`overflowMenuItem${enabledIndices[nextValidIndex]}`];
214
- overflowMenuItem?.focus();
215
- });
216
- /**
217
- * Handles the floating menu being unmounted or non-floating menu being
218
- * mounted or unmounted.
219
- * @param {Element} menuBody The DOM element of the menu body.
220
- * @private
221
- */
222
- _defineProperty(this, "_menuBody", null);
223
- _defineProperty(this, "_bindMenuBody", menuBody => {
224
- if (!menuBody) {
225
- this._menuBody = menuBody;
182
+ }, [open, closeMenu, focusMenuEl]);
183
+ const handleClick = evt => {
184
+ setClick(true);
185
+ if (!menuBodyRef.current || !menuBodyRef.current.contains(evt.target)) {
186
+ setOpen(prev => !prev);
187
+ onClick(evt);
188
+ }
189
+ };
190
+ const handleKeyPress = evt => {
191
+ if (open && matches(evt, [ArrowUp, ArrowRight, ArrowDown, ArrowLeft])) {
192
+ evt.preventDefault();
193
+ }
194
+
195
+ // Close the overflow menu on escape
196
+ if (matches(evt, [Escape])) {
197
+ closeMenuOnEscape();
198
+
199
+ // Stop the esc keypress from bubbling out and closing something it shouldn't
200
+ evt.stopPropagation();
201
+ }
202
+ };
203
+ const handleClickOutside = evt => {
204
+ if (open && (!menuBodyRef.current || !menuBodyRef.current.contains(evt.target))) {
205
+ closeMenu();
206
+ }
207
+ };
208
+
209
+ /**
210
+ * Focuses the next enabled overflow menu item given the currently focused
211
+ * item index and direction to move.
212
+ */
213
+ const handleOverflowMenuItemFocus = _ref2 => {
214
+ let {
215
+ currentIndex,
216
+ direction
217
+ } = _ref2;
218
+ const enabledIndices = Children.toArray(children).reduce((acc, curr, i) => {
219
+ if (/*#__PURE__*/isValidElement(curr) && !curr.props.disabled) {
220
+ acc.push(i);
226
221
  }
227
- if (!menuBody && this._hFocusIn) {
228
- this._hFocusIn = this._hFocusIn.release();
222
+ return acc;
223
+ }, []);
224
+ const nextValidIndex = (() => {
225
+ const nextIndex = enabledIndices.indexOf(currentIndex) + direction;
226
+ switch (nextIndex) {
227
+ case -1:
228
+ return enabledIndices.length - 1;
229
+ case enabledIndices.length:
230
+ return 0;
231
+ default:
232
+ return nextIndex;
229
233
  }
230
- });
231
- /**
232
- * Handles the floating menu being placed.
233
- * @param {Element} menuBody The DOM element of the menu body.
234
- * @private
235
- */
236
- _defineProperty(this, "_handlePlace", menuBody => {
237
- const {
238
- onOpen = noopFn
239
- } = this.props;
240
- if (menuBody) {
241
- this._menuBody = menuBody;
242
- const hasFocusin = 'onfocusin' in window;
243
- const focusinEventName = hasFocusin ? 'focusin' : 'focus';
244
- this._hFocusIn = on(menuBody.ownerDocument, focusinEventName, event => {
245
- const target = ClickListener.getEventTarget(event);
246
- const {
247
- current: triggerEl
248
- } = this._triggerRef;
249
- if (typeof target.matches === 'function') {
250
- if (!menuBody.contains(target) && triggerEl && !target.matches(`.${this.context}--overflow-menu:first-child,.${this.context}--overflow-menu-options:first-child`)) {
251
- this.closeMenuAndFocus();
252
- }
253
- }
254
- }, !hasFocusin);
255
- onOpen();
234
+ })();
235
+ const overflowMenuItem = menuItemRefs.current[enabledIndices[nextValidIndex]];
236
+ overflowMenuItem?.focus();
237
+ };
238
+ const bindMenuBody = menuBody => {
239
+ if (!menuBody) {
240
+ menuBodyRef.current = menuBody;
241
+ }
242
+ if (!menuBody && hFocusIn.current) {
243
+ hFocusIn.current = hFocusIn.current.release();
244
+ }
245
+ };
246
+ const handlePlace = menuBody => {
247
+ if (!menuBody) return;
248
+ menuBodyRef.current = menuBody;
249
+ const hasFocusin = 'onfocusin' in window;
250
+ const focusinEventName = hasFocusin ? 'focusin' : 'focus';
251
+ hFocusIn.current = on(menuBody.ownerDocument, focusinEventName, event => {
252
+ const target = event.target;
253
+ const triggerEl = triggerRef.current;
254
+ if (typeof target.matches === 'function') {
255
+ if (!menuBody.contains(target) && triggerEl && !target.matches(`.${prefix}--overflow-menu:first-child, .${prefix}--overflow-menu-options:first-child`)) {
256
+ closeMenuAndFocus();
257
+ }
256
258
  }
257
- });
258
- /**
259
- * @returns {Element} The DOM element where the floating menu is placed in.
260
- */
261
- _defineProperty(this, "_getTarget", () => {
262
- const {
263
- current: triggerEl
264
- } = this._triggerRef;
265
- return triggerEl instanceof Element && triggerEl.closest('[data-floating-menu-container]') || document.body;
266
- });
267
- }
268
- componentDidUpdate(_, prevState) {
269
- const {
270
- onClose = noopFn
271
- } = this.props;
272
- if (!this.state.open && prevState.open) {
273
- onClose();
259
+ }, !hasFocusin);
260
+ onOpen();
261
+ };
262
+ const getTarget = () => {
263
+ const triggerEl = triggerRef.current;
264
+ if (triggerEl instanceof Element) {
265
+ return triggerEl.closest('[data-floating-menu-container]') || document.body;
274
266
  }
275
- }
276
- componentDidMount() {
277
- // ensure that if open=true on first render, we wait
278
- // to render the floating menu until the trigger ref is not null
279
- if (this._triggerRef.current) {
280
- this.setState({
281
- hasMountedTrigger: true
267
+ return document.body;
268
+ };
269
+ const menuBodyId = `overflow-menu-${instanceId.current}__menu-body`;
270
+ const overflowMenuClasses = cx(className, `${prefix}--overflow-menu`, {
271
+ [`${prefix}--overflow-menu--open`]: open,
272
+ [`${prefix}--overflow-menu--light`]: light,
273
+ [`${prefix}--overflow-menu--${size}`]: size
274
+ });
275
+ const overflowMenuOptionsClasses = cx(menuOptionsClass, `${prefix}--overflow-menu-options`, {
276
+ [`${prefix}--overflow-menu--flip`]: flipped,
277
+ [`${prefix}--overflow-menu-options--open`]: open,
278
+ [`${prefix}--overflow-menu-options--light`]: light,
279
+ [`${prefix}--overflow-menu-options--${size}`]: size
280
+ });
281
+ const overflowMenuIconClasses = cx(`${prefix}--overflow-menu__icon`, iconClass);
282
+ const childrenWithProps = Children.toArray(children).map((child, index) => {
283
+ if (/*#__PURE__*/isValidElement(child)) {
284
+ const childElement = child;
285
+ return /*#__PURE__*/cloneElement(childElement, {
286
+ closeMenu: childElement.props.closeMenu || closeMenuAndFocus,
287
+ handleOverflowMenuItemFocus,
288
+ ref: el => {
289
+ menuItemRefs.current[index] = el;
290
+ },
291
+ index
282
292
  });
283
293
  }
284
- }
285
- static getDerivedStateFromProps(_ref2, state) {
286
- let {
287
- open
288
- } = _ref2;
289
- const {
290
- prevOpen
291
- } = state;
292
- return prevOpen === open ? null : {
293
- open,
294
- prevOpen: open
295
- };
296
- }
297
- componentWillUnmount() {
298
- if (typeof this._hBlurTimeout === 'number') {
299
- clearTimeout(this._hBlurTimeout);
300
- this._hBlurTimeout = undefined;
301
- }
302
- }
303
- render() {
304
- const prefix = this.context;
305
- const {
306
- id,
307
- ['aria-label']: ariaLabel = null,
308
- ariaLabel: deprecatedAriaLabel,
309
- children,
310
- iconDescription = 'Options',
311
- direction = DIRECTION_BOTTOM,
312
- flipped = false,
313
- focusTrap = true,
314
- menuOffset = getMenuOffset,
315
- menuOffsetFlip = getMenuOffset,
316
- iconClass,
317
- onClick = noopFn,
318
- // eslint-disable-line
319
- onOpen = noopFn,
320
- // eslint-disable-line
321
- selectorPrimaryFocus = '[data-floating-menu-primary-focus]',
322
- // eslint-disable-line
323
- renderIcon: IconElement = OverflowMenuVertical,
324
- // eslint-disable-next-line react/prop-types
325
- innerRef: ref,
326
- menuOptionsClass,
327
- light,
328
- size = 'md',
329
- ...other
330
- } = this.props;
331
- const {
332
- open = false
333
- } = this.state;
334
- const overflowMenuClasses = cx(this.props.className, `${prefix}--overflow-menu`, {
335
- [`${prefix}--overflow-menu--open`]: open,
336
- [`${prefix}--overflow-menu--light`]: light,
337
- [`${prefix}--overflow-menu--${size}`]: size
338
- });
339
- const overflowMenuOptionsClasses = cx(menuOptionsClass, `${prefix}--overflow-menu-options`, {
340
- [`${prefix}--overflow-menu--flip`]: this.props.flipped,
341
- [`${prefix}--overflow-menu-options--open`]: open,
342
- [`${prefix}--overflow-menu-options--light`]: light,
343
- [`${prefix}--overflow-menu-options--${size}`]: size
344
- });
345
- const overflowMenuIconClasses = cx(`${prefix}--overflow-menu__icon`, iconClass);
346
- const childrenWithProps = React__default.Children.toArray(children).map((child, index) => /*#__PURE__*/React__default.isValidElement(child) ? /*#__PURE__*/React__default.cloneElement(child, {
347
- // @ts-expect-error: PropTypes are not expressive enough to cover this case
348
- closeMenu: child.props.closeMenu || this.closeMenuAndFocus,
349
- handleOverflowMenuItemFocus: this.handleOverflowMenuItemFocus,
350
- ref: e => {
351
- this[`overflowMenuItem${index}`] = e;
352
- },
353
- index
354
- }) : null);
355
- const menuBodyId = `overflow-menu-${this.instanceId}__menu-body`;
356
- const menuBody = /*#__PURE__*/React__default.createElement("ul", {
357
- className: overflowMenuOptionsClasses,
358
- tabIndex: -1,
359
- role: "menu",
360
- "aria-label": ariaLabel || deprecatedAriaLabel,
361
- onKeyDown: this.handleKeyPress,
362
- id: menuBodyId
363
- }, childrenWithProps);
364
- const wrappedMenuBody = /*#__PURE__*/React__default.createElement(FloatingMenu, {
365
- focusTrap: focusTrap,
366
- triggerRef: this._triggerRef,
367
- menuDirection: direction,
368
- menuOffset: flipped ? menuOffsetFlip : menuOffset,
369
- menuRef: this._bindMenuBody,
370
- flipped: this.props.flipped,
371
- target: this._getTarget,
372
- onPlace: this._handlePlace,
373
- selectorPrimaryFocus: this.props.selectorPrimaryFocus
374
- }, /*#__PURE__*/React__default.cloneElement(menuBody, {
375
- 'data-floating-menu-direction': direction
376
- }));
377
- const iconProps = {
378
- className: overflowMenuIconClasses,
379
- 'aria-label': iconDescription
380
- };
381
- return /*#__PURE__*/React__default.createElement(ClickListener, {
382
- onClickOutside: this.handleClickOutside
383
- }, /*#__PURE__*/React__default.createElement("span", {
384
- className: `${prefix}--overflow-menu__wrapper`,
385
- "aria-owns": open ? menuBodyId : undefined
386
- }, /*#__PURE__*/React__default.createElement(IconButton, _extends({}, other, {
387
- type: "button",
388
- "aria-haspopup": true,
389
- "aria-expanded": open,
390
- "aria-controls": open ? menuBodyId : undefined,
391
- className: overflowMenuClasses,
392
- onClick: this.handleClick,
393
- id: id,
394
- ref: mergeRefs(this._triggerRef, ref),
395
- size: size,
396
- label: iconDescription,
397
- kind: "ghost"
398
- }), /*#__PURE__*/React__default.createElement(IconElement, iconProps)), open && this.state.hasMountedTrigger && wrappedMenuBody));
399
- }
400
- }
401
- _defineProperty(OverflowMenu, "propTypes", {
294
+ return null;
295
+ });
296
+ const menuBody = /*#__PURE__*/React__default.createElement("ul", {
297
+ className: overflowMenuOptionsClasses,
298
+ tabIndex: -1,
299
+ role: "menu",
300
+ "aria-label": ariaLabel || deprecatedAriaLabel,
301
+ onKeyDown: handleKeyPress,
302
+ id: menuBodyId
303
+ }, childrenWithProps);
304
+ const wrappedMenuBody = /*#__PURE__*/React__default.createElement(FloatingMenu, {
305
+ focusTrap: focusTrap,
306
+ triggerRef: triggerRef,
307
+ menuDirection: direction,
308
+ menuOffset: flipped ? menuOffsetFlip : menuOffset,
309
+ menuRef: bindMenuBody,
310
+ flipped: flipped,
311
+ target: getTarget,
312
+ onPlace: handlePlace,
313
+ selectorPrimaryFocus: selectorPrimaryFocus
314
+ }, /*#__PURE__*/cloneElement(menuBody, {
315
+ 'data-floating-menu-direction': direction
316
+ }));
317
+ return /*#__PURE__*/React__default.createElement(ClickListener, {
318
+ onClickOutside: handleClickOutside
319
+ }, /*#__PURE__*/React__default.createElement("span", {
320
+ className: `${prefix}--overflow-menu__wrapper`,
321
+ "aria-owns": open ? menuBodyId : undefined
322
+ }, /*#__PURE__*/React__default.createElement(IconButton, _extends({}, other, {
323
+ type: "button",
324
+ "aria-haspopup": true,
325
+ "aria-expanded": open,
326
+ "aria-controls": open ? menuBodyId : undefined,
327
+ className: overflowMenuClasses,
328
+ onClick: handleClick,
329
+ id: id,
330
+ ref: mergeRefs(triggerRef, ref),
331
+ size: size,
332
+ label: iconDescription,
333
+ kind: "ghost"
334
+ }), /*#__PURE__*/React__default.createElement(IconElement, {
335
+ className: overflowMenuIconClasses,
336
+ "aria-label": iconDescription
337
+ })), open && hasMountedTrigger && wrappedMenuBody));
338
+ });
339
+ OverflowMenu.propTypes = {
402
340
  /**
403
341
  * Specify a label to be read by screen readers on the container node
404
342
  */
@@ -449,15 +387,15 @@ _defineProperty(OverflowMenu, "propTypes", {
449
387
  * The adjustment in position applied to the floating menu.
450
388
  */
451
389
  menuOffset: PropTypes.oneOfType([PropTypes.shape({
452
- top: PropTypes.number,
453
- left: PropTypes.number
390
+ top: PropTypes.number.isRequired,
391
+ left: PropTypes.number.isRequired
454
392
  }), PropTypes.func]),
455
393
  /**
456
394
  * The adjustment in position applied to the floating menu.
457
395
  */
458
396
  menuOffsetFlip: PropTypes.oneOfType([PropTypes.shape({
459
- top: PropTypes.number,
460
- left: PropTypes.number
397
+ top: PropTypes.number.isRequired,
398
+ left: PropTypes.number.isRequired
461
399
  }), PropTypes.func]),
462
400
  /**
463
401
  * The class to apply to the menu options
@@ -488,8 +426,9 @@ _defineProperty(OverflowMenu, "propTypes", {
488
426
  */
489
427
  open: PropTypes.bool,
490
428
  /**
491
- * Function called to override icon rendering.
429
+ * A component used to render an icon.
492
430
  */
431
+ // @ts-expect-error: PropTypes are not expressive enough to cover this case
493
432
  renderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
494
433
  /**
495
434
  * Specify a CSS selector that matches the DOM element that should
@@ -500,14 +439,6 @@ _defineProperty(OverflowMenu, "propTypes", {
500
439
  * Specify the size of the OverflowMenu. Currently supports either `sm`, 'md' (default) or 'lg` as an option.
501
440
  */
502
441
  size: PropTypes.oneOf(['sm', 'md', 'lg'])
503
- });
504
- _defineProperty(OverflowMenu, "contextType", PrefixContext);
505
- (() => {
506
- const forwardRef = (props, ref) => /*#__PURE__*/React__default.createElement(OverflowMenu, _extends({}, props, {
507
- innerRef: ref
508
- }));
509
- forwardRef.displayName = 'OverflowMenu';
510
- return /*#__PURE__*/React__default.forwardRef(forwardRef);
511
- })();
442
+ };
512
443
 
513
- export { OverflowMenu, getMenuOffset };
444
+ export { OverflowMenu, OverflowMenu as default, getMenuOffset };