@atlaskit/dropdown-menu 11.5.2 → 11.5.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @atlaskit/dropdown-menu
2
2
 
3
+ ## 11.5.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [`625585b8db6`](https://bitbucket.org/atlassian/atlassian-frontend/commits/625585b8db6) - Bug fix to re-position the menu after change in loading state.
8
+ - Updated dependencies
9
+
3
10
  ## 11.5.2
4
11
 
5
12
  ### Patch Changes
@@ -35,12 +35,8 @@ var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/glyph/chevron-
35
35
 
36
36
  var _popup = _interopRequireDefault(require("@atlaskit/popup"));
37
37
 
38
- var _spinner = _interopRequireDefault(require("@atlaskit/spinner"));
39
-
40
38
  var _constants = require("@atlaskit/theme/constants");
41
39
 
42
- var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden"));
43
-
44
40
  var _focusManager = _interopRequireDefault(require("./internal/components/focus-manager"));
45
41
 
46
42
  var _menuWrapper = _interopRequireDefault(require("./internal/components/menu-wrapper"));
@@ -56,12 +52,6 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
56
52
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
57
53
 
58
54
  var gridSize = (0, _constants.gridSize)();
59
- var spinnerContainerStyles = (0, _react2.css)({
60
- display: 'flex',
61
- minWidth: "".concat(gridSize * 20, "px"),
62
- padding: "".concat(gridSize * 2.5, "px"),
63
- justifyContent: 'center'
64
- });
65
55
  var MAX_HEIGHT = "calc(100vh - ".concat(gridSize * 2, "px)");
66
56
  var opposites = {
67
57
  top: 'bottom',
@@ -116,8 +106,7 @@ var DropdownMenu = function DropdownMenu(props) {
116
106
  _props$autoFocus = props.autoFocus,
117
107
  autoFocus = _props$autoFocus === void 0 ? false : _props$autoFocus,
118
108
  testId = props.testId,
119
- _props$statusLabel = props.statusLabel,
120
- statusLabel = _props$statusLabel === void 0 ? 'Loading' : _props$statusLabel,
109
+ statusLabel = props.statusLabel,
121
110
  _props$zIndex = props.zIndex,
122
111
  zIndex = _props$zIndex === void 0 ? _constants.layers.modal() : _props$zIndex;
123
112
 
@@ -237,19 +226,17 @@ var DropdownMenu = function DropdownMenu(props) {
237
226
  }), _trigger);
238
227
  },
239
228
  content: function content(_ref) {
240
- var setInitialFocusRef = _ref.setInitialFocusRef;
229
+ var setInitialFocusRef = _ref.setInitialFocusRef,
230
+ update = _ref.update;
241
231
  return (0, _react2.jsx)(_focusManager.default, null, (0, _react2.jsx)(_menuWrapper.default, {
242
232
  maxHeight: MAX_HEIGHT,
243
233
  maxWidth: 800,
244
234
  onClose: handleOnClose,
235
+ onUpdate: update,
236
+ isLoading: isLoading,
237
+ statusLabel: statusLabel,
245
238
  setInitialFocusRef: isTriggeredUsingKeyboard || autoFocus ? setInitialFocusRef : undefined
246
- }, isLoading ? (0, _react2.jsx)("div", {
247
- css: spinnerContainerStyles
248
- }, (0, _react2.jsx)(_spinner.default, {
249
- size: "small"
250
- }), (0, _react2.jsx)(_visuallyHidden.default, {
251
- role: "status"
252
- }, statusLabel)) : children));
239
+ }, children));
253
240
  }
254
241
  }));
255
242
  };
@@ -2,8 +2,6 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
- var _typeof = require("@babel/runtime/helpers/typeof");
6
-
7
5
  Object.defineProperty(exports, "__esModule", {
8
6
  value: true
9
7
  });
@@ -13,22 +11,44 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
13
11
 
14
12
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
15
13
 
16
- var _react = _interopRequireWildcard(require("react"));
14
+ var _react = require("react");
15
+
16
+ var _react2 = require("@emotion/react");
17
17
 
18
18
  var _menuGroup = _interopRequireDefault(require("@atlaskit/menu/menu-group"));
19
19
 
20
+ var _spinner = _interopRequireDefault(require("@atlaskit/spinner"));
21
+
22
+ var _constants = require("@atlaskit/theme/constants");
23
+
24
+ var _visuallyHidden = _interopRequireDefault(require("@atlaskit/visually-hidden"));
25
+
20
26
  var _focusManager = require("../components/focus-manager");
21
27
 
22
28
  var _isCheckboxItem = _interopRequireDefault(require("../utils/is-checkbox-item"));
23
29
 
24
30
  var _isRadioItem = _interopRequireDefault(require("../utils/is-radio-item"));
25
31
 
26
- var _excluded = ["onClose", "setInitialFocusRef"];
27
-
28
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
29
-
30
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
32
+ var _excluded = ["onClose", "onUpdate", "isLoading", "statusLabel", "setInitialFocusRef", "children"];
33
+ var gridSize = (0, _constants.gridSize)();
34
+ var spinnerContainerStyles = (0, _react2.css)({
35
+ display: 'flex',
36
+ minWidth: "".concat(gridSize * 20, "px"),
37
+ padding: "".concat(gridSize * 2.5, "px"),
38
+ justifyContent: 'center'
39
+ });
31
40
 
