@carbon/react 1.77.0-rc.0 → 1.78.0-rc.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 (134) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +945 -858
  2. package/es/components/Accordion/AccordionItem.js +1 -1
  3. package/es/components/BadgeIndicator/index.d.ts +23 -0
  4. package/es/components/BadgeIndicator/index.js +45 -0
  5. package/es/components/Breadcrumb/Breadcrumb.d.ts +5 -0
  6. package/es/components/Breadcrumb/Breadcrumb.js +8 -2
  7. package/es/components/Button/Button.d.ts +9 -0
  8. package/es/components/Button/Button.js +13 -0
  9. package/es/components/ComboBox/ComboBox.js +13 -9
  10. package/es/components/Dropdown/Dropdown.d.ts +1 -1
  11. package/es/components/Dropdown/Dropdown.js +3 -2
  12. package/es/components/FileUploader/FileUploader.js +1 -1
  13. package/es/components/FileUploader/FileUploaderItem.js +1 -1
  14. package/es/components/IconButton/index.d.ts +7 -1
  15. package/es/components/IconButton/index.js +18 -2
  16. package/es/components/IconIndicator/index.d.ts +1 -1
  17. package/es/components/InlineLoading/InlineLoading.js +2 -5
  18. package/es/components/Menu/MenuItem.js +1 -1
  19. package/es/components/Modal/Modal.d.ts +3 -3
  20. package/es/components/Modal/Modal.js +9 -3
  21. package/es/components/Modal/next/index.d.ts +1 -5
  22. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  23. package/es/components/MultiSelect/FilterableMultiSelect.js +11 -3
  24. package/es/components/MultiSelect/MultiSelect.js +3 -2
  25. package/es/components/MultiSelect/MultiSelectPropTypes.d.ts +5 -2
  26. package/es/components/MultiSelect/tools/sorting.js +8 -7
  27. package/es/components/Notification/Notification.js +1 -1
  28. package/es/components/NumberInput/NumberInput.js +12 -12
  29. package/es/components/OverflowMenu/OverflowMenu.d.ts +8 -20
  30. package/es/components/OverflowMenu/OverflowMenu.js +7 -9
  31. package/es/components/OverflowMenuItem/OverflowMenuItem.js +1 -1
  32. package/es/components/Pagination/Pagination.js +2 -2
  33. package/es/components/ProgressIndicator/ProgressIndicator.js +1 -1
  34. package/es/components/RadioTile/RadioTile.js +1 -1
  35. package/es/components/Select/Select.js +11 -2
  36. package/es/components/ShapeIndicator/index.d.ts +29 -0
  37. package/es/components/ShapeIndicator/index.js +92 -0
  38. package/es/components/Tabs/Tabs.d.ts +6 -4
  39. package/es/components/Tabs/Tabs.js +27 -8
  40. package/es/components/Tag/OperationalTag.d.ts +1 -36
  41. package/es/components/Tag/OperationalTag.js +7 -5
  42. package/es/components/Text/Text.d.ts +11 -9
  43. package/es/components/Text/Text.js +6 -6
  44. package/es/components/Text/TextDirection.d.ts +7 -9
  45. package/es/components/Text/TextDirection.js +5 -2
  46. package/es/components/Text/TextDirectionContext.d.ts +14 -0
  47. package/es/components/Text/TextDirectionContext.js +6 -2
  48. package/es/components/Text/createTextComponent.d.ts +5 -5
  49. package/es/components/Text/createTextComponent.js +5 -4
  50. package/es/components/Text/index.d.ts +6 -7
  51. package/es/components/Text/index.js +3 -2
  52. package/es/components/Tile/Tile.d.ts +6 -0
  53. package/es/components/Tile/Tile.js +5 -9
  54. package/es/components/Toggletip/index.d.ts +3 -2
  55. package/es/components/Tooltip/DefinitionTooltip.d.ts +4 -0
  56. package/es/components/Tooltip/DefinitionTooltip.js +7 -1
  57. package/es/components/Tooltip/Tooltip.d.ts +5 -66
  58. package/es/components/Tooltip/Tooltip.js +26 -26
  59. package/es/components/UIShell/HeaderGlobalAction.d.ts +9 -0
  60. package/es/components/UIShell/HeaderGlobalAction.js +16 -1
  61. package/es/index.d.ts +4 -1
  62. package/es/index.js +2 -1
  63. package/es/internal/FloatingMenu.d.ts +83 -0
  64. package/es/internal/FloatingMenu.js +216 -408
  65. package/es/internal/wrapFocus.js +1 -1
  66. package/lib/components/Accordion/AccordionItem.js +1 -1
  67. package/lib/components/BadgeIndicator/index.d.ts +23 -0
  68. package/lib/components/BadgeIndicator/index.js +56 -0
  69. package/lib/components/Breadcrumb/Breadcrumb.d.ts +5 -0
  70. package/lib/components/Breadcrumb/Breadcrumb.js +8 -2
  71. package/lib/components/Button/Button.d.ts +9 -0
  72. package/lib/components/Button/Button.js +13 -0
  73. package/lib/components/ComboBox/ComboBox.js +13 -9
  74. package/lib/components/Dropdown/Dropdown.d.ts +1 -1
  75. package/lib/components/Dropdown/Dropdown.js +2 -1
  76. package/lib/components/FileUploader/FileUploader.js +1 -1
  77. package/lib/components/FileUploader/FileUploaderItem.js +1 -1
  78. package/lib/components/IconButton/index.d.ts +7 -1
  79. package/lib/components/IconButton/index.js +18 -2
  80. package/lib/components/IconIndicator/index.d.ts +1 -1
  81. package/lib/components/InlineLoading/InlineLoading.js +2 -5
  82. package/lib/components/Menu/MenuItem.js +1 -1
  83. package/lib/components/Modal/Modal.d.ts +3 -3
  84. package/lib/components/Modal/Modal.js +9 -3
  85. package/lib/components/Modal/next/index.d.ts +1 -5
  86. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  87. package/lib/components/MultiSelect/FilterableMultiSelect.js +10 -2
  88. package/lib/components/MultiSelect/MultiSelect.js +2 -1
  89. package/lib/components/MultiSelect/MultiSelectPropTypes.d.ts +5 -2
  90. package/lib/components/MultiSelect/tools/sorting.js +8 -7
  91. package/lib/components/Notification/Notification.js +1 -1
  92. package/lib/components/NumberInput/NumberInput.js +12 -12
  93. package/lib/components/OverflowMenu/OverflowMenu.d.ts +8 -20
  94. package/lib/components/OverflowMenu/OverflowMenu.js +7 -9
  95. package/lib/components/OverflowMenuItem/OverflowMenuItem.js +1 -1
  96. package/lib/components/Pagination/Pagination.js +3 -2
  97. package/lib/components/ProgressIndicator/ProgressIndicator.js +1 -1
  98. package/lib/components/RadioTile/RadioTile.js +1 -1
  99. package/lib/components/Select/Select.js +11 -2
  100. package/lib/components/ShapeIndicator/index.d.ts +29 -0
  101. package/lib/components/ShapeIndicator/index.js +104 -0
  102. package/lib/components/Tabs/Tabs.d.ts +6 -4
  103. package/lib/components/Tabs/Tabs.js +42 -23
  104. package/lib/components/Tag/OperationalTag.d.ts +1 -36
  105. package/lib/components/Tag/OperationalTag.js +6 -4
  106. package/lib/components/Text/Text.d.ts +11 -9
  107. package/lib/components/Text/Text.js +5 -5
  108. package/lib/components/Text/TextDirection.d.ts +7 -9
  109. package/lib/components/Text/TextDirection.js +5 -2
  110. package/lib/components/Text/TextDirectionContext.d.ts +14 -0
  111. package/lib/components/Text/TextDirectionContext.js +6 -2
  112. package/lib/components/Text/createTextComponent.d.ts +5 -5
  113. package/lib/components/Text/createTextComponent.js +5 -4
  114. package/lib/components/Text/index.d.ts +6 -7
  115. package/lib/components/Text/index.js +4 -3
  116. package/lib/components/Tile/Tile.d.ts +6 -0
  117. package/lib/components/Tile/Tile.js +5 -9
  118. package/lib/components/Toggletip/index.d.ts +3 -2
  119. package/lib/components/Tooltip/DefinitionTooltip.d.ts +4 -0
  120. package/lib/components/Tooltip/DefinitionTooltip.js +7 -1
  121. package/lib/components/Tooltip/Tooltip.d.ts +5 -66
  122. package/lib/components/Tooltip/Tooltip.js +26 -26
  123. package/lib/components/UIShell/HeaderGlobalAction.d.ts +9 -0
  124. package/lib/components/UIShell/HeaderGlobalAction.js +16 -1
  125. package/lib/index.d.ts +4 -1
  126. package/lib/index.js +42 -40
  127. package/lib/internal/FloatingMenu.d.ts +83 -0
  128. package/lib/internal/FloatingMenu.js +216 -409
  129. package/lib/internal/wrapFocus.js +1 -1
  130. package/package.json +7 -7
  131. package/scss/components/badge-indicator/_badge-indicator.scss +9 -0
  132. package/scss/components/badge-indicator/_index.scss +9 -0
  133. package/es/tools/array.js +0 -29
  134. package/lib/tools/array.js +0 -33
