carbon-react 147.10.0 → 148.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.
Files changed (189) hide show
  1. package/esm/__internal__/checkable-input/checkable-input.component.js +9 -4
  2. package/esm/__internal__/checkable-input/hidden-checkable-input.component.js +9 -4
  3. package/esm/__internal__/input/input.component.js +9 -4
  4. package/esm/__internal__/radio-button-mapper/radio-button-mapper.component.js +1 -1
  5. package/esm/__internal__/utils/helpers/events/composedPath.d.ts +1 -1
  6. package/esm/__internal__/utils/helpers/events/events.d.ts +1 -1
  7. package/esm/components/accordion/accordion.component.js +1 -1
  8. package/esm/components/action-popover/action-popover-menu/action-popover-menu.component.js +1 -6
  9. package/esm/components/action-popover/action-popover.component.js +7 -2
  10. package/esm/components/advanced-color-picker/advanced-color-picker.component.d.ts +2 -2
  11. package/esm/components/advanced-color-picker/advanced-color-picker.component.js +1 -1
  12. package/esm/components/anchor-navigation/anchor-navigation.component.js +1 -1
  13. package/esm/components/box/box.component.js +1 -1
  14. package/esm/components/breadcrumbs/crumb/crumb.component.d.ts +1 -1
  15. package/esm/components/breadcrumbs/crumb/crumb.component.js +5 -1
  16. package/esm/components/breadcrumbs/crumb/crumb.style.d.ts +2 -2
  17. package/esm/components/button-toggle/button-toggle-group/button-toggle-group.component.js +1 -3
  18. package/esm/components/checkbox/checkbox.component.js +9 -4
  19. package/esm/components/content/content.style.js +2 -2
  20. package/esm/components/date/date.component.js +40 -60
  21. package/esm/components/decimal/decimal.component.js +10 -5
  22. package/esm/components/dialog/dialog.component.d.ts +1 -1
  23. package/esm/components/dialog-full-screen/dialog-full-screen.component.d.ts +1 -1
  24. package/esm/components/draggable/draggable-container.component.js +4 -1
  25. package/esm/components/drawer/drawer.component.js +1 -1
  26. package/esm/components/duelling-picklist/picklist-group/picklist-group.component.js +3 -0
  27. package/esm/components/grouped-character/grouped-character.component.js +9 -4
  28. package/esm/components/heading/heading.style.d.ts +1 -1
  29. package/esm/components/help/help.component.js +1 -1
  30. package/esm/components/hr/hr.component.d.ts +0 -1
  31. package/esm/components/image/image.style.d.ts +1 -1
  32. package/esm/components/link/link.component.d.ts +1 -3
  33. package/esm/components/link/link.component.js +5 -5
  34. package/esm/components/link/link.style.js +7 -4
  35. package/esm/components/loader-star/internal/star.component.d.ts +0 -1
  36. package/esm/components/loader-star/loader-star.component.d.ts +0 -1
  37. package/esm/components/menu/__internal__/menu.context.d.ts +1 -0
  38. package/esm/components/menu/__internal__/submenu/submenu.component.d.ts +1 -1
  39. package/esm/components/menu/__internal__/submenu/submenu.component.js +14 -37
  40. package/esm/components/menu/__internal__/submenu/submenu.context.d.ts +1 -2
  41. package/esm/components/menu/__internal__/submenu/submenu.style.js +0 -11
  42. package/esm/components/menu/menu-item/menu-item.component.js +39 -46
  43. package/esm/components/menu/menu-item/menu-item.style.d.ts +2 -2
  44. package/esm/components/menu/menu-item/menu-item.style.js +65 -83
  45. package/esm/components/menu/menu.component.js +1 -0
  46. package/esm/components/modal/modal.component.d.ts +1 -1
  47. package/esm/components/multi-action-button/multi-action-button.component.js +8 -4
  48. package/esm/components/number/number.component.js +9 -4
  49. package/esm/components/pager/pager.component.js +1 -1
  50. package/esm/components/pager/pager.style.d.ts +1 -1
  51. package/esm/components/pages/pages.component.js +1 -1
  52. package/esm/components/popover-container/popover-container.component.d.ts +1 -1
  53. package/esm/components/portrait/portrait.component.d.ts +2 -1
  54. package/esm/components/profile/profile.style.d.ts +1 -1
  55. package/esm/components/radio-button/radio-button.component.js +9 -4
  56. package/esm/components/radio-button/radio-button.style.d.ts +1 -1
  57. package/esm/components/search/search.component.js +0 -1
  58. package/esm/components/select/__internal__/select-list/select-list.component.d.ts +9 -8
  59. package/esm/components/select/__internal__/select-list/select-list.component.js +34 -66
  60. package/esm/components/select/__internal__/select-list/select-list.style.js +9 -3
  61. package/esm/components/select/__internal__/select-textbox/select-textbox.component.d.ts +1 -1
  62. package/esm/components/select/__internal__/select-textbox/select-textbox.component.js +10 -5
  63. package/esm/components/select/filterable-select/filterable-select.component.js +16 -13
  64. package/esm/components/select/multi-select/multi-select.component.js +12 -7
  65. package/esm/components/select/option/option.component.d.ts +6 -5
  66. package/esm/components/select/option/option.component.js +10 -5
  67. package/esm/components/select/option-row/option-row.component.d.ts +2 -2
  68. package/esm/components/select/simple-select/simple-select.component.d.ts +0 -7
  69. package/esm/components/select/simple-select/simple-select.component.js +12 -7
  70. package/esm/components/sidebar/sidebar.component.d.ts +1 -1
  71. package/esm/components/simple-color-picker/simple-color-picker.component.js +3 -6
  72. package/esm/components/split-button/split-button.component.js +8 -4
  73. package/esm/components/step-flow/step-flow.component.js +0 -1
  74. package/esm/components/switch/switch.component.js +9 -4
  75. package/esm/components/tabs/__internal__/tab-title/tab-title.component.js +2 -11
  76. package/esm/components/tabs/tab/tab.component.d.ts +3 -3
  77. package/esm/components/tabs/tabs.component.js +15 -25
  78. package/esm/components/text-editor/__internal__/editor-link/editor-link.style.d.ts +1 -1
  79. package/esm/components/textarea/textarea.component.js +9 -4
  80. package/esm/components/textbox/textbox.component.js +9 -4
  81. package/esm/components/tile/flex-tile-cell/flex-tile-cell.component.js +1 -1
  82. package/esm/components/tile/flex-tile-divider/flex-tile-divider.component.d.ts +0 -1
  83. package/esm/components/time/time.component.js +0 -1
  84. package/esm/components/toast/toast.style.d.ts +3 -3
  85. package/esm/components/typography/typography.style.d.ts +2 -2
  86. package/esm/components/vertical-divider/vertical-divider.component.d.ts +0 -1
  87. package/esm/components/vertical-menu/vertical-menu-full-screen/vertical-menu-full-screen.component.d.ts +1 -1
  88. package/esm/components/vertical-menu/vertical-menu-full-screen/vertical-menu-full-screen.component.js +1 -2
  89. package/esm/components/vertical-menu/vertical-menu-item/vertical-menu-item.component.d.ts +1 -1
  90. package/esm/hooks/__internal__/useCharacterCount/useCharacterCount.d.ts +0 -1
  91. package/esm/hooks/__internal__/useChildButtons/useChildButtons.d.ts +1 -1
  92. package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +1 -1
  93. package/esm/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +2 -2
  94. package/esm/hooks/__internal__/useStableCallback/useStableCallback.d.ts +1 -1
  95. package/lib/__internal__/checkable-input/checkable-input.component.js +9 -4
  96. package/lib/__internal__/checkable-input/hidden-checkable-input.component.js +9 -4
  97. package/lib/__internal__/input/input.component.js +9 -4
  98. package/lib/__internal__/radio-button-mapper/radio-button-mapper.component.js +1 -1
  99. package/lib/__internal__/utils/helpers/events/composedPath.d.ts +1 -1
  100. package/lib/__internal__/utils/helpers/events/events.d.ts +1 -1
  101. package/lib/components/accordion/accordion.component.js +1 -1
  102. package/lib/components/action-popover/action-popover-menu/action-popover-menu.component.js +1 -6
  103. package/lib/components/action-popover/action-popover.component.js +7 -2
  104. package/lib/components/advanced-color-picker/advanced-color-picker.component.d.ts +2 -2
  105. package/lib/components/advanced-color-picker/advanced-color-picker.component.js +1 -1
  106. package/lib/components/anchor-navigation/anchor-navigation.component.js +1 -1
  107. package/lib/components/box/box.component.js +1 -1
  108. package/lib/components/breadcrumbs/crumb/crumb.component.d.ts +1 -1
  109. package/lib/components/breadcrumbs/crumb/crumb.component.js +5 -1
  110. package/lib/components/breadcrumbs/crumb/crumb.style.d.ts +2 -2
  111. package/lib/components/button-toggle/button-toggle-group/button-toggle-group.component.js +1 -3
  112. package/lib/components/checkbox/checkbox.component.js +9 -4
  113. package/lib/components/content/content.style.js +2 -2
  114. package/lib/components/date/date.component.js +40 -60
  115. package/lib/components/decimal/decimal.component.js +10 -5
  116. package/lib/components/dialog/dialog.component.d.ts +1 -1
  117. package/lib/components/dialog-full-screen/dialog-full-screen.component.d.ts +1 -1
  118. package/lib/components/draggable/draggable-container.component.js +4 -1
  119. package/lib/components/drawer/drawer.component.js +1 -1
  120. package/lib/components/duelling-picklist/picklist-group/picklist-group.component.js +3 -0
  121. package/lib/components/grouped-character/grouped-character.component.js +9 -4
  122. package/lib/components/heading/heading.style.d.ts +1 -1
  123. package/lib/components/help/help.component.js +1 -1
  124. package/lib/components/hr/hr.component.d.ts +0 -1
  125. package/lib/components/image/image.style.d.ts +1 -1
  126. package/lib/components/link/link.component.d.ts +1 -3
  127. package/lib/components/link/link.component.js +5 -5
  128. package/lib/components/link/link.style.js +7 -4
  129. package/lib/components/loader-star/internal/star.component.d.ts +0 -1
  130. package/lib/components/loader-star/loader-star.component.d.ts +0 -1
  131. package/lib/components/menu/__internal__/menu.context.d.ts +1 -0
  132. package/lib/components/menu/__internal__/submenu/submenu.component.d.ts +1 -1
  133. package/lib/components/menu/__internal__/submenu/submenu.component.js +14 -37
  134. package/lib/components/menu/__internal__/submenu/submenu.context.d.ts +1 -2
  135. package/lib/components/menu/__internal__/submenu/submenu.style.js +0 -11
  136. package/lib/components/menu/menu-item/menu-item.component.js +38 -45
  137. package/lib/components/menu/menu-item/menu-item.style.d.ts +2 -2
  138. package/lib/components/menu/menu-item/menu-item.style.js +65 -83
  139. package/lib/components/menu/menu.component.js +1 -0
  140. package/lib/components/modal/modal.component.d.ts +1 -1
  141. package/lib/components/multi-action-button/multi-action-button.component.js +8 -4
  142. package/lib/components/number/number.component.js +9 -4
  143. package/lib/components/pager/pager.component.js +1 -1
  144. package/lib/components/pager/pager.style.d.ts +1 -1
  145. package/lib/components/pages/pages.component.js +1 -1
  146. package/lib/components/popover-container/popover-container.component.d.ts +1 -1
  147. package/lib/components/portrait/portrait.component.d.ts +2 -1
  148. package/lib/components/profile/profile.style.d.ts +1 -1
  149. package/lib/components/radio-button/radio-button.component.js +9 -4
  150. package/lib/components/radio-button/radio-button.style.d.ts +1 -1
  151. package/lib/components/search/search.component.js +0 -1
  152. package/lib/components/select/__internal__/select-list/select-list.component.d.ts +9 -8
  153. package/lib/components/select/__internal__/select-list/select-list.component.js +34 -66
  154. package/lib/components/select/__internal__/select-list/select-list.style.js +9 -3
  155. package/lib/components/select/__internal__/select-textbox/select-textbox.component.d.ts +1 -1
  156. package/lib/components/select/__internal__/select-textbox/select-textbox.component.js +10 -5
  157. package/lib/components/select/filterable-select/filterable-select.component.js +16 -13
  158. package/lib/components/select/multi-select/multi-select.component.js +12 -7
  159. package/lib/components/select/option/option.component.d.ts +6 -5
  160. package/lib/components/select/option/option.component.js +10 -5
  161. package/lib/components/select/option-row/option-row.component.d.ts +2 -2
  162. package/lib/components/select/simple-select/simple-select.component.d.ts +0 -7
  163. package/lib/components/select/simple-select/simple-select.component.js +12 -7
  164. package/lib/components/sidebar/sidebar.component.d.ts +1 -1
  165. package/lib/components/simple-color-picker/simple-color-picker.component.js +3 -6
  166. package/lib/components/split-button/split-button.component.js +8 -4
  167. package/lib/components/step-flow/step-flow.component.js +0 -1
  168. package/lib/components/switch/switch.component.js +9 -4
  169. package/lib/components/tabs/__internal__/tab-title/tab-title.component.js +2 -11
  170. package/lib/components/tabs/tab/tab.component.d.ts +3 -3
  171. package/lib/components/tabs/tabs.component.js +15 -25
  172. package/lib/components/text-editor/__internal__/editor-link/editor-link.style.d.ts +1 -1
  173. package/lib/components/textarea/textarea.component.js +9 -4
  174. package/lib/components/textbox/textbox.component.js +9 -4
  175. package/lib/components/tile/flex-tile-cell/flex-tile-cell.component.js +1 -1
  176. package/lib/components/tile/flex-tile-divider/flex-tile-divider.component.d.ts +0 -1
  177. package/lib/components/time/time.component.js +0 -1
  178. package/lib/components/toast/toast.style.d.ts +3 -3
  179. package/lib/components/typography/typography.style.d.ts +2 -2
  180. package/lib/components/vertical-divider/vertical-divider.component.d.ts +0 -1
  181. package/lib/components/vertical-menu/vertical-menu-full-screen/vertical-menu-full-screen.component.d.ts +1 -1
  182. package/lib/components/vertical-menu/vertical-menu-full-screen/vertical-menu-full-screen.component.js +1 -2
  183. package/lib/components/vertical-menu/vertical-menu-item/vertical-menu-item.component.d.ts +1 -1
  184. package/lib/hooks/__internal__/useCharacterCount/useCharacterCount.d.ts +0 -1
  185. package/lib/hooks/__internal__/useChildButtons/useChildButtons.d.ts +1 -1
  186. package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.d.ts +1 -1
  187. package/lib/hooks/__internal__/useMenuKeyboardNavigation/useMenuKeyboardNavigation.js +2 -2
  188. package/lib/hooks/__internal__/useStableCallback/useStableCallback.d.ts +1 -1
  189. package/package.json +31 -36