41
+ var LoadingIndicator = function LoadingIndicator(_ref) {
42
+ var _ref$statusLabel = _ref.statusLabel,
43
+ statusLabel = _ref$statusLabel === void 0 ? 'Loading' : _ref$statusLabel;
44
+ return (0, _react2.jsx)("div", {
45
+ css: spinnerContainerStyles
46
+ }, (0, _react2.jsx)(_spinner.default, {
47
+ size: "small"
48
+ }), (0, _react2.jsx)(_visuallyHidden.default, {
49
+ role: "status"
50
+ }, statusLabel));
51
+ };
32
52
  /**
33
53
  *
34
54
  * MenuWrapper wraps all the menu items.
@@ -36,10 +56,16 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
36
56
  * if a CheckboxItem or RadioItem is clicked.
37
57
  * It also sets focus to the first menu item when opened.
38
58
  */
39
- var MenuWrapper = function MenuWrapper(_ref) {
40
- var onClose = _ref.onClose,
41
- setInitialFocusRef = _ref.setInitialFocusRef,
42
- props = (0, _objectWithoutProperties2.default)(_ref, _excluded);
59
+
60
+
61
+ var MenuWrapper = function MenuWrapper(_ref2) {
62
+ var onClose = _ref2.onClose,
63
+ onUpdate = _ref2.onUpdate,
64
+ isLoading = _ref2.isLoading,
65
+ statusLabel = _ref2.statusLabel,
66
+ setInitialFocusRef = _ref2.setInitialFocusRef,
67
+ children = _ref2.children,
68
+ props = (0, _objectWithoutProperties2.default)(_ref2, _excluded);
43
69
 
44
70
  var _useContext = (0, _react.useContext)(_focusManager.FocusManagerContext),
45
71
  menuItemRefs = _useContext.menuItemRefs;
@@ -56,14 +82,23 @@ var MenuWrapper = function MenuWrapper(_ref) {
56
82
  if (isTargetMenuItemOrDecendant && onClose) {
57
83
  onClose(e);
58
84
  }
59
- };
60
-
61
- setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]); // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
62
-
63
- return /*#__PURE__*/_react.default.createElement(_menuGroup.default, (0, _extends2.default)({
64
- role: "menu",
65
- onClick: closeOnMenuItemClick
66
- }, props));
85
+ }; // Using useEffect here causes a flicker.
86
+ // useLayoutEffect ensures that the update and render happen in the same
87
+ // rAF tick.
88
+
89
+
90
+ (0, _react.useLayoutEffect)(function () {
91
+ onUpdate();
92
+ }, [isLoading, onUpdate]);
93
+ setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]);
94
+ return (// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
95
+ (0, _react2.jsx)(_menuGroup.default, (0, _extends2.default)({
96
+ role: "menu",
97
+ onClick: closeOnMenuItemClick
98
+ }, props), isLoading ? (0, _react2.jsx)(LoadingIndicator, {
99
+ statusLabel: statusLabel
100
+ }) : children)
101
+ );
67
102
  };
68
103
 
69
104
  var _default = MenuWrapper;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "11.5.2",
3
+ "version": "11.5.3",
4
4
  "sideEffects": false
5
5
  }
@@ -2,7 +2,7 @@ import _extends from "@babel/runtime/helpers/extends";
2
2
 
3
3
  /** @jsx jsx */
4
4
  import { useCallback, useEffect, useMemo, useState } from 'react';
5
- import { css, jsx } from '@emotion/react';
5
+ import { jsx } from '@emotion/react';
6
6
  import { bind } from 'bind-event-listener';
7
7
  import Button from '@atlaskit/button/standard-button';
8
8
  import { KEY_DOWN } from '@atlaskit/ds-lib/keycodes';
@@ -11,20 +11,12 @@ import useControlledState from '@atlaskit/ds-lib/use-controlled';
11
11
  import useFocus from '@atlaskit/ds-lib/use-focus-event';
12
12
  import ExpandIcon from '@atlaskit/icon/glyph/chevron-down';
13
13
  import Popup from '@atlaskit/popup';
14
- import Spinner from '@atlaskit/spinner';
15
14
  import { gridSize as gridSizeFn, layers } from '@atlaskit/theme/constants';
16
- import VisuallyHidden from '@atlaskit/visually-hidden';
17
15
  import FocusManager from './internal/components/focus-manager';
18
16
  import MenuWrapper from './internal/components/menu-wrapper';
19
17
  import SelectionStore from './internal/context/selection-store';
20
18
  import useGeneratedId from './internal/utils/use-generated-id';
21
19
  const gridSize = gridSizeFn();
22
- const spinnerContainerStyles = css({
23
- display: 'flex',
24
- minWidth: `${gridSize * 20}px`,
25
- padding: `${gridSize * 2.5}px`,
26
- justifyContent: 'center'
27
- });
28
20
  const MAX_HEIGHT = `calc(100vh - ${gridSize * 2}px)`;
29
21
  const opposites = {
30
22
  top: 'bottom',
@@ -74,7 +66,7 @@ const DropdownMenu = props => {
74
66
  isLoading = false,
75
67
  autoFocus = false,
76
68
  testId,
77
- statusLabel = 'Loading',
69
+ statusLabel,
78
70
  zIndex = layers.modal()
79
71
  } = props;
80
72
  const [isLocalOpen, setLocalIsOpen] = useControlledState(isOpen, () => defaultOpen);
@@ -185,19 +177,17 @@ const DropdownMenu = props => {
185
177
  }), trigger);
186
178
  },