@@ -9,17 +9,15 @@
9
9
 
10
10
  Object.defineProperty(exports, '__esModule', { value: true });
11
11
 
12
- var _rollupPluginBabelHelpers = require('../_virtual/_rollupPluginBabelHelpers.js');
13
- var PropTypes = require('prop-types');
14
12
  var React = require('react');
13
+ var FeatureFlags = require('@carbon/feature-flags');
15
14
  var ReactDOM = require('react-dom');
16
15
  var window = require('window-or-global');
17
16
  var OptimizedResize = require('./OptimizedResize.js');
18
17
  var navigation = require('./keyboard/navigation.js');
18
+ var usePrefix = require('./usePrefix.js');
19
19
  var warning = require('./warning.js');
20
20
  var wrapFocus = require('./wrapFocus.js');
21
- var usePrefix = require('./usePrefix.js');
22
- var FeatureFlags = require('@carbon/feature-flags');
23
21
  var match = require('./keyboard/match.js');
24
22
  var keys = require('./keyboard/keys.js');
25
23
 
@@ -43,85 +41,27 @@ function _interopNamespace(e) {
43
41
  return Object.freeze(n);
44
42
  }
45
43
 
46
- var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
47
44
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
45
+ var FeatureFlags__namespace = /*#__PURE__*/_interopNamespace(FeatureFlags);
48
46
  var ReactDOM__default = /*#__PURE__*/_interopDefaultLegacy(ReactDOM);
