@atlaskit/dropdown-menu 13.0.6 → 14.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @atlaskit/dropdown-menu
2
2
 
3
+ ## 14.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#134856](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/134856)
8
+ [`948a950e395ad`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/948a950e395ad) -
9
+ The `onOpenChange` prop type has been updated, to make the `event` parameter nullable. This
10
+ property is for the corresponding `event` that led to the callback being called.
11
+
12
+ This is to support programatically closing the dropdown menu.
13
+
14
+ We are also adding the native `Event` type in the type union, to better align with the underlying
15
+ `Popup` component that `DropdownMenu` is built on top of.
16
+
17
+ Previously, the type of `onOpenChange` was:
18
+
19
+ ```ts
20
+ onOpenChange?: (args: {
21
+ isOpen: boolean;
22
+ event: React.MouseEvent | React.KeyboardEvent;
23
+ }) => void;
24
+ ```
25
+
26
+ It is now:
27
+
28
+ ```ts
29
+ onOpenChange?: (args: {
30
+ isOpen: boolean;
31
+ event: Event | React.MouseEvent | React.KeyboardEvent | null;
32
+ }) => void;
33
+ ```
34
+
35
+ When the dropdown is closed programatically, the `event` parameter will be `null`.
36
+
37
+ ### Patch Changes
38
+
39
+ - Updated dependencies
40
+
41
+ ## 13.1.0
42
+
43
+ ### Minor Changes
44
+
45
+ - [#134128](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/134128)
46
+ [`8255a77865aac`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/8255a77865aac) -
47
+ Added support for an optional role attribute on dropdown items to allow customization of ARIA
48
+ roles. Defaults to menuitem.
49
+
3
50
  ## 13.0.6
4
51
 
5
52
  ### Patch Changes
@@ -15,7 +15,7 @@ var _customItem = _interopRequireDefault(require("@atlaskit/menu/custom-item"));
15
15
  var _linkItem = _interopRequireDefault(require("@atlaskit/menu/link-item"));
16
16
  var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
17
17
  var _useRegisterItemWithFocusManager = _interopRequireDefault(require("./internal/hooks/use-register-item-with-focus-manager"));
18
- var _excluded = ["children", "component", "description", "elemAfter", "elemBefore", "href", "isDisabled", "isSelected", "onClick", "rel", "shouldDescriptionWrap", "shouldTitleWrap", "target", "testId", "UNSAFE_shouldDisableRouterLink", "returnFocusRef", "interactionName"];
18
+ var _excluded = ["children", "component", "description", "elemAfter", "elemBefore", "href", "isDisabled", "isSelected", "onClick", "rel", "shouldDescriptionWrap", "shouldTitleWrap", "target", "testId", "UNSAFE_shouldDisableRouterLink", "returnFocusRef", "interactionName", "role"];
19
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
20
20
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
21
21
  /**
@@ -47,6 +47,7 @@ var DropdownMenuItem = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref)
47
47
  UNSAFE_shouldDisableRouterLink = _ref.UNSAFE_shouldDisableRouterLink,
48
48
  returnFocusRef = _ref.returnFocusRef,
49
49
  interactionName = _ref.interactionName,
50
+ role = _ref.role,
50
51
  rest = (0, _objectWithoutProperties2.default)(_ref, _excluded);
51
52
  // if the dropdown item has aria-haspopup, we won't register with focus manager
52
53
  // since it is a nested trigger, we have registered inside dropdown-menu
@@ -111,7 +112,7 @@ var DropdownMenuItem = /*#__PURE__*/(0, _react.forwardRef)(function (_ref, ref)
111
112
  isSelected: isSelected,
112
113
  onClick: handleItemClick,
113
114
  ref: (0, _mergeRefs.default)([ref, itemRef]),
114
- role: "menuitem",
115
+ role: role || 'menuitem',
115
116
  shouldDescriptionWrap: shouldDescriptionWrap,
116
117
  shouldTitleWrap: shouldTitleWrap,
117
118
  testId: testId
@@ -61,6 +61,9 @@ var getFallbackPlacements = function getFallbackPlacements(placement) {
61
61
  return ["".concat(mainAxis, "-start"), "".concat(mainAxis, "-end"), "".concat(opposites[mainAxis]), "".concat(opposites[mainAxis], "-start"), "".concat(opposites[mainAxis], "-end"), "auto"];
62
62
  }
63
63
  };
64
+ function isKeyboardEvent(event) {
65
+ return event !== null && (event instanceof KeyboardEvent || 'nativeEvent' in event && event.nativeEvent instanceof KeyboardEvent);
66
+ }
64
67
 
65
68
  /**
66
69
  * __Dropdown menu__
@@ -150,8 +153,9 @@ var DropdownMenu = function DropdownMenu(_ref) {
150
153
  });
151
154
  }, [isLocalOpen, setLocalIsOpen, onOpenChange, itemRef]);
152
155
  var handleOnClose = (0, _react.useCallback)(function (event, currentLevel) {
153
- var _event$target, _event$target$closest;
154
- if (event.key !== 'Escape' && event.key !== 'Tab' && (_event$target = event.target) !== null && _event$target !== void 0 && (_event$target$closest = _event$target.closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, "[id^=".concat(_useGeneratedId.PREFIX, "] [aria-haspopup]"))) {
156
+ var _event$target$closest, _event$target;
157
+ var isTabOrEscapeKey = isKeyboardEvent(event) && (event.key === 'Tab' || event.key === 'Escape');
158
+ if (event !== null && !isTabOrEscapeKey && event.target instanceof HTMLElement && (_event$target$closest = (_event$target = event.target).closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, "[id^=".concat(_useGeneratedId.PREFIX, "] [aria-haspopup]"))) {
155
159
  var _itemRef$current2;
156
160
  // Check if it is within dropdown and it is a trigger button
157
161
  // if it is a nested dropdown, clicking trigger won't close the dropdown
@@ -175,7 +179,7 @@ var DropdownMenu = function DropdownMenu(_ref) {
175
179
  var _returnFocusRef$curre;
176
180
  (_returnFocusRef$curre = returnFocusRef.current) === null || _returnFocusRef$curre === void 0 || _returnFocusRef$curre.focus();
177
181
  });
178
- } else if (event.key === 'Tab' && event.shiftKey || event.key === 'Escape') {
182
+ } else if (isKeyboardEvent(event) && (event.key === 'Tab' && event.shiftKey || event.key === 'Escape')) {
179
183
  requestAnimationFrame(function () {
180
184
  var _itemRef$current3;
181
185
  (_itemRef$current3 = itemRef.current) === null || _itemRef$current3 === void 0 || _itemRef$current3.focus();
@@ -33,6 +33,7 @@ const DropdownMenuItem = /*#__PURE__*/forwardRef(({
33
33
  UNSAFE_shouldDisableRouterLink,
34
34
  returnFocusRef,
35
35
  interactionName,
36
+ role,
36
37
  ...rest
37
38
  }, ref) => {
38
39
  // if the dropdown item has aria-haspopup, we won't register with focus manager
@@ -98,7 +99,7 @@ const DropdownMenuItem = /*#__PURE__*/forwardRef(({
98
99
  isSelected: isSelected,
99
100
  onClick: handleItemClick,
100
101
  ref: mergeRefs([ref, itemRef]),
101
- role: "menuitem",
102
+ role: role || 'menuitem',
102
103
  shouldDescriptionWrap: shouldDescriptionWrap,
103
104
  shouldTitleWrap: shouldTitleWrap,
104
105
  testId: testId
@@ -46,6 +46,9 @@ const getFallbackPlacements = placement => {
46
46
  return [`${mainAxis}-start`, `${mainAxis}-end`, `${opposites[mainAxis]}`, `${opposites[mainAxis]}-start`, `${opposites[mainAxis]}-end`, `auto`];
47
47
  }
48
48
  };
49
+ function isKeyboardEvent(event) {
50
+ return event !== null && (event instanceof KeyboardEvent || 'nativeEvent' in event && event.nativeEvent instanceof KeyboardEvent);
51
+ }
49
52
 
50
53
  /**
51
54
  * __Dropdown menu__
@@ -119,8 +122,9 @@ const DropdownMenu = ({
119
122
  });
120
123
  }, [isLocalOpen, setLocalIsOpen, onOpenChange, itemRef]);
121
124
  const handleOnClose = useCallback((event, currentLevel) => {
122
- var _event$target, _event$target$closest;
123
- if (event.key !== 'Escape' && event.key !== 'Tab' && (_event$target = event.target) !== null && _event$target !== void 0 && (_event$target$closest = _event$target.closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, `[id^=${PREFIX}] [aria-haspopup]`)) {
125
+ var _event$target$closest, _event$target;
126
+ const isTabOrEscapeKey = isKeyboardEvent(event) && (event.key === 'Tab' || event.key === 'Escape');
127
+ if (event !== null && !isTabOrEscapeKey && event.target instanceof HTMLElement && (_event$target$closest = (_event$target = event.target).closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, `[id^=${PREFIX}] [aria-haspopup]`)) {
124
128
  var _itemRef$current2;
125
129
  // Check if it is within dropdown and it is a trigger button
126
130
  // if it is a nested dropdown, clicking trigger won't close the dropdown
@@ -144,7 +148,7 @@ const DropdownMenu = ({
144
148
  var _returnFocusRef$curre;
145
149
  (_returnFocusRef$curre = returnFocusRef.current) === null || _returnFocusRef$curre === void 0 ? void 0 : _returnFocusRef$curre.focus();
146
150
  });
147
- } else if (event.key === 'Tab' && event.shiftKey || event.key === 'Escape') {
151
+ } else if (isKeyboardEvent(event) && (event.key === 'Tab' && event.shiftKey || event.key === 'Escape')) {
148
152
  requestAnimationFrame(() => {
149
153
  var _itemRef$current3;
150
154
  (_itemRef$current3 = itemRef.current) === null || _itemRef$current3 === void 0 ? void 0 : _itemRef$current3.focus();
@@ -1,6 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
2
  import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["children", "component", "description", "elemAfter", "elemBefore", "href", "isDisabled", "isSelected", "onClick", "rel", "shouldDescriptionWrap", "shouldTitleWrap", "target", "testId", "UNSAFE_shouldDisableRouterLink", "returnFocusRef", "interactionName"];
3
+ var _excluded = ["children", "component", "description", "elemAfter", "elemBefore", "href", "isDisabled", "isSelected", "onClick", "rel", "shouldDescriptionWrap", "shouldTitleWrap", "target", "testId", "UNSAFE_shouldDisableRouterLink", "returnFocusRef", "interactionName", "role"];
4
4
  import React, { forwardRef, useCallback } from 'react';
5
5
  import mergeRefs from '@atlaskit/ds-lib/merge-refs';
6
6
  import ButtonItem from '@atlaskit/menu/button-item';
@@ -37,6 +37,7 @@ var DropdownMenuItem = /*#__PURE__*/forwardRef(function (_ref, ref) {
37
37
  UNSAFE_shouldDisableRouterLink = _ref.UNSAFE_shouldDisableRouterLink,
38
38
  returnFocusRef = _ref.returnFocusRef,
39
39
  interactionName = _ref.interactionName,
40
+ role = _ref.role,
40
41
  rest = _objectWithoutProperties(_ref, _excluded);
41
42
  // if the dropdown item has aria-haspopup, we won't register with focus manager
42
43
  // since it is a nested trigger, we have registered inside dropdown-menu
@@ -101,7 +102,7 @@ var DropdownMenuItem = /*#__PURE__*/forwardRef(function (_ref, ref) {
101
102
  isSelected: isSelected,
102
103
  onClick: handleItemClick,
103
104
  ref: mergeRefs([ref, itemRef]),
104
- role: "menuitem",
105
+ role: role || 'menuitem',
105
106
  shouldDescriptionWrap: shouldDescriptionWrap,
106
107
  shouldTitleWrap: shouldTitleWrap,
107
108
  testId: testId
@@ -52,6 +52,9 @@ var getFallbackPlacements = function getFallbackPlacements(placement) {
52
52
  return ["".concat(mainAxis, "-start"), "".concat(mainAxis, "-end"), "".concat(opposites[mainAxis]), "".concat(opposites[mainAxis], "-start"), "".concat(opposites[mainAxis], "-end"), "auto"];
53
53
  }
54
54
  };
55
+ function isKeyboardEvent(event) {
56
+ return event !== null && (event instanceof KeyboardEvent || 'nativeEvent' in event && event.nativeEvent instanceof KeyboardEvent);
57
+ }
55
58
 
56
59
  /**
57
60
  * __Dropdown menu__
@@ -141,8 +144,9 @@ var DropdownMenu = function DropdownMenu(_ref) {
141
144
  });
142
145
  }, [isLocalOpen, setLocalIsOpen, onOpenChange, itemRef]);
143
146
  var handleOnClose = useCallback(function (event, currentLevel) {
144
- var _event$target, _event$target$closest;
145
- if (event.key !== 'Escape' && event.key !== 'Tab' && (_event$target = event.target) !== null && _event$target !== void 0 && (_event$target$closest = _event$target.closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, "[id^=".concat(PREFIX, "] [aria-haspopup]"))) {
147
+ var _event$target$closest, _event$target;
148
+ var isTabOrEscapeKey = isKeyboardEvent(event) && (event.key === 'Tab' || event.key === 'Escape');
149
+ if (event !== null && !isTabOrEscapeKey && event.target instanceof HTMLElement && (_event$target$closest = (_event$target = event.target).closest) !== null && _event$target$closest !== void 0 && _event$target$closest.call(_event$target, "[id^=".concat(PREFIX, "] [aria-haspopup]"))) {
146
150
  var _itemRef$current2;
147
151
  // Check if it is within dropdown and it is a trigger button
148
152
  // if it is a nested dropdown, clicking trigger won't close the dropdown
@@ -166,7 +170,7 @@ var DropdownMenu = function DropdownMenu(_ref) {
166
170
  var _returnFocusRef$curre;
167
171
  (_returnFocusRef$curre = returnFocusRef.current) === null || _returnFocusRef$curre === void 0 || _returnFocusRef$curre.focus();
168
172
  });
169
- } else if (event.key === 'Tab' && event.shiftKey || event.key === 'Escape') {
173
+ } else if (isKeyboardEvent(event) && (event.key === 'Tab' && event.shiftKey || event.key === 'Escape')) {
170
174
  requestAnimationFrame(function () {
171
175
  var _itemRef$current3;
172
176
  (_itemRef$current3 = itemRef.current) === null || _itemRef$current3 === void 0 || _itemRef$current3.focus();
@@ -51,7 +51,11 @@ export interface CustomTriggerProps<TriggerElement extends HTMLElement = any> ex
51
51
  }
52
52
  export interface OnOpenChangeArgs {
53
53
  isOpen: boolean;
54
- event: MouseEvent | KeyboardEvent;
54
+ /**
55
+ * The event that triggered the close.
56
+ * The value will be `null` when the dropdown is closed programatically and has no corresponding event.
57
+ */
58
+ event: Event | MouseEvent | KeyboardEvent | null;
55
59
  }
56
60
  export interface MenuWrapperProps extends MenuGroupProps {
57
61
  setInitialFocusRef?: ContentProps['setInitialFocusRef'];
@@ -150,6 +154,8 @@ interface InternalDropdownMenuProps<TriggerElement extends HTMLElement = any> {
150
154
  defaultOpen?: boolean;
151
155
  /**
152
156
  * Called when the menu should be open/closed. Receives an object with `isOpen` state.
157
+ *
158
+ * If the dropdown was closed programatically, the `event` parameter will be `null`.
153
159
  */
154
160
  onOpenChange?: (args: OnOpenChangeArgs) => void;
155
161
  /**
@@ -272,6 +278,13 @@ export interface DropdownItemProps {
272
278
  * An optional boolean value used to indicate if the dropdown item has popup or not.
273
279
  */
274
280
  'aria-haspopup'?: boolean | 'dialog';
281
+ /**
282
+ * An optional string value that specifies the role of the dropdown item.
283
+ * Use this to indicate whether the item is
284
+ * or presentational (e.g., 'presentation') for accessibility purposes.
285
+ * If not specified, it defaults to role="menuitem".
286
+ */
287
+ role?: string;
275
288
  }
276
289
  export interface DropdownItemCheckboxProps {
277
290
  /**
@@ -51,7 +51,11 @@ export interface CustomTriggerProps<TriggerElement extends HTMLElement = any> ex
51
51
  }
52
52
  export interface OnOpenChangeArgs {
53
53
  isOpen: boolean;
54
- event: MouseEvent | KeyboardEvent;
54
+ /**
55
+ * The event that triggered the close.
56
+ * The value will be `null` when the dropdown is closed programatically and has no corresponding event.
57
+ */
58
+ event: Event | MouseEvent | KeyboardEvent | null;
55
59
  }
56
60
  export interface MenuWrapperProps extends MenuGroupProps {
57
61
  setInitialFocusRef?: ContentProps['setInitialFocusRef'];
@@ -150,6 +154,8 @@ interface InternalDropdownMenuProps<TriggerElement extends HTMLElement = any> {
150
154
  defaultOpen?: boolean;
151
155
  /**
152
156
  * Called when the menu should be open/closed. Receives an object with `isOpen` state.
157
+ *
158
+ * If the dropdown was closed programatically, the `event` parameter will be `null`.
153
159
  */
154
160
  onOpenChange?: (args: OnOpenChangeArgs) => void;
155
161
  /**
@@ -272,6 +278,13 @@ export interface DropdownItemProps {
272
278
  * An optional boolean value used to indicate if the dropdown item has popup or not.
273
279
  */
274
280
  'aria-haspopup'?: boolean | 'dialog';
281
+ /**
282
+ * An optional string value that specifies the role of the dropdown item.
283
+ * Use this to indicate whether the item is
284
+ * or presentational (e.g., 'presentation') for accessibility purposes.
285
+ * If not specified, it defaults to role="menuitem".
286
+ */
287
+ role?: string;
275
288
  }
276
289
  export interface DropdownItemCheckboxProps {
277
290
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "13.0.6",
3
+ "version": "14.0.0",
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/"
@@ -28,9 +28,9 @@
28
28
  "@atlaskit/button": "^22.0.0",
29
29
  "@atlaskit/codemod-utils": "^4.2.0",
30
30
  "@atlaskit/ds-lib": "^4.0.0",
31
- "@atlaskit/icon": "^25.2.0",
31
+ "@atlaskit/icon": "^25.3.0",
32
32
  "@atlaskit/layering": "^2.0.0",
33
- "@atlaskit/menu": "^3.1.0",
33
+ "@atlaskit/menu": "^3.2.0",
34
34
  "@atlaskit/platform-feature-flags": "^1.1.0",
35
35
  "@atlaskit/popup": "^3.0.0",
36
36
  "@atlaskit/primitives": "^14.2.0",
@@ -56,7 +56,7 @@
56
56
  "@atlaskit/docs": "^10.0.0",
57
57
  "@atlaskit/form": "^12.0.0",
58
58
  "@atlaskit/heading": "^5.1.0",
59
- "@atlaskit/link": "^3.0.0",
59
+ "@atlaskit/link": "^3.1.0",
60
60
  "@atlaskit/lozenge": "^12.2.0",
61
61
  "@atlaskit/modal-dialog": "^14.0.0",
62
62
  "@atlaskit/section-message": "^8.2.0",