187
179
  content: ({
188
- setInitialFocusRef
180
+ setInitialFocusRef,
181
+ update
189
182
  }) => jsx(FocusManager, null, jsx(MenuWrapper, {
190
183
  maxHeight: MAX_HEIGHT,
191
184
  maxWidth: 800,
192
185
  onClose: handleOnClose,
186
+ onUpdate: update,
187
+ isLoading: isLoading,
188
+ statusLabel: statusLabel,
193
189
  setInitialFocusRef: isTriggeredUsingKeyboard || autoFocus ? setInitialFocusRef : undefined
194
- }, isLoading ? jsx("div", {
195
- css: spinnerContainerStyles
196
- }, jsx(Spinner, {
197
- size: "small"
198
- }), jsx(VisuallyHidden, {
199
- role: "status"
200
- }, statusLabel)) : children))
190
+ }, children))
201
191
  }));
202
192
  };
203
193
 
@@ -1,9 +1,32 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import React, { useContext } from 'react';
2
+
3
+ /** @jsx jsx */
4
+ import { useContext, useLayoutEffect } from 'react';
5
+ import { css, jsx } from '@emotion/react';
3
6
  import MenuGroup from '@atlaskit/menu/menu-group';
7
+ import Spinner from '@atlaskit/spinner';
8
+ import { gridSize as gridSizeFn } from '@atlaskit/theme/constants';
9
+ import VisuallyHidden from '@atlaskit/visually-hidden';
4
10
  import { FocusManagerContext } from '../components/focus-manager';
5
11
  import isCheckboxItem from '../utils/is-checkbox-item';
6
12
  import isRadioItem from '../utils/is-radio-item';
13
+ const gridSize = gridSizeFn();
14
+ const spinnerContainerStyles = css({
15
+ display: 'flex',
16
+ minWidth: `${gridSize * 20}px`,
17
+ padding: `${gridSize * 2.5}px`,
18
+ justifyContent: 'center'
19
+ });
20
+
21
+ const LoadingIndicator = ({
22
+ statusLabel = 'Loading'
23
+ }) => jsx("div", {
24
+ css: spinnerContainerStyles
25
+ }, jsx(Spinner, {
26
+ size: "small"
27
+ }), jsx(VisuallyHidden, {
28
+ role: "status"
29
+ }, statusLabel));
7
30
  /**
8
31
  *
9
32
  * MenuWrapper wraps all the menu items.
@@ -12,9 +35,14 @@ import isRadioItem from '../utils/is-radio-item';
12
35
  * It also sets focus to the first menu item when opened.
13
36
  */
14
37
 
38
+
15
39
  const MenuWrapper = ({
16
40
  onClose,
41
+ onUpdate,
42
+ isLoading,
43
+ statusLabel,
17
44
  setInitialFocusRef,
45
+ children,
18
46
  ...props
19
47
  }) => {
20
48
  const {
@@ -33,14 +61,23 @@ const MenuWrapper = ({
33
61
  if (isTargetMenuItemOrDecendant && onClose) {
34
62
  onClose(e);
35
63
  }
36
- };
64
+ }; // Using useEffect here causes a flicker.
65
+ // useLayoutEffect ensures that the update and render happen in the same
66
+ // rAF tick.
37
67
 
38
- setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]); // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
39
68
 
40
- return /*#__PURE__*/React.createElement(MenuGroup, _extends({
41
- role: "menu",
42
- onClick: closeOnMenuItemClick
43
- }, props));
69
+ useLayoutEffect(() => {
70
+ onUpdate();
71
+ }, [isLoading, onUpdate]);
72
+ setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]);
73
+ return (// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
74
+ jsx(MenuGroup, _extends({
75
+ role: "menu",
76
+ onClick: closeOnMenuItemClick
77
+ }, props), isLoading ? jsx(LoadingIndicator, {
78
+ statusLabel: statusLabel
79
+ }) : children)
80
+ );
44
81
  };
45
82
 
46
83
  export default MenuWrapper;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "11.5.2",
3
+ "version": "11.5.3",
4
4
  "sideEffects": false
5
5
  }
@@ -10,7 +10,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
10
10
 
11
11
  /** @jsx jsx */
12
12
  import { useCallback, useEffect, useMemo, useState } from 'react';
13
- import { css, jsx } from '@emotion/react';
13
+ import { jsx } from '@emotion/react';
14
14
  import { bind } from 'bind-event-listener';
15
15
  import Button from '@atlaskit/button/standard-button';
16
16
  import { KEY_DOWN } from '@atlaskit/ds-lib/keycodes';
@@ -19,20 +19,12 @@ import useControlledState from '@atlaskit/ds-lib/use-controlled';
19
19
  import useFocus from '@atlaskit/ds-lib/use-focus-event';
20
20
  import ExpandIcon from '@atlaskit/icon/glyph/chevron-down';
21
21
  import Popup from '@atlaskit/popup';
22
- import Spinner from '@atlaskit/spinner';
23
22
  import { gridSize as gridSizeFn, layers } from '@atlaskit/theme/constants';
24
- import VisuallyHidden from '@atlaskit/visually-hidden';
25
23
  import FocusManager from './internal/components/focus-manager';
26
24
  import MenuWrapper from './internal/components/menu-wrapper';
27
25
  import SelectionStore from './internal/context/selection-store';
28
26
  import useGeneratedId from './internal/utils/use-generated-id';
29
27
  var gridSize = gridSizeFn();
30
- var spinnerContainerStyles = css({
31
- display: 'flex',
32
- minWidth: "".concat(gridSize * 20, "px"),
33
- padding: "".concat(gridSize * 2.5, "px"),
34
- justifyContent: 'center'
35
- });
36
28
  var MAX_HEIGHT = "calc(100vh - ".concat(gridSize * 2, "px)");