49
47
  var window__default = /*#__PURE__*/_interopDefaultLegacy(window);
50
- var FeatureFlags__namespace = /*#__PURE__*/_interopNamespace(FeatureFlags);
51
-
52
- /**
53
- * The structure for the position of floating menu.
54
- * @typedef {object} FloatingMenu~position
55
- * @property {number} left The left position.
56
- * @property {number} top The top position.
57
- * @property {number} right The right position.
58
- * @property {number} bottom The bottom position.
59
- */
60
-
61
- /**
62
- * The structure for the size of floating menu.
63
- * @typedef {object} FloatingMenu~size
64
- * @property {number} width The width.
65
- * @property {number} height The height.
66
- */
67
-
68
- /**
69
- * The structure for the position offset of floating menu.
70
- * @typedef {object} FloatingMenu~offset
71
- * @property {number} top The top position.
72
- * @property {number} left The left position.
73
- */
74
-
75
- /**
76
- * The structure for the target container.
77
- * @typedef {object} FloatingMenu~container
78
- * @property {DOMRect} rect Return of element.getBoundingClientRect()
79
- * @property {string} position Position style (static, absolute, relative...)
80
- */
81
48
 
82
49
  const DIRECTION_LEFT = 'left';
83
50
  const DIRECTION_TOP = 'top';
84
51
  const DIRECTION_RIGHT = 'right';
85
52
  const DIRECTION_BOTTOM = 'bottom';
86
-
87
53
  /**
88
- * @param {FloatingMenu~offset} [oldMenuOffset={}] The old value.
89
- * @param {FloatingMenu~offset} [menuOffset={}] The new value.
90
- * @returns `true` if the parent component wants to change in the adjustment of the floating menu position.
91
- * @private
92
- */
93
- const hasChangeInOffset = function () {
94
- let oldMenuOffset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
95
- let menuOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
96
- if (typeof oldMenuOffset !== typeof menuOffset) {
97
- return true;
98
- }
99
- if (Object(menuOffset) === menuOffset && typeof menuOffset !== 'function') {
100
- return oldMenuOffset.top !== menuOffset.top || oldMenuOffset.left !== menuOffset.left;
101
- }
102
- return oldMenuOffset !== menuOffset;
103
- };
104
-
105
- /**
106
- * @param {object} params The parameters.
107
- * @param {FloatingMenu~size} params.menuSize The size of the menu.
108
- * @param {FloatingMenu~position} params.refPosition The position of the triggering element.
109
- * @param {FloatingMenu~offset} [params.offset={ left: 0, top: 0 }] The position offset of the menu.
110
- * @param {string} [params.direction=bottom] The menu direction.
111
- * @param {number} [params.scrollX=0] The scroll position of the viewport.
112
- * @param {number} [params.scrollY=0] The scroll position of the viewport.
113
- * @param {FloatingMenu~container} [params.container] The size and position type of target element.
114
- * @returns {FloatingMenu~offset} The position of the menu, relative to the top-left corner of the viewport.
115
- * @private
54
+ * Computes the floating menu's position based on the menu size, trigger element
55
+ * position, offset, direction, and container.
116
56
  */