@@ -7,11 +7,11 @@ import Events from "../../../../__internal__/utils/helpers/events";
7
7
  import MenuContext from "../menu.context";
8
8
  import { characterNavigation } from "../keyboard-navigation";
9
9
  import SubmenuContext from "./submenu.context";
10
- import useClickAwayListener from "../../../../hooks/__internal__/useClickAwayListener";
11
10
  import guid from "../../../../__internal__/utils/helpers/guid";
12
11
  import { SCROLLABLE_BLOCK, SCROLLABLE_BLOCK_PARENT, BLOCK_INDEX_SELECTOR, ALL_CHILDREN_SELECTOR } from "../locators";
13
12
  import useStableCallback from "../../../../hooks/__internal__/useStableCallback/useStableCallback";
14
13
  import FixedNavigationBarContext from "../../../navigation-bar/__internal__/fixed-navigation-bar.context";
14
+ import { defaultFocusableSelectors as focusableSelectors } from "../../../../__internal__/focus-trap/focus-trap-utils";
15
15
  const Submenu = /*#__PURE__*/React.forwardRef(({
16
16
  children,
17
17
  className,
@@ -46,7 +46,6 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
46
46
  const [characterString, setCharacterString] = useState("");
47
47
  const [applyFocusRadius, setApplyFocusRadius] = useState(false);
48
48
  const [applyFocusRadiusToLastItem, setApplyFocusRadiusToLastItem] = useState(false);
49
- const shiftTabPressed = useRef(false);
50
49
  const focusFirstMenuItemOnOpen = useRef(false);
51
50
  const numberOfChildren = submenuItemIds.length;
52
51
  const {
@@ -137,7 +136,6 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
137
136
  }
138
137
  }, [submenuOpen, onSubmenuOpen]);
139
138
  const closeSubmenu = useCallback(() => {
140
- shiftTabPressed.current = false;
141
139
  setSubmenuOpen(false);
142
140
  setSubmenuFocusId(null);
143
141
  if (onSubmenuClose) {
@@ -166,38 +164,20 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
166
164
  const index = findCurrentIndex(submenuFocusId);
167
165
  let nextIndex = index;
168
166
  if (href && !submenuFocusId) {
169
- if (Events.isDownKey(event) || Events.isUpKey(event) || Events.isTabKey(event) && !Events.isShiftKey(event)) {
167
+ if (Events.isDownKey(event) || Events.isUpKey(event)) {
170
168
  event.preventDefault();
171
169
  setSubmenuFocusId(submenuItemIds[0]);
172
170
  return;
173
171
  }
174
172
  }
175
- if (Events.isTabKey(event) && !Events.isShiftKey(event)) {
176
- if (nextIndex === numberOfChildren - 1) {
177
- closeSubmenu();
178
- return;
179
- }
180
- shiftTabPressed.current = false;
181
- nextIndex += 1;
182
- }
183
- if (Events.isTabKey(event) && Events.isShiftKey(event)) {
184
- if (nextIndex <= 0) {
185
- closeSubmenu();
186
- return;
187
- }
188
- shiftTabPressed.current = true;
189
- nextIndex -= 1;
190
- }
191
173
  if (Events.isDownKey(event)) {
192
174
  event.preventDefault();
193
- shiftTabPressed.current = false;
194
175
  if (nextIndex < numberOfChildren - 1) {
195
176
  nextIndex += 1;
196
177
  }
197
178
  }
198
179
  if (Events.isUpKey(event)) {
199
180
  event.preventDefault();
200
- shiftTabPressed.current = false;
201
181
  setApplyFocusRadius(false);
202
182
  if (nextIndex > 0) {
203
183
  nextIndex -= 1;
@@ -210,17 +190,16 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
210
190
  }
211
191
  if (Events.isHomeKey(event)) {
212
192
  event.preventDefault();
213
- shiftTabPressed.current = false;
193
+ event.stopPropagation();
214
194
  nextIndex = 0;
215
195
  }
216
196
  if (Events.isEndKey(event)) {
217
197
  event.preventDefault();
218
- shiftTabPressed.current = false;
198
+ event.stopPropagation();
219
199
  nextIndex = numberOfChildren - 1;
220
200
  }
221
201
  if (event.key.length === 1) {
222
202
  event.stopPropagation();
223
- shiftTabPressed.current = false;
224
203
  if (characterTimer.current) {
225
204
  restartCharacterTimeout();
226
205
  } else {
@@ -230,7 +209,7 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
230
209
  } else {
231
210
  setCharacterString("");
232
211
  }
233
- const eventIsFromInput = Events.composedPath(event).find(p => p.getAttribute("data-element") === "input" || p.getAttribute("data-element") === "input-icon-toggle");
212
+ const eventIsFromInput = Events.composedPath(event.nativeEvent).find(p => p instanceof HTMLElement && (p.getAttribute("data-element") === "input" || p.getAttribute("data-element") === "input-icon-toggle"));
234
213
  if (!eventIsFromInput) {
235
214
  if (Events.isEnterKey(event)) {
236
215
  /* timeout enforces that the "closeSubmenu" method will be run after
@@ -250,7 +229,7 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
250
229
 
251
230
  /* istanbul ignore else */
252
231
  if (items) {
253
- setSubmenuItemIds(Array.from(items).map(item => item.getAttribute("id")));
232
+ setSubmenuItemIds(Array.from(items).filter(item => item.querySelector(focusableSelectors)).map(item => item.getAttribute("id")));
254
233
  }
255
234
  }
256
235
  }, [children, submenuOpen, submenuRef]);
@@ -260,11 +239,6 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
260
239
  setSubmenuFocusId(submenuItemIds[0]);
261
240
  }
262
241
  }, [submenuOpen, submenuFocusId, submenuItemIds]);
263
- const handleClickAway = () => {
264
- document.removeEventListener("click", handleClickAway);
265
- closeSubmenu();
266
- };
267
- const handleClickInside = useClickAwayListener(handleClickAway);
268
242
  const handleClick = event => {
269
243
  openSubmenu();
270
244
  if (onClick) {
@@ -281,13 +255,17 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
281
255
  }
282
256
  }
283
257
  }, [submenuRef, characterString, submenuItemIds]);
258
+ const handleSubmenuBlur = event => {
259
+ if (!event.currentTarget.contains(event.relatedTarget)) {
260
+ closeSubmenu();
261
+ }
262
+ };
284
263
  if (inFullscreenView) {
285
264
  return /*#__PURE__*/React.createElement(StyledSubmenuWrapper, {
286
265
  "data-component": "submenu-wrapper",
287
266
  inFullscreenView: inFullscreenView,
288
267
  asPassiveItem: asPassiveItem,
289
- menuType: menuContext.menuType,
290
- onClick: handleClickInside
268
+ menuType: menuContext.menuType
291
269
  }, /*#__PURE__*/React.createElement(StyledMenuItemWrapper, _extends({}, rest, {
292
270
  onClick: asPassiveItem ? undefined : onClick,
293
271
  className: className,
@@ -319,7 +297,6 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
319
297
  onMouseOver: !clickToOpen ? () => openSubmenu() : undefined,
320
298
  onMouseLeave: () => closeSubmenu(),
321
299
  isSubmenuOpen: submenuOpen,
322
- onClick: handleClickInside,
323
300
  ref: setSubmenuRef
324
301
  }, /*#__PURE__*/React.createElement(StyledMenuItemWrapper, _extends({}, rest, {
325
302
  className: className,
@@ -347,14 +324,14 @@ const Submenu = /*#__PURE__*/React.forwardRef(({
347
324
  maxHeight: submenuMaxHeight,
348
325
  applyFocusRadiusStyling: applyFocusRadius,
349
326
  applyFocusRadiusStylingToLastItem: applyFocusRadiusToLastItem,
350
- submenuMaxWidth: submenuMaxWidth
327
+ submenuMaxWidth: submenuMaxWidth,
328
+ onBlur: handleSubmenuBlur
351
329
  }, /*#__PURE__*/React.createElement(SubmenuContext.Provider, {
352
330
  value: {
353
331
  submenuFocusId,
354
332
  handleKeyDown,
355
333
  blockIndex,
356
334
  updateFocusId: setSubmenuFocusId,
357
- shiftTabPressed: shiftTabPressed.current,
358
335
  submenuHasMaxWidth: !!submenuMaxWidth
359
336
  }
360
337
  }, children)));
@@ -2,8 +2,7 @@ import React from "react";
2
2
  export interface SubmenuContextProps {
3
3
  submenuFocusId?: string | null;
4
4
  updateFocusId?: (id: string) => void;
5
- handleKeyDown?: (event: React.KeyboardEvent<HTMLAnchorElement>) => void;
6
- shiftTabPressed?: boolean;
5
+ handleKeyDown?: (event: React.KeyboardEvent<HTMLAnchorElement> | React.KeyboardEvent<HTMLButtonElement>) => void;
7
6
  blockIndex?: number;
8
7
  submenuHasMaxWidth?: boolean;
9
8
  }
@@ -149,7 +149,6 @@ const StyledSubmenu = styled.ul`
149
149
  display: flex;
150
150
  align-items: center;
151
151
  white-space: nowrap;
152
- cursor: pointer;
153
152
 
154
153
  ${inFullscreenView && css`
155
154
  white-space: normal;
@@ -169,16 +168,6 @@ const StyledSubmenu = styled.ul`
169
168
  background-color: ${menuConfigVariants[menuType].submenuItemBackground};
170
169
  }
171
170
 
172
- > a:hover,
173
- > button:hover {
174
- background-color: transparent;
175
- color: var(--colorsComponentsMenuYang100);
176
-
177
- > [data-component="icon"] {
178
- color: var(--colorsComponentsMenuYang100);
179
- }
180
- }
181
-
182
171
  > a,
183
172
  > button {
184
173
  padding: 11px 16px 12px;
@@ -1,7 +1,8 @@
1
1
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
- import React, { useRef, useEffect, useCallback, useContext } from "react";
2
+ import React, { useRef, useEffect, useContext } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import invariant from "invariant";
5
+ import { defaultFocusableSelectors as focusableSelectors } from "../../../__internal__/focus-trap/focus-trap-utils";
5
6
  import { filterStyledSystemPaddingProps } from "../../../style/utils";
6
7
  import StyledMenuItemWrapper from "./menu-item.style";
7
8
  import Events from "../../../__internal__/utils/helpers/events";
@@ -39,6 +40,7 @@ export const MenuItem = ({
39
40
  !(icon || children) ? process.env.NODE_ENV !== "production" ? invariant(false, "Either prop `icon` must be defined or this node must have `children`.") : invariant(false) : void 0;
40
41
  !(children || ariaLabel || typeof submenu === "string") ? process.env.NODE_ENV !== "production" ? invariant(false, "If no text is provided an `ariaLabel` should be given to facilitate accessibility.") : invariant(false) : void 0;
41
42
  !(typeof submenu === "boolean" || submenu === undefined || children && typeof submenu === "string" && submenu.length) ? process.env.NODE_ENV !== "production" ? invariant(false, "You should not pass `children` when `submenu` is an empty string") : invariant(false) : void 0;
43
+ const menuItemId = useRef(guid());
42
44
  const {
43
45
  isChildOfSegment,
44
46
  overriddenVariant
@@ -48,24 +50,21 @@ export const MenuItem = ({
48
50
  registerItem,
49
51
  unregisterItem,
50
52
  focusId,
51
- menuType,
52
- openSubmenuId
53
+ updateFocusId,
54
+ menuType
53
55
  } = useContext(MenuContext);
54
- const menuItemId = useRef(guid());
55
56
  const submenuContext = useContext(SubmenuContext);
57
+ const isInSubmenu = Object.keys(submenuContext).length > 0;
56
58
  const {
57
59
  submenuFocusId,
58
60
  updateFocusId: updateSubmenuFocusId,
59
61
  handleKeyDown: handleSubmenuKeyDown,
60
- shiftTabPressed,
61
62
  submenuHasMaxWidth
62
63
  } = submenuContext;
63
- const ref = useRef(null);
64
64
  const focusFromMenu = focusId === menuItemId.current;
65
65
  const focusFromSubmenu = submenuFocusId ? submenuFocusId === menuItemId.current : undefined;
66
- const inputRef = useRef(null);
67
- inputRef.current = ref.current ? ref.current.querySelector("[data-element='input']") : null;
68
- const focusRef = inputRef.current ? inputRef : ref;
66
+ const ref = useRef(null);
67
+ const firstFocusableChild = ref.current?.querySelector(focusableSelectors) ?? null;
69
68
  useEffect(() => {
70
69
  const id = menuItemId.current;
71
70
 
@@ -81,41 +80,35 @@ export const MenuItem = ({
81
80
  };
82
81
  }, [registerItem, unregisterItem]);
83
82
  useEffect(() => {
84
- const inputIcon = ref.current?.querySelector("[data-element='input-icon-toggle']");
85
- if (!openSubmenuId && focusFromSubmenu === undefined && focusFromMenu) {
86
- /* istanbul ignore else */
87
- if (focusRef.current) {
88
- focusRef.current?.focus();
89
- }
90
- } else if (focusFromSubmenu && !(shiftTabPressed && inputIcon?.getAttribute("tabindex") === "0")) {
91
- /* istanbul ignore else */
92
- if (focusRef.current) {
93
- focusRef.current?.focus();
83
+ if (focusFromMenu && !focusFromSubmenu || focusFromSubmenu) {
84
+ if (firstFocusableChild) {
85
+ firstFocusableChild.focus();
86
+ return;
94
87
  }
88
+ ref.current?.focus();
95
89
  }
96
- }, [openSubmenuId, focusFromMenu, focusFromSubmenu, shiftTabPressed, focusRef]);
97
- const updateFocusOnClick = useCallback(() => {
98
- if (updateSubmenuFocusId) {
99
- updateSubmenuFocusId(menuItemId.current);
100
- }
101
- }, [updateSubmenuFocusId]);
102
- const handleKeyDown = useCallback(event => {
103
- if (onKeyDown) {
104
- onKeyDown(event);
90
+ }, [firstFocusableChild, focusFromMenu, focusFromSubmenu]);
91
+ const handleFocus = event => {
92
+ if (isInSubmenu) {
93
+ event.stopPropagation();
94
+ updateSubmenuFocusId?.(menuItemId.current);
95
+ } else {
96
+ updateFocusId?.(menuItemId.current);
105
97
  }
106
- if (ref.current && Events.isEscKey(event)) {
98
+ };
99
+ const handleKeyDown = event => {
100
+ onKeyDown?.(event);
101
+ if (Events.isEscKey(event)) {
107
102
  ref.current?.focus();
108
103
  }
109
- if (handleSubmenuKeyDown) {
110
- handleSubmenuKeyDown(event);
111
- }
112
- }, [onKeyDown, handleSubmenuKeyDown]);
104
+ handleSubmenuKeyDown?.(event);
105
+ };
113
106
  const elementProps = {
114
107
  className: href || onClick ? "carbon-menu-item--has-link" : "",
115
- href,
108
+ href: firstFocusableChild ? undefined : href,
109
+ onClick: firstFocusableChild ? undefined : onClick,
116
110
  target,
117
111
  rel,
118
- onClick,
119
112
  icon,
120
113
  removeAriaLabelOnIcon: true,
121
114
  selected,
@@ -128,8 +121,7 @@ export const MenuItem = ({
128
121
  }
129
122
  const getTitle = title => maxWidth && typeof title === "string" ? title : undefined;
130
123
  const itemMaxWidth = !inFullscreenView ? maxWidth : undefined;
131
- const asPassiveItem = !(onClick || href);
132
- const hasInput = !!inputRef.current;
124
+ const asPassiveItem = !(onClick || href || firstFocusableChild);
133
125
  if (submenu) {
134
126
  return /*#__PURE__*/React.createElement(StyledMenuItem, _extends({
135
127
  "data-component": "menu-item",
@@ -137,12 +129,12 @@ export const MenuItem = ({
137
129
  "data-role": dataRole,
138
130
  menuType: menuType,
139
131
  title: getTitle(submenu),
140
- maxWidth: itemMaxWidth,
141
- onClick: updateFocusOnClick
132
+ maxWidth: itemMaxWidth
142
133
  }, rest, {
143
134
  inFullscreenView: inFullscreenView,
144
135
  id: menuItemId.current,
145
- as: as
136
+ as: as,
137
+ onFocus: handleFocus
146
138
  }), /*#__PURE__*/React.createElement(Submenu, _extends({}, typeof submenu !== "boolean" && {
147
139
  title: submenu
148
140
  }, {
@@ -160,19 +152,20 @@ export const MenuItem = ({
160
152
  }, rest), children));
161
153
  }
162
154
  const paddingProps = filterStyledSystemPaddingProps(rest);
155
+ const hasInput = !!ref.current?.querySelector("[data-element='input']");
163
156
  return /*#__PURE__*/React.createElement(StyledMenuItem, _extends({
164
157
  "data-component": "menu-item",
165
158
  "data-element": dataElement,
166
159
  "data-role": dataRole,
167
160
  menuType: menuType,
168
- inSubmenu: !!handleSubmenuKeyDown,
161
+ inSubmenu: isInSubmenu,
169
162
  title: getTitle(children),
170
163
  maxWidth: itemMaxWidth
171
164
  }, rest, {
172
165
  inFullscreenView: inFullscreenView && !Object.keys(submenuContext).length,
173
166
  id: menuItemId.current,
174
- onClick: updateFocusOnClick,
175
- as: as
167
+ as: as,
168
+ onFocus: handleFocus
176
169
  }), /*#__PURE__*/React.createElement(StyledMenuItemWrapper, _extends({
177
170
  menuType: menuType,
178
171
  "data-role": "menu-item-wrapper"
@@ -181,12 +174,12 @@ export const MenuItem = ({
181
174
  ariaLabel: ariaLabel,
182
175
  maxWidth: !submenuHasMaxWidth ? itemMaxWidth : undefined,
183
176
  inFullscreenView: inFullscreenView,
184
- asPassiveItem: asPassiveItem,
185
- placeholderTabIndex: asPassiveItem
177
+ asPassiveItem: asPassiveItem
186
178
  }, paddingProps, {
187
179
  asDiv: hasInput || as === "div",
180
+ hasFocusableChild: !!firstFocusableChild,
188
181
  hasInput: hasInput,
189
- inSubmenu: !!handleSubmenuKeyDown
182
+ inSubmenu: isInSubmenu
190
183
  }), children));
191
184
  };
192
185
  export default MenuItem;
@@ -9,15 +9,15 @@ interface StyledMenuItemWrapperProps extends Pick<MenuWithChildren, "href" | "sh
9
9
  isOpen?: boolean;
10
10
  inFullscreenView?: boolean;
11
11
  asPassiveItem?: boolean;
12
- placeholderTabIndex?: boolean;
13
12
  icon?: string;
14
13
  ariaLabel?: string;
15
14
  asDiv?: boolean;
15
+ hasFocusableChild?: boolean;
16
16
  hasInput?: boolean;
17
17
  menuItemVariant?: Pick<MenuWithChildren, "variant">["variant"];
18
18
  inSubmenu?: boolean;
19
19
  }
20
20
  declare const StyledMenuItemWrapper: import("styled-components").StyledComponent<"a", any, {
21
- as: import("react").ForwardRefExoticComponent<import("../../link").LinkProps & import("react").RefAttributes<HTMLButtonElement | HTMLLinkElement>>;
21
+ as: import("react").ForwardRefExoticComponent<import("../../link").LinkProps & import("react").RefAttributes<HTMLAnchorElement | HTMLButtonElement>>;
22
22
  } & StyledMenuItemWrapperProps, "as">;
23
23
  export default StyledMenuItemWrapper;
@@ -91,6 +91,7 @@ const StyledMenuItemWrapper = styled.a.attrs({
91
91
  overrideColor,
92
92
  asPassiveItem,
93
93
  asDiv,
94
+ hasFocusableChild,
94
95
  hasInput,
95
96
  inSubmenu
96
97
  }) => css`
@@ -104,7 +105,6 @@ const StyledMenuItemWrapper = styled.a.attrs({
104
105
 
105
106
  a,
106
107
  button {
107
- cursor: pointer;
108
108
  min-height: 40px;
109
109
  height: 100%;
110
110
  box-sizing: border-box;
@@ -174,7 +174,7 @@ const StyledMenuItemWrapper = styled.a.attrs({
174
174
  background-color: transparent;
175
175
  }
176
176
 
177
- ${!asDiv && css`
177
+ ${!asDiv && !asPassiveItem && css`
178
178
  background-color: var(--colorsComponentsMenuAutumnStandard600);
179
179
  color: var(--colorsComponentsMenuYang100);
180
180
 
@@ -190,63 +190,61 @@ const StyledMenuItemWrapper = styled.a.attrs({
190
190
  }
191
191
  `}
192
192
 
193
- ${asPassiveItem ? `
194
- ${!inFullscreenView && `
195
- > a:not(:has(button)) {
196
- padding: 11px 16px;
197
- }
193
+ ${hasFocusableChild && css`
194
+ ${!inFullscreenView && css`
195
+ > a:not(:has(button)) {
196
+ padding: 11px 16px;
197
+ }
198
198
 
199
- > a:has(${StyledButton}:not(.search-button)) {
200
- height: 100%;
199
+ > a:has(${StyledButton}:not(.search-button)) {
200
+ height: 100%;
201
201
 
202
- ${StyledContent} {
203
- height: inherit;
202
+ ${StyledContent} {
203
+ height: inherit;
204
204
 
205
- div {
206
- height: inherit;
207
- }
208
- }
209
-
210
- ${StyledButton} {
211
- min-height: 40px;
212
- padding: 10px 0px;
213
- box-sizing: border-box;
214
- height: 100%;
215
- }
205
+ div {
206
+ height: inherit;
216
207
  }
217
- `}
218
-
219
- ${StyledIconButton} {
220
- > span {
221
- display: inline-flex;
222
- margin-right: 0;
223
208
  }
224
209
 
225
- :focus {
226
- outline: none;
227
- [data-component="icon"] {
228
- color: ${menuConfigVariants[menuType].color};
229
- }
210
+ ${StyledButton} {
211
+ min-height: 40px;
212
+ padding: 10px 0px;
213
+ box-sizing: border-box;
214
+ height: 100%;
230
215
  }
231
216
  }
232
- ` : `
233
- ${hasSubmenu || maxWidth && !inFullscreenView ? `
234
- a,
235
- ${StyledLink} a,
236
- button,
237
- ${StyledLink} button {
238
- padding: 11px 16px ${hasSubmenu && maxWidth ? "12px" : "10px"};
239
- }
240
- ` : `
241
- a,
242
- ${StyledLink} a,
243
- button,
244
- ${StyledLink} button {
245
- padding: ${!inFullscreenView ? "11px" : "0px"} 16px;
246
- }
247
- `}
248
217
  `}
249
218
 
219
+ ${StyledIconButton} {
220
+ > span {
221
+ display: inline-flex;
222
+ margin-right: 0;
223
+ }
224
+
225
+ :focus {
226
+ outline: none;
227
+ [data-component="icon"] {
228
+ color: ${menuConfigVariants[menuType].color};
229
+ }
230
+ }
231
+ }
232
+ `}
233
+
234
+ ${!hasFocusableChild && !inFullscreenView && css`
235
+ ${hasSubmenu || maxWidth ? css`
236
+ > a,
237
+ > button {
238
+ padding: 11px 16px ${hasSubmenu && maxWidth ? "12px" : "10px"};
239
+ }
240
+ ` : css`
241
+ > a,
242
+ > button {
243
+ padding: 11px 16px;
244
+ }
245
+ `}
246
+ `}
247
+
250
248
  button,
251
249
  ${StyledLink} button,
252
250
  a,
@@ -422,28 +420,10 @@ const StyledMenuItemWrapper = styled.a.attrs({
422
420
  }
423
421
  `}
424
422
 
425
- ${asPassiveItem && css`
426
- cursor: default;
427
-
428
- a {
429
- padding: 0 16px;
430
- }
431
-
432
- :hover {
433
- background: transparent;
434
- }
435
- `}
436
-
437
-
438
423
  > a, > button {
439
- min-height: 40px;
440
- line-height: 40px;
441
- }
442
-
443
- a,
444
- ${StyledLink} a,
445
- button,
446
- ${StyledLink} button {
424
+ min-height: 40px;
425
+ line-height: 40px;
426
+ padding: 0px 16px;
447
427
  width: 100vw;
448
428
  box-sizing: border-box;
449
429
  }
@@ -454,21 +434,23 @@ const StyledMenuItemWrapper = styled.a.attrs({
454
434
  position: relative;
455
435
  }
456
436
 
457
- && {
458
- > a:focus,
459
- > a:hover,
460
- > button:focus,
461
- > button:hover {
462
- background-color: var(--colorsComponentsMenuAutumnStandard600);
463
- color: var(--colorsComponentsMenuYang100);
437
+ ${!asPassiveItem && css`
438
+ && {
439
+ > a:focus,
440
+ > a:hover,
441
+ > button:focus,
442
+ > button:hover {
443
+ background-color: var(--colorsComponentsMenuAutumnStandard600);
444
+ color: var(--colorsComponentsMenuYang100);
464
445
 
465
- ${!hasInput && `
466
- [data-component="icon"] {
467
- color: var(--colorsComponentsMenuYang100);
468
- }
469
- `}
446
+ ${!hasInput && css`
447
+ [data-component="icon"] {
448
+ color: var(--colorsComponentsMenuYang100);
449
+ }
450
+ `}
451
+ }
470
452
  }
471
- }
453
+ `}
472
454
  }
473
455
  `}
474
456
  `}
@@ -54,6 +54,7 @@ export const Menu = ({
54
54
  openSubmenuId,
55
55
  setOpenSubmenuId,
56
56
  focusId,
57
+ updateFocusId: setFocusId,
57
58
  registerItem,
58
59
  unregisterItem
59
60
  }
@@ -18,7 +18,7 @@ export interface ModalProps extends Omit<TagProps, "data-component"> {
18
18
  /** Determines if the background is disabled when the modal is open */
19
19
  enableBackgroundUI?: boolean;
20
20
  /** A custom close event handler */
21
- onCancel?: (ev: React.KeyboardEvent<HTMLElement>) => void;
21
+ onCancel?: (ev: React.KeyboardEvent<HTMLElement> | KeyboardEvent) => void;
22
22
  /** Sets the open state of the modal */
23
23
  open: boolean;
24
24
  /** Transition time */
@@ -98,14 +98,18 @@ if (process.env.NODE_ENV !== "production") {
98
98
  "aria-activedescendant": PropTypes.string,
99
99
  "aria-atomic": PropTypes.oneOfType([PropTypes.oneOf(["false", "true"]), PropTypes.bool]),
100
100
  "aria-autocomplete": PropTypes.oneOf(["both", "inline", "list", "none"]),
101
+ "aria-braillelabel": PropTypes.string,
102
+ "aria-brailleroledescription": PropTypes.string,
101
103
  "aria-busy": PropTypes.oneOfType([PropTypes.oneOf(["false", "true"]), PropTypes.bool]),
102
104
  "aria-checked": PropTypes.oneOfType([PropTypes.oneOf(["false", "mixed", "true"]), PropTypes.bool]),
103
105
  "aria-colcount": PropTypes.number,
104
106
  "aria-colindex": PropTypes.number,
107
+ "aria-colindextext": PropTypes.string,
105
108
  "aria-colspan": PropTypes.number,
106
109
  "aria-controls": PropTypes.string,
107
110
  "aria-current": PropTypes.oneOfType([PropTypes.oneOf(["date", "false", "location", "page", "step", "time", "true"]), PropTypes.bool]),
108
111
  "aria-describedby": PropTypes.string,
112
+ "aria-description": PropTypes.string,
109
113
  "aria-details": PropTypes.string,
110
114
  "aria-disabled": PropTypes.oneOfType([PropTypes.oneOf(["false", "true"]), PropTypes.bool]),
111
115
  "aria-dropeffect": PropTypes.oneOf(["copy", "execute", "link", "move", "none", "popup"]),
@@ -135,6 +139,7 @@ if (process.env.NODE_ENV !== "production") {
135
139
  "aria-roledescription": PropTypes.string,
136
140
  "aria-rowcount": PropTypes.number,
137
141
  "aria-rowindex": PropTypes.number,
142
+ "aria-rowindextext": PropTypes.string,
138
143
  "aria-rowspan": PropTypes.number,
139
144
  "aria-selected": PropTypes.oneOfType([PropTypes.oneOf(["false", "true"]), PropTypes.bool]),
140
145
  "aria-setsize": PropTypes.number,
@@ -202,7 +207,7 @@ if (process.env.NODE_ENV !== "production") {
202
207
  "className": PropTypes.string,
203
208
  "color": PropTypes.string,
204
209
  "content": PropTypes.string,
205
- "contentEditable": PropTypes.oneOfType([PropTypes.oneOf(["false", "inherit", "true"]), PropTypes.bool]),
210
+ "contentEditable": PropTypes.oneOfType([PropTypes.oneOf(["false", "inherit", "plaintext-only", "true"]), PropTypes.bool]),
206
211
  "contextMenu": PropTypes.string,
207
212
  "dangerouslySetInnerHTML": PropTypes.shape({
208
213
  "__html": PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired
@@ -500,9 +505,7 @@ if (process.env.NODE_ENV !== "production") {
500
505
  "onPointerDown": PropTypes.func,
501
506
  "onPointerDownCapture": PropTypes.func,
502
507
  "onPointerEnter": PropTypes.func,
503
- "onPointerEnterCapture": PropTypes.func,
504
508
  "onPointerLeave": PropTypes.func,
505
- "onPointerLeaveCapture": PropTypes.func,
506
509
  "onPointerMove": PropTypes.func,
507
510
  "onPointerMoveCapture": PropTypes.func,
508
511
  "onPointerOut": PropTypes.func,
@@ -517,6 +520,8 @@ if (process.env.NODE_ENV !== "production") {
517
520
  "onRateChangeCapture": PropTypes.func,
518
521
  "onReset": PropTypes.func,
519
522
  "onResetCapture": PropTypes.func,
523
+ "onResize": PropTypes.func,
524
+ "onResizeCapture": PropTypes.func,
520
525
  "onScroll": PropTypes.func,
521
526
  "onScrollCapture": PropTypes.func,
522
527
  "onSeeked": PropTypes.func,
@@ -549,7 +554,6 @@ if (process.env.NODE_ENV !== "production") {
549
554
  "onWaitingCapture": PropTypes.func,
550
555
  "onWheel": PropTypes.func,
551
556
  "onWheelCapture": PropTypes.func,
552
- "placeholder": PropTypes.string,
553
557
  "position": PropTypes.oneOf(["left", "right"]),
554
558
  "prefix": PropTypes.string,
555
559
  "property": PropTypes.string,