@atlaskit/dropdown-menu 13.1.0 → 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,43 @@
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
+
3
41
  ## 13.1.0
4
42
 
5
43
  ### Minor Changes
@@ -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();
@@ -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();
@@ -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
  /**
@@ -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
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/dropdown-menu",
3
- "version": "13.1.0",
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/"