117
57
  const getFloatingPosition = _ref => {
118
58
  let {
119
59
  menuSize,
120
- refPosition = {},
121
- offset = {},
122
- direction = DIRECTION_BOTTOM,
123
- scrollX: pageXOffset = 0,
124
- scrollY: pageYOffset = 0,
60
+ refPosition,
61
+ offset,
62
+ direction,
63
+ scrollX,
64
+ scrollY,
125
65
  container
126
66
  } = _ref;
127
67
  const {
@@ -130,8 +70,8 @@ const getFloatingPosition = _ref => {
130
70
  right: refRight = 0,
131
71
  bottom: refBottom = 0
132
72
  } = refPosition;
133
- const scrollX = container.position !== 'static' ? 0 : pageXOffset;
134
- const scrollY = container.position !== 'static' ? 0 : pageYOffset;
73
+ const effectiveScrollX = container.position !== 'static' ? 0 : scrollX;
74
+ const effectiveScrollY = container.position !== 'static' ? 0 : scrollY;
135
75
  const relativeDiff = {
136
76
  top: container.position !== 'static' ? container.rect.top : 0,
137
77
  left: container.position !== 'static' ? container.rect.left : 0
@@ -146,370 +86,237 @@ const getFloatingPosition = _ref => {
146
86
  } = offset;
147
87
  const refCenterHorizontal = (refLeft + refRight) / 2;
148
88
  const refCenterVertical = (refTop + refBottom) / 2;
149
- return {
89
+ const positions = {
150
90
  [DIRECTION_LEFT]: () => ({
151
- left: refLeft - width + scrollX - left - relativeDiff.left,
152
- top: refCenterVertical - height / 2 + scrollY + top - 9 - relativeDiff.top
91
+ left: refLeft - width + effectiveScrollX - left - relativeDiff.left,
92
+ top: refCenterVertical - height / 2 + effectiveScrollY + top - 9 - relativeDiff.top
153
93
  }),
154
94
  [DIRECTION_TOP]: () => ({
155
- left: refCenterHorizontal - width / 2 + scrollX + left - relativeDiff.left,
156
- top: refTop - height + scrollY - top - relativeDiff.top
95
+ left: refCenterHorizontal - width / 2 + effectiveScrollX + left - relativeDiff.left,
96
+ top: refTop - height + effectiveScrollY - top - relativeDiff.top
157
97
  }),
158
98
  [DIRECTION_RIGHT]: () => ({
159
- left: refRight + scrollX + left - relativeDiff.left,
160
- top: refCenterVertical - height / 2 + scrollY + top + 3 - relativeDiff.top
99
+ left: refRight + effectiveScrollX + left - relativeDiff.left,
100
+ top: refCenterVertical - height / 2 + effectiveScrollY + top + 3 - relativeDiff.top
161
101
  }),
162
102
  [DIRECTION_BOTTOM]: () => ({
163
- left: refCenterHorizontal - width / 2 + scrollX + left - relativeDiff.left,
164
- top: refBottom + scrollY + top - relativeDiff.top
103
+ left: refCenterHorizontal - width / 2 + effectiveScrollX + left - relativeDiff.left,
104
+ top: refBottom + effectiveScrollY + top - relativeDiff.top
165
105
  })
166
- }[direction]();
106
+ };
107
+ return positions[direction]();
167
108
  };
168
-
169
- /**
170
- * A menu that is detached from the triggering element.
171
- * Useful when the container of the triggering element cannot have `overflow:visible` style, etc.
172
- */
173
- class FloatingMenu extends React__default["default"].Component {
174
- constructor() {
175
- var _this;
176
- super(...arguments);
177
- _this = this;
178
- // `true` if the menu body is mounted and calculation of the position is in progress.
179
- _rollupPluginBabelHelpers.defineProperty(this, "_placeInProgress", false);
180
- _rollupPluginBabelHelpers.defineProperty(this, "state", {
181
- /**
182
- * The position of the menu, relative to the top-left corner of the viewport.
183
- * @type {FloatingMenu~offset}
184
- */
185
- floatingPosition: undefined
186
- });
187
- /**
188
- * The cached reference to the menu container.
189
- * Only used if React portal API is not available.
190
- * @type {Element}
191
- * @private
192
- */
193
- _rollupPluginBabelHelpers.defineProperty(this, "_menuContainer", null);
194
- /**
195
- * The cached reference to the menu body.
196
- * The reference is set via callback ref instead of object ref,
197
- * in order to hook the event when the element ref gets available,
198
- * which can be at a different timing from `cDM()`, presumably with SSR scenario.
199
- * @type {Element}
200
- * @private
201
- */
202
- _rollupPluginBabelHelpers.defineProperty(this, "_menuBody", null);
203
- /**
204
- * Focus sentinel refs for focus trap behavior
205
- */
206
- _rollupPluginBabelHelpers.defineProperty(this, "startSentinel", /*#__PURE__*/React__default["default"].createRef());
207
- _rollupPluginBabelHelpers.defineProperty(this, "endSentinel", /*#__PURE__*/React__default["default"].createRef());
208
- /**
209
- * Calculates the position in the viewport of floating menu,
210
- * once this component is mounted or updated upon change in the following props:
211
- *
212
- * * `menuOffset` (The adjustment that should be applied to the calculated floating menu's position)
213
- * * `menuDirection` (Where the floating menu menu should be placed relative to the trigger button)
214
- *
215
- * @private
216
- */
217
- _rollupPluginBabelHelpers.defineProperty(this, "_updateMenuSize", function () {
218
- let prevProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
219
- let isAdjustment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
220
- const menuBody = _this._menuBody;
109
+ const FloatingMenu = _ref2 => {
110
+ let {
111
+ children,
112
+ flipped,
113
+ focusTrap,
114
+ menuDirection = DIRECTION_BOTTOM,
115
+ menuOffset = {},
116
+ menuRef: externalMenuRef,
117
+ onPlace,
118
+ selectorPrimaryFocus,
119
+ styles,
120
+ target = () => document.body,
121
+ triggerRef,
122
+ updateOrientation
123
+ } = _ref2;
124
+ const prefix = React.useContext(usePrefix.PrefixContext);
125
+ const [floatingPosition, setFloatingPosition] = React.useState(undefined);
126
+ const menuBodyRef = React.useRef(null);
127
+ const startSentinelRef = React.useRef(null);
128
+ const endSentinelRef = React.useRef(null);
129
+ const placeInProgressRef = React.useRef(false);
130
+ const updateMenuPosition = React.useCallback(isAdjustment => {
131
+ const menuBody = menuBodyRef.current;
132
+ if (!menuBody) {
221
133
  process.env.NODE_ENV !== "production" ? warning.warning(menuBody, 'The DOM node for menu body for calculating its position is not available. Skipping...') : void 0;
222
- if (!menuBody) {
223
- return;
224
- }
225
- const {
226
- menuOffset: oldMenuOffset = {},
227
- menuDirection: oldMenuDirection
228
- } = prevProps;
229
- const {
230
- menuOffset = {},
231
- menuDirection = DIRECTION_BOTTOM
232
- } = _this.props;
233
- if (hasChangeInOffset(oldMenuOffset, menuOffset) || oldMenuDirection !== menuDirection || isAdjustment) {
234
- const {
235
- flipped,
236
- triggerRef,
237
- updateOrientation = null
238
- } = _this.props;
239
- const {
240
- current: triggerEl
241
- } = triggerRef;
242
- const menuSize = menuBody.getBoundingClientRect();
243
- const refPosition = triggerEl && triggerEl.getBoundingClientRect();
244
- const offset = typeof menuOffset !== 'function' ? menuOffset : menuOffset(menuBody, menuDirection, triggerEl, flipped);
245
-
246
- // Optional function to allow parent component to check
247
- // if the orientation needs to be changed based on params
248
- if (updateOrientation) {
249
- updateOrientation({
250
- menuSize,
251
- refPosition,
252
- direction: menuDirection,
253
- offset,
254
- scrollX: window__default["default"].pageXOffset,
255
- scrollY: window__default["default"].pageYOffset,
256
- container: {
257
- rect: _this.props.target().getBoundingClientRect(),
258
- position: getComputedStyle(_this.props.target()).position
259
- }
260
- });
261
- }
262
- // Skips if either in the following condition:
263
- // a) Menu body has `display:none`
264
- // b) `menuOffset` as a callback returns `undefined` (The callback saw that it couldn't calculate the value)
265
- if (menuSize.width > 0 && menuSize.height > 0 || !offset) {
266
- _this.setState({
267
- floatingPosition: getFloatingPosition({
268
- menuSize,
269
- refPosition,
270
- direction: menuDirection,
271
- offset,
272
- scrollX: window__default["default"].pageXOffset,
273
- scrollY: window__default["default"].pageYOffset,
274
- container: {
275
- rect: _this.props.target().getBoundingClientRect(),
276
- position: getComputedStyle(_this.props.target()).position
277
- }
278
- })
279
- }, () => {
280
- if (!isAdjustment) {
281
- const newMenuSize = menuBody.getBoundingClientRect();
282
- if (newMenuSize !== menuSize) {
283
- _this._updateMenuSize(_this.props, true);
284
- }
285
- }
286
- });
134
+ return;
135
+ }
136
+ const triggerEl = triggerRef.current;
137
+ const menuSize = menuBody.getBoundingClientRect();
138
+ const refPosition = triggerEl ? triggerEl.getBoundingClientRect() : undefined;
139
+ const offsetValue = typeof menuOffset === 'function' ? menuOffset(menuBody, menuDirection, triggerEl, flipped) : menuOffset;
140
+ if (updateOrientation) {
141
+ updateOrientation({
142
+ menuSize,
143
+ refPosition,
144
+ direction: menuDirection,
145
+ offset: offsetValue,
146
+ scrollX: window__default["default"].pageXOffset,
147
+ scrollY: window__default["default"].pageYOffset,
148
+ container: {
149
+ rect: target().getBoundingClientRect(),
150
+ position: getComputedStyle(target()).position
287
151
  }
288
- }
289
- });
290
- /**
291
- * Set focus on floating menu content after menu placement.
292
- * @param {Element} menuBody The DOM element of the menu body.
293
- * @private
294
- */
295
- _rollupPluginBabelHelpers.defineProperty(this, "_focusMenuContent", menuBody => {
296
- const primaryFocusNode = menuBody.querySelector(this.props.selectorPrimaryFocus || null);
297
- const tabbableNode = menuBody.querySelector(navigation.selectorTabbable);
298
- const focusableNode = menuBody.querySelector(navigation.selectorFocusable);
299
- const focusTarget = primaryFocusNode ||
300
- // User defined focusable node
301
- tabbableNode ||
302
- // First sequentially focusable node
303
- focusableNode ||
304
- // First programmatic focusable node
305
- menuBody;
306
- focusTarget.focus();
307
- if (focusTarget === menuBody && process.env.NODE_ENV !== "production") {
308
- process.env.NODE_ENV !== "production" ? warning.warning(focusableNode === null, 'Floating Menus must have at least a programmatically focusable child. ' + 'This can be accomplished by adding tabIndex="-1" to the content element.') : void 0;
309
- }
310
- });
311
- /**
312
- * A callback for called when menu body is mounted or unmounted.
313
- * @param {Element} menuBody The menu body being mounted. `null` if the menu body is being unmounted.
314
- */
315
- _rollupPluginBabelHelpers.defineProperty(this, "_menuRef", menuBody => {
316
- const {
317
- menuRef
318
- } = this.props;
319
- this._placeInProgress = !!menuBody;
320
- menuRef && menuRef(this._menuBody = menuBody);
321
- if (menuBody) {
322
- this._updateMenuSize();
323
- }
324
- });
325
- /**
326
- * @returns The child nodes, with styles containing the floating menu position.
327
- * @private
328
- */
329
- _rollupPluginBabelHelpers.defineProperty(this, "_getChildrenWithProps", () => {
330
- const {
331
- styles,
332
- children
333
- } = this.props;
334
- const {
335
- floatingPosition: pos
336
- } = this.state;
337
- // If no pos available, we need to hide the element (offscreen to the left)
338
- // This is done so we can measure the content before positioning it correctly.
339
- const positioningStyle = pos ? {
340
- left: `${pos.left}px`,
341
- top: `${pos.top}px`,
342
- right: 'auto'
343
- } : {
344
- visibility: 'hidden',
345
- top: '0px'
346
- };
347
- return /*#__PURE__*/React__default["default"].cloneElement(children, {
348
- ref: this._menuRef,
349
- style: {
350
- ...styles,
351
- ...positioningStyle,
352
- position: 'absolute',
353
- opacity: 1
152
+ });
153
+ }
154
+
155
+ // Only set position if the menu has a valid size or if no offset is provided.
156
+ if (menuSize.width > 0 && menuSize.height > 0 || !offsetValue) {
157
+ const newFloatingPosition = getFloatingPosition({
158
+ menuSize,
159
+ refPosition: refPosition ?? {
160
+ left: 0,
161
+ top: 0,
162
+ right: 0,
163
+ bottom: 0
164
+ },
165
+ offset: offsetValue,
166
+ direction: menuDirection,
167
+ scrollX: window__default["default"].pageXOffset,
168
+ scrollY: window__default["default"].pageYOffset,
169
+ container: {
170
+ rect: target().getBoundingClientRect(),
171
+ position: getComputedStyle(target()).position
354
172
  }
355
173
  });
356
- });
357
- /**
358
- * Blur handler for when focus wrap behavior is enabled
359
- * @param {Event} event
360
- * @param {Element} event.target previously focused node
361
- * @param {Element} event.relatedTarget current focused node
362
- */
363
- _rollupPluginBabelHelpers.defineProperty(this, "handleBlur", _ref2 => {
364
- let {
365
- target: oldActiveNode,
366
- relatedTarget: currentActiveNode
367
- } = _ref2;
368
- if (currentActiveNode && oldActiveNode) {
369
- const {
370
- current: startSentinelNode
371
- } = this.startSentinel;
372
- const {
373
- current: endSentinelNode
374
- } = this.endSentinel;
375
- wrapFocus["default"]({
376
- bodyNode: this._menuBody,
377
- startSentinelNode,
378
- endSentinelNode,
379
- currentActiveNode,
380
- oldActiveNode
381
- });
174
+
175
+ // Only update if the position has actually changed.
176
+ if (!floatingPosition || floatingPosition.left !== newFloatingPosition.left || floatingPosition.top !== newFloatingPosition.top) {
177
+ setFloatingPosition(newFloatingPosition);
382
178
  }
383
- });
384
- /**
385
- * Keydown handler for when focus wrap behavior is enabled
386
- * @param {Event} event
387
- */
388
- _rollupPluginBabelHelpers.defineProperty(this, "handleKeyDown", event => {
389
- if (match.match(event, keys.Tab) && this._menuBody) {
390
- wrapFocus.wrapFocusWithoutSentinels({
391
- containerNode: this._menuBody,
392
- currentActiveNode: event.target,
393
- event
394
- });
179
+
180
+ // Re-check after setting the position if not already adjusting.
181
+ if (!isAdjustment) {
182
+ const newMenuSize = menuBody.getBoundingClientRect();
183
+ // TODO: Was there a bug in the old code? How could one `DOMRect` be
184
+ // compared to another using `!==`?
185
+ if (newMenuSize.width !== menuSize.width || newMenuSize.height !== menuSize.height) {
186
+ updateMenuPosition(true);
187
+ }
395
188
  }
396
- });
397
- }
398
- componentWillUnmount() {
399
- this.hResize.release();
400
- }
401
- componentDidMount() {
402
- this.hResize = OptimizedResize["default"].add(() => {
403
- this._updateMenuSize();
404
- });
405
- }
406
- componentDidUpdate(prevProps) {
407
- this._updateMenuSize(prevProps);
408
- const {
409
- onPlace
410
- } = this.props;
411
- if (this._placeInProgress && this.state.floatingPosition) {
412
- if (this._menuBody && !this._menuBody.contains(document.activeElement)) {
413
- this._focusMenuContent(this._menuBody);
189
+ }
190
+ }, [triggerRef, menuOffset, menuDirection, flipped, target, updateOrientation, floatingPosition]);
191
+ const focusMenuContent = menuBody => {
192
+ const primaryFocusNode = selectorPrimaryFocus ? menuBody.querySelector(selectorPrimaryFocus) : null;
193
+ const tabbableNode = menuBody.querySelector(navigation.selectorTabbable);
194
+ const focusableNode = menuBody.querySelector(navigation.selectorFocusable);
195
+ const focusTarget = primaryFocusNode ||
196
+ // User defined focusable node
197
+ tabbableNode ||
198
+ // First sequentially focusable node
199
+ focusableNode ||
200
+ // First programmatic focusable node
201
+ menuBody;
202
+ focusTarget.focus();
203
+ if (focusTarget === menuBody && process.env.NODE_ENV !== "production") {
204
+ process.env.NODE_ENV !== "production" ? warning.warning(focusableNode === null, 'Floating Menus must have at least a programmatically focusable child. This can be accomplished by adding tabIndex="-1" to the content element.') : void 0;
205
+ }
206
+ };
207
+ const handleMenuRef = node => {
208
+ menuBodyRef.current = node;
209
+ placeInProgressRef.current = !!node;
210
+ if (externalMenuRef) {
211
+ externalMenuRef(node);
212
+ }
213
+ if (node) {
214
+ updateMenuPosition();
215
+ }
216
+ };
217
+
218
+ // When the menu has been placed, focus the content and call onPlace.
219
+ React.useEffect(() => {
220
+ if (placeInProgressRef.current && floatingPosition && menuBodyRef.current) {
221
+ if (!menuBodyRef.current.contains(document.activeElement)) {
222
+ focusMenuContent(menuBodyRef.current);
414
223
  }
415
224
  if (typeof onPlace === 'function') {
416
- onPlace(this._menuBody);
417
- this._placeInProgress = false;
225
+ onPlace(menuBodyRef.current);
418
226
  }
227
+ placeInProgressRef.current = false;
419
228
  }
420
- }
421
- render() {
422
- const {
423
- context: prefix
424
- } = this;
425
- const focusTrapWithoutSentinels = FeatureFlags__namespace.enabled('enable-experimental-focus-wrap-without-sentinels');
426
- if (typeof document !== 'undefined') {
427
- const {
428
- focusTrap,
429
- target
430
- } = this.props;
431
- return /*#__PURE__*/ReactDOM__default["default"].createPortal(
432
- /*#__PURE__*/
433
- //eslint-disable-next-line jsx-a11y/no-static-element-interactions
434
- React__default["default"].createElement("div", {
435
- onBlur: focusTrap && !focusTrapWithoutSentinels ? this.handleBlur : () => {},
436
- onKeyDown: focusTrapWithoutSentinels ? this.handleKeyDown : () => {}
437
- }, !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
438
- ref: this.startSentinel,
439
- tabIndex: "0",
440
- role: "link",
441
- className: `${prefix}--visually-hidden`
442
- }, "Focus sentinel"), this._getChildrenWithProps(), !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
443
- ref: this.endSentinel,
444
- tabIndex: "0",
445
- role: "link",
446
- className: `${prefix}--visually-hidden`
447
- }, "Focus sentinel")), !target ? document.body : target());
448
- }
449
- return null;
450
- }
451
- }
452
- _rollupPluginBabelHelpers.defineProperty(FloatingMenu, "contextType", usePrefix.PrefixContext);
453
- _rollupPluginBabelHelpers.defineProperty(FloatingMenu, "propTypes", {
454
- /**
455
- * Contents to put into the floating menu.
456
- */
457
- children: PropTypes__default["default"].object,
458
- /**
459
- * `true` if the menu alignment should be flipped.
460
- */
461
- flipped: PropTypes__default["default"].bool,
462
- /**
463
- * Enable or disable focus trap behavior
464
- */
465
- focusTrap: PropTypes__default["default"].bool,
466
- /**
467
- * Where to put the tooltip, relative to the trigger button.
468
- */
469
- menuDirection: PropTypes__default["default"].oneOf([DIRECTION_LEFT, DIRECTION_TOP, DIRECTION_RIGHT, DIRECTION_BOTTOM]),
470
- /**
471
- * The adjustment of the floating menu position, considering the position of dropdown arrow, etc.
472
- */
473
- menuOffset: PropTypes__default["default"].oneOfType([PropTypes__default["default"].shape({
474
- top: PropTypes__default["default"].number,
475
- left: PropTypes__default["default"].number
476
- }), PropTypes__default["default"].func]),
477
- /**
478
- * The callback called when the menu body has been mounted to/will be unmounted from the DOM.
479
- */
480
- menuRef: PropTypes__default["default"].func,
481
- /**
482
- * The callback called when the menu body has been mounted and positioned.
483
- */
484
- onPlace: PropTypes__default["default"].func,
485
- /**
486
- * Specify a CSS selector that matches the DOM element that should
487
- * be focused when the Modal opens
488
- */
489
- selectorPrimaryFocus: PropTypes__default["default"].string,
490
- /**
491
- * The additional styles to put to the floating menu.
492
- */
493
- styles: PropTypes__default["default"].object,
229
+ }, [floatingPosition, onPlace]);
230
+
231
+ // Attach a resize listener.
232
+ React.useEffect(() => {
233
+ const resizeHandler = OptimizedResize["default"].add(() => {
234
+ updateMenuPosition();
235
+ });
236
+ return () => {
237
+ resizeHandler.release();
238
+ };
239
+ }, [triggerRef, menuOffset, menuDirection, flipped, target, updateOrientation]);
240
+
241
+ // Update menu position when key props change.
242
+ React.useEffect(() => {
243
+ updateMenuPosition();
244
+ }, [menuOffset, menuDirection, flipped, triggerRef, target, updateOrientation]);
245
+
494
246
  /**
495
- * The query selector indicating where the floating menu body should be placed.
247
+ * Clones the child element to add a `ref` and positioning styles.
496
248
  */
497
- target: PropTypes__default["default"].func,
249
+ const getChildrenWithProps = () => {
250
+ const pos = floatingPosition;
251
+ const positioningStyle = pos ? {
252
+ left: `${pos.left}px`,
253
+ top: `${pos.top}px`,
254
+ right: 'auto'
255
+ } : {
256
+ visibility: 'hidden',
257
+ top: '0px'
258
+ };
259
+ return /*#__PURE__*/React.cloneElement(children, {
260
+ ref: handleMenuRef,
261
+ style: {
262
+ ...styles,
263
+ ...positioningStyle,
264
+ position: 'absolute',
265
+ opacity: 1
266
+ }
267
+ });
268
+ };
269
+
498
270
  /**
499
- * The element ref of the tooltip's trigger button.
271
+ * Blur handler used when focus trapping is enabled.
500
272
  */
501
- triggerRef: PropTypes__default["default"].oneOfType([PropTypes__default["default"].func, PropTypes__default["default"].shape({
502
- current: PropTypes__default["default"].any
503
- })]),
273
+ const handleBlur = event => {
274
+ if (menuBodyRef.current && startSentinelRef.current && endSentinelRef.current) {
275
+ wrapFocus["default"]({
276
+ bodyNode: menuBodyRef.current,
277
+ startTrapNode: startSentinelRef.current,
278
+ endTrapNode: endSentinelRef.current,
279
+ currentActiveNode: event.relatedTarget,
280
+ oldActiveNode: event.target
281
+ });
282
+ }
283
+ };
284
+
504
285
  /**
505
- * Optional function to change orientation of tooltip based on parent
286
+ * Keydown handler for focus wrapping when experimental focus trap is enabled.
506
287
  */
507
- updateOrientation: PropTypes__default["default"].func
508
- });
509
- var FloatingMenu$1 = FloatingMenu;
288
+ const handleKeyDown = event => {
289
+ if (match.match(event, keys.Tab) && menuBodyRef.current) {
290
+ wrapFocus.wrapFocusWithoutSentinels({
291
+ containerNode: menuBodyRef.current,
292
+ currentActiveNode: event.target,
293
+ event
294
+ });
295
+ }
296
+ };
297
+ const focusTrapWithoutSentinels = FeatureFlags__namespace.enabled('enable-experimental-focus-wrap-without-sentinels');
298
+ if (typeof document !== 'undefined') {
299
+ const portalTarget = target ? target() : document.body;
300
+ return /*#__PURE__*/ReactDOM__default["default"].createPortal(/*#__PURE__*/React__default["default"].createElement("div", {
301
+ onBlur: focusTrap && !focusTrapWithoutSentinels ? handleBlur : undefined,
302
+ onKeyDown: focusTrapWithoutSentinels ? handleKeyDown : undefined
303
+ }, !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
304
+ ref: startSentinelRef,
305
+ tabIndex: 0,
306
+ role: "link",
307
+ className: `${prefix}--visually-hidden`
308
+ }, "Focus sentinel"), getChildrenWithProps(), !focusTrapWithoutSentinels && /*#__PURE__*/React__default["default"].createElement("span", {
309
+ ref: endSentinelRef,
310
+ tabIndex: 0,
311
+ role: "link",
312
+ className: `${prefix}--visually-hidden`
313
+ }, "Focus sentinel")), portalTarget);
314
+ }
315
+ return null;
316
+ };
510
317
 
511
318
  exports.DIRECTION_BOTTOM = DIRECTION_BOTTOM;
512
319
  exports.DIRECTION_LEFT = DIRECTION_LEFT;
513
320
  exports.DIRECTION_RIGHT = DIRECTION_RIGHT;
514
321
  exports.DIRECTION_TOP = DIRECTION_TOP;
515
- exports["default"] = FloatingMenu$1;
322
+ exports.FloatingMenu = FloatingMenu;