37
29
  var opposites = {
38
30
  top: 'bottom',
@@ -87,8 +79,7 @@ var DropdownMenu = function DropdownMenu(props) {
87
79
  _props$autoFocus = props.autoFocus,
88
80
  autoFocus = _props$autoFocus === void 0 ? false : _props$autoFocus,
89
81
  testId = props.testId,
90
- _props$statusLabel = props.statusLabel,
91
- statusLabel = _props$statusLabel === void 0 ? 'Loading' : _props$statusLabel,
82
+ statusLabel = props.statusLabel,
92
83
  _props$zIndex = props.zIndex,
93
84
  zIndex = _props$zIndex === void 0 ? layers.modal() : _props$zIndex;
94
85
 
@@ -209,19 +200,17 @@ var DropdownMenu = function DropdownMenu(props) {
209
200
  }), _trigger);
210
201
  },
211
202
  content: function content(_ref) {
212
- var setInitialFocusRef = _ref.setInitialFocusRef;
203
+ var setInitialFocusRef = _ref.setInitialFocusRef,
204
+ update = _ref.update;
213
205
  return jsx(FocusManager, null, jsx(MenuWrapper, {
214
206
  maxHeight: MAX_HEIGHT,
215
207
  maxWidth: 800,
216
208
  onClose: handleOnClose,
209
+ onUpdate: update,
210
+ isLoading: isLoading,
211
+ statusLabel: statusLabel,
217
212
  setInitialFocusRef: isTriggeredUsingKeyboard || autoFocus ? setInitialFocusRef : undefined
218
- }, isLoading ? jsx("div", {
219
- css: spinnerContainerStyles
220
- }, jsx(Spinner, {
221
- size: "small"
222
- }), jsx(VisuallyHidden, {
223
- role: "status"
224
- }, statusLabel)) : children));
213
+ }, children));
225
214
  }
226
215
  }));
227
216
  };
@@ -1,11 +1,36 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["onClose", "setInitialFocusRef"];
4
- import React, { useContext } from 'react';
3
+ var _excluded = ["onClose", "onUpdate", "isLoading", "statusLabel", "setInitialFocusRef", "children"];
4
+
5
+ /** @jsx jsx */
6
+ import { useContext, useLayoutEffect } from 'react';
7
+ import { css, jsx } from '@emotion/react';
5
8
  import MenuGroup from '@atlaskit/menu/menu-group';
9
+ import Spinner from '@atlaskit/spinner';
10
+ import { gridSize as gridSizeFn } from '@atlaskit/theme/constants';
11
+ import VisuallyHidden from '@atlaskit/visually-hidden';
6
12
  import { FocusManagerContext } from '../components/focus-manager';
7
13
  import isCheckboxItem from '../utils/is-checkbox-item';
8
14
  import isRadioItem from '../utils/is-radio-item';
15
+ var gridSize = gridSizeFn();
16
+ var spinnerContainerStyles = css({
17
+ display: 'flex',
18
+ minWidth: "".concat(gridSize * 20, "px"),
19
+ padding: "".concat(gridSize * 2.5, "px"),
20
+ justifyContent: 'center'
21
+ });
22
+
23
+ var LoadingIndicator = function LoadingIndicator(_ref) {
24
+ var _ref$statusLabel = _ref.statusLabel,
25
+ statusLabel = _ref$statusLabel === void 0 ? 'Loading' : _ref$statusLabel;
26
+ return jsx("div", {
27
+ css: spinnerContainerStyles
28
+ }, jsx(Spinner, {
29
+ size: "small"
30
+ }), jsx(VisuallyHidden, {
31
+ role: "status"
32
+ }, statusLabel));
33
+ };
9
34
  /**
10
35
  *
11
36
  * MenuWrapper wraps all the menu items.
@@ -14,10 +39,15 @@ import isRadioItem from '../utils/is-radio-item';
14
39
  * It also sets focus to the first menu item when opened.
15
40
  */
16
41
 
17
- var MenuWrapper = function MenuWrapper(_ref) {
18
- var onClose = _ref.onClose,
19
- setInitialFocusRef = _ref.setInitialFocusRef,
20
- props = _objectWithoutProperties(_ref, _excluded);
42
+
43
+ var MenuWrapper = function MenuWrapper(_ref2) {
44
+ var onClose = _ref2.onClose,
45
+ onUpdate = _ref2.onUpdate,
46
+ isLoading = _ref2.isLoading,
47
+ statusLabel = _ref2.statusLabel,
48
+ setInitialFocusRef = _ref2.setInitialFocusRef,
49
+ children = _ref2.children,
50
+ props = _objectWithoutProperties(_ref2, _excluded);
21
51
 
22
52
  var _useContext = useContext(FocusManagerContext),
23
53
  menuItemRefs = _useContext.menuItemRefs;
@@ -34,14 +64,23 @@ var MenuWrapper = function MenuWrapper(_ref) {
34
64
  if (isTargetMenuItemOrDecendant && onClose) {
35
65
  onClose(e);
36
66
  }
37
- };
67
+ }; // Using useEffect here causes a flicker.
68
+ // useLayoutEffect ensures that the update and render happen in the same
69
+ // rAF tick.
38
70
 
39
- setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]); // eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
40
71
 
41
- return /*#__PURE__*/React.createElement(MenuGroup, _extends({
42
- role: "menu",
43
- onClick: closeOnMenuItemClick
44
- }, props));
72
+ useLayoutEffect(function () {
73
+ onUpdate();
74
+ }, [isLoading, onUpdate]);
75
+ setInitialFocusRef && setInitialFocusRef(menuItemRefs[0]);
76
+ return (// eslint-disable-next-line @repo/internal/react/no-unsafe-spread-props
77
+ jsx(MenuGroup, _extends({
78
+ role: "menu",
79
+ onClick: closeOnMenuItemClick
80
+ }, props), isLoading ? jsx(LoadingIndicator, {
81
+ statusLabel: statusLabel
82
+ }) : children)
83
+ );
45
84
  };
46
85
 
47
86
  export default MenuWrapper;
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "11.5.2",
3
+ "version": "11.5.3",
4
4
  "sideEffects": false
5
5
  }
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import { jsx } from '@emotion/react';
2
2
  import { MenuWrapperProps } from '../../types';
3
3
  /**
4
4
  *
@@ -7,5 +7,5 @@ import { MenuWrapperProps } from '../../types';
7
7
  * if a CheckboxItem or RadioItem is clicked.
8
8
  * It also sets focus to the first menu item when opened.
9
9
  */
10
- declare const MenuWrapper: ({ onClose, setInitialFocusRef, ...props }: MenuWrapperProps) => JSX.Element;
10
+ declare const MenuWrapper: ({ onClose, onUpdate, isLoading, statusLabel, setInitialFocusRef, children, ...props }: MenuWrapperProps) => jsx.JSX.Element;
11
11
  export default MenuWrapper;
@@ -46,6 +46,9 @@ export interface OnOpenChangeArgs {
46
46
  export interface MenuWrapperProps extends MenuGroupProps {
47
47
  setInitialFocusRef?: ContentProps['setInitialFocusRef'];
48
48
  onClose?: ContentProps['onClose'];
49
+ onUpdate: ContentProps['update'];
50
+ isLoading?: DropdownMenuProps['isLoading'];
51
+ statusLabel?: DropdownMenuProps['statusLabel'];
49
52
  }
50
53
  export interface DropdownMenuGroupProps extends SectionProps {
51
54
  }
@@ -1,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import { jsx } from '@emotion/react';
2
2
  import { MenuWrapperProps } from '../../types';
3
3
  /**
4
4
  *
@@ -7,5 +7,5 @@ import { MenuWrapperProps } from '../../types';
7
7
  * if a CheckboxItem or RadioItem is clicked.
8
8
  * It also sets focus to the first menu item when opened.
9
9
  */
10
- declare const MenuWrapper: ({ onClose, setInitialFocusRef, ...props }: MenuWrapperProps) => JSX.Element;
10
+ declare const MenuWrapper: ({ onClose, onUpdate, isLoading, statusLabel, setInitialFocusRef, children, ...props }: MenuWrapperProps) => jsx.JSX.Element;
11
11
  export default MenuWrapper;
@@ -46,6 +46,9 @@ export interface OnOpenChangeArgs {
46
46
  export interface MenuWrapperProps extends MenuGroupProps {
47
47
  setInitialFocusRef?: ContentProps['setInitialFocusRef'];
48
48
  onClose?: ContentProps['onClose'];
49
+ onUpdate: ContentProps['update'];
50
+ isLoading?: DropdownMenuProps['isLoading'];
51
+ statusLabel?: DropdownMenuProps['statusLabel'];
49
52
  }
50
53
  export interface DropdownMenuGroupProps extends SectionProps {
51
54
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "11.5.2",
3
+ "version": "11.5.3",
4
4
  "description": "A dropdown menu displays a list of actions or options to a user.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -32,13 +32,13 @@
32
32
  }
33
33
  },
34
34
  "dependencies": {
35
- "@atlaskit/button": "^16.3.0",
35
+ "@atlaskit/button": "^16.4.0",
36
36
  "@atlaskit/codemod-utils": "^4.1.0",
37
37
  "@atlaskit/ds-lib": "^2.1.0",
38
38
  "@atlaskit/icon": "^21.11.0",
39
- "@atlaskit/menu": "^1.3.0",
39
+ "@atlaskit/menu": "^1.4.0",
40
40
  "@atlaskit/popup": "^1.5.0",
41
- "@atlaskit/spinner": "^15.0.0",
41
+ "@atlaskit/spinner": "^15.2.0",
42
42
  "@atlaskit/theme": "^12.2.0",
43
43
  "@atlaskit/tokens": "^0.10.0",
44
44
  "@atlaskit/visually-hidden": "^1.1.0",
@@ -53,7 +53,7 @@
53
53
  "devDependencies": {
54
54
  "@atlaskit/avatar": "^21.1.0",
55
55
  "@atlaskit/docs": "*",
56
- "@atlaskit/lozenge": "11.2.5",
56
+ "@atlaskit/lozenge": "11.3.0",
57
57
  "@atlaskit/modal-dialog": "^12.4.0",
58
58
  "@atlaskit/section-message": "^6.3.0",
59
59
  "@atlaskit/ssr": "*",
package/report.api.md CHANGED
@@ -1,6 +1,10 @@
1
- ## API Report File for "@atlaskit/dropdown-menu".
1
+ ## API Report File for "@atlaskit/dropdown-menu"
2
2
 
3
- > Do not edit this file. This report is auto-generated by [API Extractor](https://api-extractor.com/).
3
+ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
4
+
5
+ <!--
6
+ Generated API Report version: 2.0
7
+ -->
4
8
 
5
9
  [Learn more about API reports](https://hello.atlassian.net/wiki/spaces/UR/pages/1825484529/Package+API+Reports)
6
10
 
@@ -19,363 +23,141 @@ import type { SectionProps } from '@atlaskit/menu';
19
23
  import type { SectionProps as SectionProps_2 } from '@atlaskit/menu/types';
20
24
  import type { TriggerProps } from '@atlaskit/popup/types';
21
25
 
22
- export declare interface CustomTriggerProps extends Omit<TriggerProps, 'ref'> {
23
- /**
24
- * Ref that should be applied to the trigger. This is used to calculate the menu position.
25
- */
26
- triggerRef: Ref<HTMLElement>;
27
- /**
28
- * Makes the trigger appear selected.
29
- */
26
+ // @public (undocumented)
27
+ export interface CustomTriggerProps<
28
+ TriggerElement extends HTMLElement = HTMLElement
29
+ > extends Omit<TriggerProps, 'ref'> {
30
30
  isSelected?: boolean;
31
- /**
32
- * Event that is triggered when the element is clicked.
33
- */
34
31
  onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
35
- /**
36
- * A `testId` prop is provided for specified elements, which is a unique
37
- * string that appears as a data attribute `data-testid` in the rendered code,
38
- * serving as a hook for automated tests.
39
- *
40
- * As dropdown-menu is composed of different components, we passed down the testId to the sub component you want to test:
41
- * - `testId--trigger` to get the menu trigger.
42
- * - `testId--content` to get the dropdown content trigger.
43
- */
44
32
  testId?: string;
33
+ triggerRef: Ref<TriggerElement>;
45
34
  }
46
35
 
47
- /**
48
- * __Dropdown menu item__
49
- *
50
- * A dropdown item populates the dropdown menu with items. Every item should be inside a dropdown item group.
51
- *
52
- * - [Examples](https://atlassian.design/components/dropdown-item/examples)
53
- * - [Code](https://atlassian.design/components/dropdown-item/code)
54
- * - [Usage](https://atlassian.design/components/dropdown-item/usage)
55
- */
56
- export declare const DropdownItem: (props: DropdownItemProps) => JSX.Element;
36
+ // @public
37
+ export const DropdownItem: (props: DropdownItemProps) => JSX.Element;
57
38
 
58
- /**
59
- * __Dropdown item checkbox__
60
- *
61
- * A dropdown item checkbox creates groups that have multiple selections.
62
- *
63
- * - [Examples](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/examples)
64
- * - [Code](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/code)
65
- * - [Usage](https://atlassian.design/components/dropdown-menu/dropdown-item-checkbox/usage)
66
- */
67
- export declare const DropdownItemCheckbox: (
39
+ // @public
40
+ export const DropdownItemCheckbox: (
68
41
  props: DropdownItemCheckboxProps,
69
42
  ) => JSX.Element;
70
43
 
71
- /**
72
- * __Dropdown item checkbox group__
73
- *
74
- * A wrapping element for dropdown menu checkbox items.
75
- *
76
- */
77
- export declare const DropdownItemCheckboxGroup: (
44
+ // @public
45
+ export const DropdownItemCheckboxGroup: (
78
46
  props: DropdownItemCheckboxGroupProps,
79
47
  ) => JSX.Element;
80
48
 
81
- declare interface DropdownItemCheckboxGroupProps extends SectionProps {
82
- /**
83
- * Unique identifier for the checkbox group.
84
- */
49
+ // @public (undocumented)
50
+ interface DropdownItemCheckboxGroupProps extends SectionProps {
85
51
  id: string;
86
52
  }
87
53
 
88
- declare interface DropdownItemCheckboxProps {
89
- /**
90
- * Primary content for the item.
91
- */
54
+ // @public (undocumented)
55
+ interface DropdownItemCheckboxProps {
92
56
  children: React.ReactNode;
93
- /**
94
- * Description of the item.
95
- * This will render smaller text below the primary text of the item as well as slightly increasing the height of the item.
96
- */
57
+ defaultSelected?: boolean;
97
58
  description?: string | JSX.Element;
98
- /**
99
- * Makes the checkbox appear disabled as well as removing interactivity.
100
- */
59
+ id: string;
101
60
  isDisabled?: boolean;
102
- /**
103
- * When `true` the title of the item will wrap multiple lines if it's long enough.
104
- */
105
- shouldTitleWrap?: boolean;
106
- /**
107
- * When `true` the description of the item will wrap multiple lines if it's long enough.
108
- */
109
- shouldDescriptionWrap?: boolean;
110
- /**
111
- * Event that is triggered when the checkbox is clicked.
112
- */
113
- onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
114
- /**
115
- * Sets whether the checkbox is checked or unchecked.
116
- */
117
61
  isSelected?: boolean;
118
- /**
119
- * Sets whether the checkbox begins selected.
120
- */
121
- defaultSelected?: boolean;
122
- /**
123
- * Unique id of a checkbox
124
- */
125
- id: string;
126
- /**
127
- * Adds a title attribute to the root item element.
128
- */
129
- title?: string;
130
- /**
131
- * A `testId` prop is provided for specified elements,
132
- * which is a unique string that appears as a data attribute `data-testid` in the rendered code,
133
- * serving as a hook for automated tests.
134
- */
62
+ onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
63
+ shouldDescriptionWrap?: boolean;
64
+ shouldTitleWrap?: boolean;
135
65
  testId?: string;
66
+ title?: string;
136
67
  }
137
68
 
138
69
  export { DropdownItemGroup };
139
70
 
140
- export declare interface DropdownItemProps {
141
- /**
142
- * Primary content for the item.
143
- */
71
+ // @public (undocumented)
72
+ export interface DropdownItemProps {
144
73
  children: React.ReactNode;
145
- /**
146
- * Custom component to render as an item.
147
- */
148
74
  component?: CustomItemProps['component'];
149
- /**
150
- * Description of the item.
151
- * This will render smaller text below the primary text of the item as well as slightly increasing the height of the item.
152
- */
153
75
  description?: string | JSX.Element;
154
- /**
155
- * Makes the element appear disabled as well as removing interactivity.
156
- */
76
+ elemAfter?: React.ReactNode;
77
+ elemBefore?: React.ReactNode;
78
+ href?: string;
157
79
  isDisabled?: boolean;
158
- /**
159
- * When `true` the title of the item will wrap multiple lines if it's long enough.
160
- */
161
- shouldTitleWrap?: boolean;
162
- /**
163
- * When `true` the description of the item will wrap multiple lines if it's long enough.
164
- */
165
- shouldDescriptionWrap?: boolean;
166
- /**
167
- * Event that is triggered when the element is clicked.
168
- */
169
- onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
170
- /**
171
- * Makes the element appear selected.
172
- */
173
80
  isSelected?: boolean;
174
- /**
175
- * Link to another page.
176
- */
177
- href?: string;
178
- /**
179
- * Where to display the linked URL,
180
- * see [anchor information](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) on mdn for more information.
181
- */
182
- target?: string;
183
- /**
184
- * Adds a title attribute to the root item element.
185
- */
186
- title?: string;
187
- /**
188
- * Element to render before the item text.
189
- * Generally should be an [icon](https://atlaskit.atlassian.com/packages/design-system/icon) component.
190
- */
191
- elemBefore?: React.ReactNode;
192
- /**
193
- * Element to render after the item text.
194
- * Generally should be an [icon](https://atlaskit.atlassian.com/packages/design-system/icon) component.
195
- */
196
- elemAfter?: React.ReactNode;
197
- /**
198
- * The relationship of the linked URL as space-separated link types.
199
- * Generally you'll want to set this to "noopener noreferrer" when `target` is "_blank".
200
- */
81
+ onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
201
82
  rel?: string;
202
- /**
203
- * A `testId` prop is provided for specified elements,
204
- * which is a unique string that appears as a data attribute `data-testid` in the rendered code,
205
- * serving as a hook for automated tests.
206
- */
83
+ shouldDescriptionWrap?: boolean;
84
+ shouldTitleWrap?: boolean;
85
+ target?: string;
207
86
  testId?: string;
87
+ title?: string;
208
88
  }
209
89
 
210
- /**
211
- * __Dropdown item radio__
212
- *
213
- * A dropdown item radio displays groups that have a single selection.
214
- *
215
- * - [Examples](https://atlassian.design/components/dropdown-menu/dropdown-item-radio/examples)
216
- * - [Code](https://atlassian.design/components/dropdown-menu/dropdown-item-radio/code)
217
- * - [Usage](https://atlassian.design/components/dropdown-menu/dropdown-item-radio/usage)
218
- */
219
- export declare const DropdownItemRadio: (
220
- props: DropdownItemRadioProps,
221
- ) => JSX.Element;
90
+ // @public
91
+ export const DropdownItemRadio: (props: DropdownItemRadioProps) => JSX.Element;
222
92
 
223
- /**
224
- * __Dropdown item radio group__
225
- * Store which manages the selection state for each DropdownItemRadio
226
- * across mount and unmounts.
227
- *
228
- */
229
- export declare const DropdownItemRadioGroup: (
93
+ // @public
94
+ export const DropdownItemRadioGroup: (
230
95
  props: DropdownItemRadioGroupProps,
231
96
  ) => JSX.Element;
232
97
 
233
- declare interface DropdownItemRadioGroupProps extends SectionProps {
98
+ // @public (undocumented)
99
+ interface DropdownItemRadioGroupProps extends SectionProps {
100
+ // (undocumented)
234
101
  id: string;
235
102
  }
236
103
 
237
- declare interface DropdownItemRadioProps {
238
- /**
239
- * Primary content for the item.
240
- */
104
+ // @public (undocumented)
105
+ interface DropdownItemRadioProps {
241
106
  children: React.ReactNode;
242
- /**
243
- * Description of the item.
244
- * This will render smaller text below the primary text of the item as well as slightly increasing the height of the item.
245
- */
107
+ defaultSelected?: boolean;
246
108
  description?: string | JSX.Element;
247
- /**
248
- * Makes the checkbox appear disabled as well as removing interactivity.
249
- */
109
+ id: string;
250
110
  isDisabled?: boolean;
251
- /**
252
- * When `true` the title of the item will wrap multiple lines if it's long enough.
253
- */
254
- shouldTitleWrap?: boolean;
255
- /**
256
- * When `true` the description of the item will wrap multiple lines if it's long enough.
257
- */
258
- shouldDescriptionWrap?: boolean;
259
- /**
260
- * Event that is triggered when the checkbox is clicked.
261
- */
262
- onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
263
- /**
264
- * Sets whether the checkbox is checked or unchecked.
265
- */
266
111
  isSelected?: boolean;
267
- /**
268
- * Sets whether the checkbox begins selected.
269
- */
270
- defaultSelected?: boolean;
271
- /**
272
- * Unique id of a checkbox
273
- */
274
- id: string;
275
- /**
276
- * Adds a title attribute to the root item element.
277
- */
278
- title?: string;
279
- /**
280
- * A `testId` prop is provided for specified elements,
281
- * which is a unique string that appears as a data attribute `data-testid` in the rendered code,
282
- * serving as a hook for automated tests.
283
- */
112
+ onClick?: (e: MouseEvent_2 | KeyboardEvent_2) => void;
113
+ shouldDescriptionWrap?: boolean;
114
+ shouldTitleWrap?: boolean;
284
115
  testId?: string;
116
+ title?: string;
285
117
  }
286
118
 
287
- /**
288
- * __Dropdown menu__
289
- *
290
- * A dropdown menu displays a list of actions or options to a user.
291
- *
292
- * - [Examples](https://atlassian.design/components/dropdown-menu/examples)
293
- * - [Code](https://atlassian.design/components/dropdown-menu/code)
294
- * - [Usage](https://atlassian.design/components/dropdown-menu/usage)
295
- */
296
- declare const DropdownMenu: (props: DropdownMenuProps) => jsx.JSX.Element;
119
+ // @public
120
+ const DropdownMenu: <T extends HTMLElement = HTMLElement>(
121
+ props: DropdownMenuProps<T>,
122
+ ) => jsx.JSX.Element;
297
123
  export default DropdownMenu;
298
124
 
299
- export declare interface DropdownMenuGroupProps extends SectionProps_2 {}
125
+ // @public (undocumented)
126
+ export interface DropdownMenuGroupProps extends SectionProps_2 {}
300
127
 
301
- export declare interface DropdownMenuProps {
302
- /**
303
- * Controls the appearance of the menu.
304
- * Default menu has scroll after its height exceeds the pre-defined amount.
305
- * Tall menu has no scroll until the height exceeds the height of the viewport.
306
- */
128
+ // @public (undocumented)
129
+ export interface DropdownMenuProps<
130
+ TriggerElement extends HTMLElement = HTMLElement
131
+ > {
307
132
  appearance?: 'default' | 'tall';
308
- /**
309
- * Controls if the first menu item receives focus when menu is opened. Note that the menu has a focus lock
310
- * which traps the focus within the menu. Also, the first item gets fouced automatically
311
- * if the menu is triggered using the keyboard.
312
- *
313
- */
314
133
  autoFocus?: boolean;
315
- /**
316
- * Content that will be rendered inside the layer element. Should typically be
317
- * `DropdownItemGroup` or `DropdownItem`, or checkbox / radio variants of those.
318
- */
319
134
  children?: ReactNode;
320
- /**
321
- * If true, a Spinner is rendered instead of the items
322
- */
135
+ defaultOpen?: boolean;
323
136
  isLoading?: boolean;
324
- /**
325
- * Text to be used as status for assistive technologies. Defaults to "Loading".
326
- */
327
- statusLabel?: string;
328
- /**
329
- * Controls the open state of the dropdown.
330
- */
331
137
  isOpen?: boolean;
332
- /**
333
- * Position of the menu.
334
- */
138
+ onOpenChange?: (args: OnOpenChangeArgs) => void;
335
139
  placement?: Placement;
336
- /**
337
- * Allows the dropdown menu to be placed on the opposite side of its trigger if it does not
338
- * fit in the viewport.
339
- */
340
140
  shouldFlip?: boolean;
341
- /**
342
- * Content which will trigger the dropdown menu to open and close. Use with `triggerType`
343
- * to easily get a button trigger.
344
- */
345
- trigger?: string | ((triggerButtonProps: CustomTriggerProps) => ReactElement);
346
- /**
347
- * A `testId` prop is provided for specified elements, which is a unique
348
- * string that appears as a data attribute `data-testid` in the rendered code,
349
- * serving as a hook for automated tests.
350
- *
351
- * As dropdown-menu is composed of different components, we passed down the testId to the sub component you want to test:
352
- * - `testId--trigger` to get the menu trigger.
353
- * - `testId--content` to get the dropdown content trigger.
354
- */
141
+ statusLabel?: string;
355
142
  testId?: string;
356
- /**
357
- * Controls the initial open state of the dropdown. If provided, the component is considered to be controlled
358
- * which means that the user is responsible for managing the open and close state of the menu.
359
- */
360
- defaultOpen?: boolean;
361
- /**
362
- * Called when the menu should be open/closed. Receives an object with `isOpen` state.
363
- */
364
- onOpenChange?: (args: OnOpenChangeArgs) => void;
365
- /**
366
- * Z-index that the popup should be displayed in.
367
- * This is passed to the portal component.
368
- * Defaults to `layers.modal()` from `@atlaskit/theme` which is 510.
369
- */
143
+ trigger?:
144
+ | string
145
+ | ((
146
+ triggerButtonProps: CustomTriggerProps<TriggerElement>,
147
+ ) => ReactElement);
370
148
  zIndex?: number;
371
149
  }
372
150
 
373
- export declare interface OnOpenChangeArgs {
374
- isOpen: boolean;
151
+ // @public (undocumented)
152
+ export interface OnOpenChangeArgs {
153
+ // (undocumented)
375
154
  event: MouseEvent_2 | KeyboardEvent_2;
155
+ // (undocumented)
156
+ isOpen: boolean;
376
157
  }
377
158
 
378
- declare type Placement =
159
+ // @public (undocumented)
160
+ type Placement =
379
161
  | 'auto-start'
380
162
  | 'auto'
381
163
  | 'auto-end'
@@ -392,5 +174,5 @@ declare type Placement =
392
174
  | 'left'
393
175
  | 'left-start';
394
176
 
395
- export {};
177
+ // (No @packageDocumentation comment for this package)
396
178
  ```