@carbon/react 1.54.0 → 1.55.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 (62) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1065 -1012
  2. package/es/components/CodeSnippet/CodeSnippet.Skeleton.d.ts +37 -0
  3. package/es/components/CodeSnippet/CodeSnippet.d.ts +196 -0
  4. package/es/components/CodeSnippet/CodeSnippet.js +20 -19
  5. package/es/components/CodeSnippet/index.d.ts +10 -0
  6. package/es/components/ComboBox/ComboBox.d.ts +2 -2
  7. package/es/components/ComboBox/ComboBox.js +13 -5
  8. package/es/components/ComboButton/index.d.ts +51 -0
  9. package/es/components/ComboButton/index.js +9 -7
  10. package/es/components/ComposedModal/ComposedModal.d.ts +1 -1
  11. package/es/components/ComposedModal/ComposedModal.js +6 -6
  12. package/es/components/DataTable/TableBatchAction.d.ts +1 -5
  13. package/es/components/Dropdown/Dropdown.js +3 -1
  14. package/es/components/Modal/Modal.js +3 -3
  15. package/es/components/MultiSelect/FilterableMultiSelect.js +31 -0
  16. package/es/components/MultiSelect/MultiSelect.js +37 -7
  17. package/es/components/Slug/index.js +8 -13
  18. package/es/components/Tabs/Tabs.js +44 -13
  19. package/es/components/Tag/DismissibleTag.js +119 -0
  20. package/es/components/Tag/OperationalTag.js +99 -0
  21. package/es/components/Tag/SelectableTag.js +98 -0
  22. package/es/components/Tag/index.d.ts +4 -1
  23. package/es/components/TreeView/TreeNode.js +1 -1
  24. package/es/components/UIShell/HeaderMenu.d.ts +219 -0
  25. package/es/components/UIShell/HeaderMenu.js +22 -10
  26. package/es/components/UIShell/SideNavMenu.js +11 -1
  27. package/es/components/UIShell/SideNavMenuItem.d.ts +4 -0
  28. package/es/components/UIShell/SideNavMenuItem.js +8 -1
  29. package/es/components/UIShell/SwitcherItem.d.ts +4 -0
  30. package/es/components/UIShell/SwitcherItem.js +6 -0
  31. package/es/index.js +5 -2
  32. package/lib/components/CodeSnippet/CodeSnippet.Skeleton.d.ts +37 -0
  33. package/lib/components/CodeSnippet/CodeSnippet.d.ts +196 -0
  34. package/lib/components/CodeSnippet/CodeSnippet.js +20 -19
  35. package/lib/components/CodeSnippet/index.d.ts +10 -0
  36. package/lib/components/ComboBox/ComboBox.d.ts +2 -2
  37. package/lib/components/ComboBox/ComboBox.js +13 -5
  38. package/lib/components/ComboButton/index.d.ts +51 -0
  39. package/lib/components/ComboButton/index.js +9 -7
  40. package/lib/components/ComposedModal/ComposedModal.d.ts +1 -1
  41. package/lib/components/ComposedModal/ComposedModal.js +5 -5
  42. package/lib/components/DataTable/TableBatchAction.d.ts +1 -5
  43. package/lib/components/Dropdown/Dropdown.js +3 -1
  44. package/lib/components/Modal/Modal.js +3 -3
  45. package/lib/components/MultiSelect/FilterableMultiSelect.js +31 -0
  46. package/lib/components/MultiSelect/MultiSelect.js +37 -7
  47. package/lib/components/Slug/index.js +8 -13
  48. package/lib/components/Tabs/Tabs.js +44 -13
  49. package/lib/components/Tag/DismissibleTag.js +129 -0
  50. package/lib/components/Tag/OperationalTag.js +109 -0
  51. package/lib/components/Tag/SelectableTag.js +108 -0
  52. package/lib/components/Tag/index.d.ts +4 -1
  53. package/lib/components/TreeView/TreeNode.js +1 -1
  54. package/lib/components/UIShell/HeaderMenu.d.ts +219 -0
  55. package/lib/components/UIShell/HeaderMenu.js +22 -10
  56. package/lib/components/UIShell/SideNavMenu.js +11 -1
  57. package/lib/components/UIShell/SideNavMenuItem.d.ts +4 -0
  58. package/lib/components/UIShell/SideNavMenuItem.js +8 -1
  59. package/lib/components/UIShell/SwitcherItem.d.ts +4 -0
  60. package/lib/components/UIShell/SwitcherItem.js +6 -0
  61. package/lib/index.js +10 -4
  62. package/package.json +4 -4
@@ -36,7 +36,7 @@ const rowHeightInPixels = 16;
36
36
  const defaultMaxCollapsedNumberOfRows = 15;
37
37
  const defaultMaxExpandedNumberOfRows = 0;
38
38
  const defaultMinCollapsedNumberOfRows = 3;
39
- const defaultMinExpandedNumberOfRows = 0;
39
+ const defaultMinExpandedNumberOfRows = 16;
40
40
  function CodeSnippet(_ref) {
41
41
  let {
42
42
  align = 'bottom',
@@ -67,9 +67,9 @@ function CodeSnippet(_ref) {
67
67
  const {
68
68
  current: uid
69
69
  } = React.useRef(uniqueId["default"]());
70
- const codeContentRef = React.useRef();
71
- const codeContainerRef = React.useRef();
72
- const innerCodeRef = React.useRef();
70
+ const codeContentRef = React.useRef(null);
71
+ const codeContainerRef = React.useRef(null);
72
+ const innerCodeRef = React.useRef(null);
73
73
  const [hasLeftOverflow, setHasLeftOverflow] = React.useState(false);
74
74
  const [hasRightOverflow, setHasRightOverflow] = React.useState(false);
75
75
  const getCodeRef = React.useCallback(() => {
@@ -78,15 +78,17 @@ function CodeSnippet(_ref) {
78
78
  }
79
79
  if (type === 'multi') {
80
80
  return codeContentRef;
81
+ } else {
82
+ return innerCodeRef;
81
83
  }
82
84
  }, [type]);
83
85
  const prefix = usePrefix.usePrefix();
84
86
  const getCodeRefDimensions = React.useCallback(() => {
85
87
  const {
86
- clientWidth: codeClientWidth,
87
- scrollLeft: codeScrollLeft,
88
- scrollWidth: codeScrollWidth
89
- } = getCodeRef().current;
88
+ clientWidth: codeClientWidth = 0,
89
+ scrollLeft: codeScrollLeft = 0,
90
+ scrollWidth: codeScrollWidth = 0
91
+ } = getCodeRef().current || {};
90
92
  return {
91
93
  horizontalOverflow: codeScrollWidth > codeClientWidth,
92
94
  codeClientWidth,
@@ -113,7 +115,7 @@ function CodeSnippet(_ref) {
113
115
  if (codeContentRef?.current && type === 'multi') {
114
116
  const {
115
117
  height
116
- } = innerCodeRef.current.getBoundingClientRect();
118
+ } = codeContentRef.current.getBoundingClientRect();
117
119
  if (maxCollapsedNumberOfRows > 0 && (maxExpandedNumberOfRows <= 0 || maxExpandedNumberOfRows > maxCollapsedNumberOfRows) && height > maxCollapsedNumberOfRows * rowHeightInPixels) {
118
120
  setShouldShowMoreLessBtn(true);
119
121
  } else {
@@ -127,13 +129,13 @@ function CodeSnippet(_ref) {
127
129
  handleScroll();
128
130
  }
129
131
  }
130
- }, [type, maxCollapsedNumberOfRows, maxExpandedNumberOfRows, minExpandedNumberOfRows, rowHeightInPixels]);
132
+ });
131
133
  React.useEffect(() => {
132
134
  handleScroll();
133
135
  }, [handleScroll]);
134
136
  const handleCopyClick = evt => {
135
137
  if (copyText || innerCodeRef?.current) {
136
- copy__default["default"](copyText ?? innerCodeRef?.current?.innerText);
138
+ copy__default["default"](copyText ?? innerCodeRef?.current?.innerText ?? '');
137
139
  }
138
140
  if (onClick) {
139
141
  onClick(evt);
@@ -167,12 +169,11 @@ function CodeSnippet(_ref) {
167
169
  feedback: feedback,
168
170
  feedbackTimeout: feedbackTimeout
169
171
  }), /*#__PURE__*/React__default["default"].createElement("code", {
170
- "aria-live": "assertive",
171
172
  id: uid,
172
173
  ref: innerCodeRef
173
174
  }, children));
174
175
  }
175
- let containerStyle = {};
176
+ const containerStyle = {};
176
177
  if (type === 'multi') {
177
178
  const styles = {};
178
179
  if (expandedCode) {
@@ -198,16 +199,16 @@ function CodeSnippet(_ref) {
198
199
  className: codeSnippetClasses
199
200
  }), /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
200
201
  ref: codeContainerRef,
201
- role: type === 'single' || type === 'multi' ? 'textbox' : null,
202
- tabIndex: (type === 'single' || type === 'multi') && !disabled ? 0 : null,
202
+ role: type === 'single' || type === 'multi' ? 'textbox' : undefined,
203
+ tabIndex: (type === 'single' || type === 'multi') && !disabled ? 0 : undefined,
203
204
  className: `${prefix}--snippet-container`,
204
205
  "aria-label": deprecatedAriaLabel || ariaLabel || 'code-snippet',
205
- "aria-readonly": type === 'single' || type === 'multi' ? true : null,
206
- "aria-multiline": type === 'multi' ? true : null,
207
- onScroll: type === 'single' && handleScroll || null
206
+ "aria-readonly": type === 'single' || type === 'multi' ? true : undefined,
207
+ "aria-multiline": type === 'multi' ? true : undefined,
208
+ onScroll: type === 'single' && handleScroll || undefined
208
209
  }, containerStyle), /*#__PURE__*/React__default["default"].createElement("pre", {
209
210
  ref: codeContentRef,
210
- onScroll: type === 'multi' && handleScroll || null
211
+ onScroll: type === 'multi' && handleScroll || undefined
211
212
  }, /*#__PURE__*/React__default["default"].createElement("code", {
212
213
  ref: innerCodeRef
213
214
  }, children))), hasLeftOverflow && /*#__PURE__*/React__default["default"].createElement("div", {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import CodeSnippet from './CodeSnippet';
8
+ export default CodeSnippet;
9
+ export { CodeSnippet };
10
+ export { default as CodeSnippetSkeleton } from './CodeSnippet.Skeleton';
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import Downshift from 'downshift';
8
8
  import { ReactNodeLike } from 'prop-types';
9
- import { type ComponentProps, type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithoutRef, type InputHTMLAttributes, type MouseEvent } from 'react';
9
+ import { type ComponentProps, type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithRef, type InputHTMLAttributes, type MouseEvent } from 'react';
10
10
  import { ListBoxSize } from '../ListBox';
11
11
  type ExcludedAttributes = 'id' | 'onChange' | 'onClick' | 'type' | 'size';
12
12
  interface OnChangeData<ItemType> {
@@ -159,7 +159,7 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
159
159
  */
160
160
  warnText?: ReactNode;
161
161
  }
162
- type ComboboxComponentProps<ItemType> = PropsWithoutRef<PropsWithChildren<ComboBoxProps<ItemType>> & RefAttributes<HTMLInputElement>>;
162
+ type ComboboxComponentProps<ItemType> = PropsWithRef<PropsWithChildren<ComboBoxProps<ItemType>> & RefAttributes<HTMLInputElement>>;
163
163
  interface ComboBoxComponent {
164
164
  <ItemType>(props: ComboboxComponentProps<ItemType>): ReactElement | null;
165
165
  }
@@ -42,9 +42,11 @@ const {
42
42
  keyDownArrowUp,
43
43
  keyDownEscape,
44
44
  clickButton,
45
+ clickItem,
45
46
  blurButton,
46
47
  changeInput,
47
- blurInput
48
+ blurInput,
49
+ unknown
48
50
  } = Downshift__default["default"].stateChangeTypes;
49
51
  const defaultItemToString = item => {
50
52
  if (typeof item === 'string') {
@@ -206,15 +208,16 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
206
208
  switch (type) {
207
209
  case keyDownArrowDown:
208
210
  case keyDownArrowUp:
209
- setHighlightedIndex(changes.highlightedIndex);
211
+ if (changes.isOpen) {
212
+ updateHighlightedIndex(getHighlightedIndex(changes));
213
+ } else {
214
+ setHighlightedIndex(changes.highlightedIndex);
215
+ }
210
216
  break;
211
217
  case blurButton:
212
218
  case keyDownEscape:
213
219
  setHighlightedIndex(changes.highlightedIndex);
214
220
  break;
215
- case clickButton:
216
- setHighlightedIndex(changes.highlightedIndex);
217
- break;
218
221
  case changeInput:
219
222
  updateHighlightedIndex(getHighlightedIndex(changes));
220
223
  break;
@@ -229,6 +232,11 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
229
232
  }
230
233
  }
231
234
  break;
235
+ case clickButton:
236
+ case clickItem:
237
+ case unknown:
238
+ setHighlightedIndex(getHighlightedIndex(changes));
239
+ break;
232
240
  }
233
241
  };
234
242
  const handleToggleClick = isOpen => event => {
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright IBM Corp. 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import { IconButton } from '../IconButton';
9
+ import Button from '../Button';
10
+ import { Menu } from '../Menu';
11
+ interface ComboButtonProps {
12
+ /**
13
+ * A collection of `MenuItems` to be rendered as additional actions for this `ComboButton`.
14
+ */
15
+ children: React.ComponentProps<typeof Menu>['children'];
16
+ /**
17
+ * Additional CSS class names.
18
+ */
19
+ className?: string;
20
+ /**
21
+ * Specify whether the `ComboButton` should be disabled, or not.
22
+ */
23
+ disabled?: boolean;
24
+ /**
25
+ * Provide the label to be rendered on the primary action button.
26
+ */
27
+ label: React.ComponentProps<typeof Button>['title'];
28
+ /**
29
+ * Experimental property. Specify how the menu should align with the button element
30
+ */
31
+ menuAlignment?: React.ComponentProps<typeof Menu>['menuAlignment'];
32
+ /**
33
+ * Provide an optional function to be called when the primary action element is clicked.
34
+ */
35
+ onClick?: React.ComponentProps<typeof Button>['onClick'];
36
+ /**
37
+ * Specify the size of the buttons and menu.
38
+ */
39
+ size?: 'sm' | 'md' | 'lg';
40
+ /**
41
+ * Specify how the trigger tooltip should be aligned.
42
+ */
43
+ tooltipAlignment?: React.ComponentProps<typeof IconButton>['align'];
44
+ /**
45
+ * Optional method that takes in a message `id` and returns an
46
+ * internationalized string.
47
+ */
48
+ translateWithId?: (id: string) => string;
49
+ }
50
+ declare const ComboButton: React.ForwardRefExoticComponent<ComboButtonProps & React.RefAttributes<HTMLDivElement>>;
51
+ export { ComboButton, type ComboButtonProps };
@@ -80,10 +80,12 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
80
80
  }
81
81
  }
82
82
  function handleOpen() {
83
- menuRef.current.style.inlineSize = `${width}px`;
84
- menuRef.current.style.minInlineSize = `${width}px`;
85
- if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
86
- menuRef.current.style.inlineSize = `fit-content`;
83
+ if (menuRef.current) {
84
+ menuRef.current.style.inlineSize = `${width}px`;
85
+ menuRef.current.style.minInlineSize = `${width}px`;
86
+ if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
87
+ menuRef.current.style.inlineSize = `fit-content`;
88
+ }
87
89
  }
88
90
  }
89
91
  const containerClasses = cx__default["default"](`${prefix}--combo-button__container`, `${prefix}--combo-button__container--${size}`, {
@@ -95,7 +97,7 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
95
97
  return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
96
98
  className: containerClasses,
97
99
  ref: ref,
98
- "aria-owns": open ? id : null
100
+ "aria-owns": open ? id : undefined
99
101
  }), /*#__PURE__*/React__default["default"].createElement("div", {
100
102
  className: primaryActionClasses
101
103
  }, /*#__PURE__*/React__default["default"].createElement(Button["default"], {
@@ -113,7 +115,7 @@ const ComboButton = /*#__PURE__*/React__default["default"].forwardRef(function C
113
115
  "aria-expanded": open,
114
116
  onClick: handleTriggerClick,
115
117
  onMouseDown: handleTriggerMousedown,
116
- "aria-controls": open ? id : null
118
+ "aria-controls": open ? id : undefined
117
119
  }, _ChevronDown || (_ChevronDown = /*#__PURE__*/React__default["default"].createElement(iconsReact.ChevronDown, null))), /*#__PURE__*/React__default["default"].createElement(Menu.Menu, {
118
120
  containerRef: containerRef,
119
121
  menuAlignment: menuAlignment,
@@ -144,7 +146,7 @@ ComboButton.propTypes = {
144
146
  */
145
147
  disabled: PropTypes__default["default"].bool,
146
148
  /**
147
- * Provide the label to be renderd on the primary action button.
149
+ * Provide the label to be rendered on the primary action button.
148
150
  */
149
151
  label: PropTypes__default["default"].string.isRequired,
150
152
  /**
@@ -68,7 +68,7 @@ export interface ComposedModalProps extends HTMLAttributes<HTMLDivElement> {
68
68
  */
69
69
  selectorPrimaryFocus?: string;
70
70
  /** Specify the CSS selectors that match the floating menus. */
71
- selectorsFloatingMenus?: Array<string | null | undefined>;
71
+ selectorsFloatingMenus?: string[];
72
72
  size?: 'xs' | 'sm' | 'md' | 'lg';
73
73
  /**
74
74
  * **Experimental**: Provide a `Slug` component to be rendered inside the `ComposedModal` component
@@ -159,9 +159,9 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
159
159
  onKeyDown?.(event);
160
160
  }
161
161
  function handleMousedown(evt) {
162
+ const target = evt.target;
162
163
  evt.stopPropagation();
163
- const isInside = innerModal.current?.contains(evt.target);
164
- if (!isInside && !preventCloseOnClickOutside) {
164
+ if (!preventCloseOnClickOutside && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target)) {
165
165
  closeModal(evt);
166
166
  }
167
167
  }
@@ -253,11 +253,11 @@ const ComposedModal = /*#__PURE__*/React__default["default"].forwardRef(function
253
253
  }
254
254
  }, [open, selectorPrimaryFocus, isOpen]);
255
255
 
256
- // Slug is always size `lg`
256
+ // Slug is always size `sm`
257
257
  let normalizedSlug;
258
258
  if (slug && slug['type']?.displayName === 'Slug') {
259
259
  normalizedSlug = /*#__PURE__*/React__default["default"].cloneElement(slug, {
260
- size: 'lg'
260
+ size: 'sm'
261
261
  });
262
262
  }
263
263
  return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
@@ -347,7 +347,7 @@ ComposedModal.propTypes = {
347
347
  /**
348
348
  * Specify the CSS selectors that match the floating menus
349
349
  */
350
- selectorsFloatingMenus: PropTypes__default["default"].arrayOf(PropTypes__default["default"].string),
350
+ selectorsFloatingMenus: PropTypes__default["default"].arrayOf(PropTypes__default["default"].string.isRequired),
351
351
  /**
352
352
  * Specify the size variant.
353
353
  */
@@ -22,11 +22,7 @@ export interface TableBatchActionProps extends React.ButtonHTMLAttributes<HTMLBu
22
22
  renderIcon?: React.ElementType;
23
23
  }
24
24
  declare const TableBatchAction: {
25
- ({ renderIcon, iconDescription, ...props }: {
26
- [x: string]: any;
27
- renderIcon?: import("@carbon/icons-react").CarbonIconType | undefined;
28
- iconDescription?: string | undefined;
29
- }): import("react/jsx-runtime").JSX.Element;
25
+ ({ renderIcon, iconDescription, ...props }: TableBatchActionProps): import("react/jsx-runtime").JSX.Element;
30
26
  propTypes: {
31
27
  /**
32
28
  * Specify if the button is an icon-only button
@@ -36,7 +36,8 @@ const {
36
36
  ToggleButtonKeyDownArrowUp,
37
37
  ToggleButtonKeyDownHome,
38
38
  ToggleButtonKeyDownEnd,
39
- ItemMouseMove
39
+ ItemMouseMove,
40
+ MenuMouseLeave
40
41
  } = Downshift.useSelect.stateChangeTypes;
41
42
  const defaultItemToString = item => {
42
43
  if (typeof item === 'string') {
@@ -121,6 +122,7 @@ const Dropdown = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref) =
121
122
  }
122
123
  return changes;
123
124
  case ItemMouseMove:
125
+ case MenuMouseLeave:
124
126
  return {
125
127
  ...changes,
126
128
  highlightedIndex: state.highlightedIndex
@@ -119,7 +119,7 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
119
119
  function handleMousedown(evt) {
120
120
  const target = evt.target;
121
121
  evt.stopPropagation();
122
- if (innerModal.current && !innerModal.current.contains(target) && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && !preventCloseOnClickOutside) {
122
+ if (!preventCloseOnClickOutside && !wrapFocus.elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && innerModal.current && !innerModal.current.contains(target)) {
123
123
  onRequestClose(evt);
124
124
  }
125
125
  }
@@ -237,11 +237,11 @@ const Modal = /*#__PURE__*/React__default["default"].forwardRef(function Modal(_
237
237
  };
238
238
  }, []);
239
239
 
240
- // Slug is always size `lg`
240
+ // Slug is always size `sm`
241
241
  let normalizedSlug;
242
242
  if (slug && slug['type']?.displayName === 'Slug') {
243
243
  normalizedSlug = /*#__PURE__*/React__default["default"].cloneElement(slug, {
244
- size: 'lg'
244
+ size: 'sm'
245
245
  });
246
246
  }
247
247
  const modalButton = /*#__PURE__*/React__default["default"].createElement("div", {
@@ -149,6 +149,9 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
149
149
  if (onMenuChange) {
150
150
  onMenuChange(nextIsOpen);
151
151
  }
152
+ if (!isOpen) {
153
+ setHighlightedIndex(0);
154
+ }
152
155
  }
153
156
  function handleOnOuterClick() {
154
157
  handleOnMenuChange(false);
@@ -172,6 +175,34 @@ const FilterableMultiSelect = /*#__PURE__*/React__default["default"].forwardRef(
172
175
  break;
173
176
  case stateChangeTypes.keyDownEscape:
174
177
  handleOnMenuChange(false);
178
+ setHighlightedIndex(0);
179
+ break;
180
+ case stateChangeTypes.changeInput:
181
+ setHighlightedIndex(0);
182
+ break;
183
+ case stateChangeTypes.keyDownEnter:
184
+ if (!isOpen) {
185
+ setHighlightedIndex(0);
186
+ }
187
+ break;
188
+ case stateChangeTypes.clickItem:
189
+ if (isOpen) {
190
+ const sortedItems = sortItems(filterItems(items, {
191
+ itemToString: itemToString$1,
192
+ inputValue
193
+ }), {
194
+ selectedItems: {
195
+ top: changes.selectedItems,
196
+ fixed: [],
197
+ 'top-after-reopen': topItems
198
+ }[selectionFeedback],
199
+ itemToString: itemToString$1,
200
+ compareItems,
201
+ locale
202
+ });
203
+ const sortedSelectedIndex = sortedItems.indexOf(changes.selectedItem);
204
+ setHighlightedIndex(sortedSelectedIndex);
205
+ }
175
206
  break;
176
207
  }
177
208
  }
@@ -48,9 +48,11 @@ const {
48
48
  ToggleButtonKeyDownEscape,
49
49
  ToggleButtonKeyDownSpaceButton,
50
50
  ItemMouseMove,
51
+ MenuMouseLeave,
51
52
  ToggleButtonClick,
52
- ToggleButtonKeyDownHome,
53
- ToggleButtonKeyDownEnd
53
+ ToggleButtonKeyDownPageDown,
54
+ ToggleButtonKeyDownPageUp,
55
+ FunctionSetHighlightedIndex
54
56
  } = Downshift.useSelect.stateChangeTypes;
55
57
  const defaultItemToString = item => {
56
58
  if (typeof item === 'string') {
@@ -146,7 +148,8 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
146
148
  getMenuProps,
147
149
  getItemProps,
148
150
  selectedItem,
149
- highlightedIndex
151
+ highlightedIndex,
152
+ setHighlightedIndex
150
153
  } = Downshift.useSelect(selectProps);
151
154
  const toggleButtonProps = getToggleButtonProps({
152
155
  onFocus: () => {
@@ -165,6 +168,7 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
165
168
  setItemsCleared(true);
166
169
  }
167
170
  if ((match.match(e, keys.Space) || match.match(e, keys.ArrowDown) || match.match(e, keys.Enter)) && !isOpen) {
171
+ setHighlightedIndex(0);
168
172
  setItemsCleared(false);
169
173
  setIsOpenWrapper(true);
170
174
  }
@@ -248,7 +252,6 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
248
252
  setTopItems(controlledSelectedItems);
249
253
  }
250
254
  switch (type) {
251
- case ItemClick:
252
255
  case ToggleButtonKeyDownSpaceButton:
253
256
  case ToggleButtonKeyDownEnter:
254
257
  if (changes.selectedItem === undefined) {
@@ -268,11 +271,38 @@ const MultiSelect = /*#__PURE__*/React__default["default"].forwardRef((_ref, ref
268
271
  break;
269
272
  case ToggleButtonClick:
270
273
  setIsOpenWrapper(changes.isOpen || false);
271
- break;
274
+ return {
275
+ ...changes,
276
+ highlightedIndex: 0
277
+ };
278
+ case ItemClick:
279
+ setHighlightedIndex(changes.selectedItem);
280
+ onItemChange(changes.selectedItem);
281
+ return {
282
+ ...changes,
283
+ highlightedIndex: state.highlightedIndex
284
+ };
285
+ case MenuMouseLeave:
286
+ return {
287
+ ...changes,
288
+ highlightedIndex: state.highlightedIndex
289
+ };
290
+ case FunctionSetHighlightedIndex:
291
+ if (!isOpen) {
292
+ return {
293
+ ...changes,
294
+ highlightedIndex: 0
295
+ };
296
+ } else {
297
+ return {
298
+ ...changes,
299
+ highlightedIndex: props.items.indexOf(highlightedIndex)
300
+ };
301
+ }
272
302
  case ToggleButtonKeyDownArrowDown:
273
303
  case ToggleButtonKeyDownArrowUp:
274
- case ToggleButtonKeyDownHome:
275
- case ToggleButtonKeyDownEnd:
304
+ case ToggleButtonKeyDownPageDown:
305
+ case ToggleButtonKeyDownPageUp:
276
306
  if (highlightedIndex > -1) {
277
307
  const itemArray = document.querySelectorAll(`li.${prefix}--list-box__menu-item[role="option"]`);
278
308
  props.scrollIntoView(itemArray[highlightedIndex]);
@@ -148,26 +148,21 @@ Slug.propTypes = {
148
148
  */
149
149
  align: PropTypes__default["default"].oneOf(['top', 'top-left',
150
150
  // deprecated use top-start instead
151
- 'top-right',
151
+ 'top-start', 'top-right',
152
152
  // deprecated use top-end instead
153
-
154
- 'bottom', 'bottom-left',
153
+ 'top-end', 'bottom', 'bottom-left',
155
154
  // deprecated use bottom-start instead
156
- 'bottom-right',
155
+ 'bottom-start', 'bottom-right',
157
156
  // deprecated use bottom-end instead
158
-
159
- 'left', 'left-bottom',
157
+ 'bottom-end', 'left', 'left-bottom',
160
158
  // deprecated use left-end instead
161
- 'left-top',
159
+ 'left-end', 'left-top',
162
160
  // deprecated use left-start instead
163
-
164
- 'right', 'right-bottom',
161
+ 'left-start', 'right', 'right-bottom',
165
162
  // deprecated use right-end instead
166
- 'right-top',
163
+ 'right-end', 'right-top',
167
164
  // deprecated use right-start instead
168
-
169
- // new values to match floating-ui
170
- 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']),
165
+ 'right-start']),
171
166
  /**
172
167
  * Will auto-align the popover. This prop is currently experimental and is subject to future changes.
173
168
  */
@@ -210,7 +210,8 @@ function TabList(_ref2) {
210
210
  // TODO: V12 - Remove this class
211
211
  [`${prefix}--layout--size-lg`]: iconSize === 'lg',
212
212
  [`${prefix}--tabs--tall`]: hasSecondaryLabelTabs,
213
- [`${prefix}--tabs--full-width`]: distributeWidth
213
+ [`${prefix}--tabs--full-width`]: distributeWidth,
214
+ [`${prefix}--tabs--dismissable`]: dismissable
214
215
  }, customClassName);
215
216
 
216
217
  // Previous Button
@@ -552,6 +553,25 @@ const Tab = /*#__PURE__*/React.forwardRef(function Tab(_ref5, forwardRef) {
552
553
  const handleClose = evt => {
553
554
  evt.stopPropagation();
554
555
  onTabCloseRequest?.(index);
556
+
557
+ // set focus after removing tab
558
+ if (tabRef.current && tabRef.current.parentElement) {
559
+ // determine number of tabs, excluding disabled
560
+ const tabCount = Array.from(tabRef.current.parentElement.childNodes).filter(node => {
561
+ const element = node;
562
+ return element.classList.contains('cds--tabs__nav-link') && !element.classList.contains('cds--tabs__nav-item--disabled');
563
+ }).length;
564
+
565
+ // if not removing last tab focus on next tab
566
+ if (tabRef.current && index + 1 !== tabCount) {
567
+ tabRef.current.focus();
568
+ }
569
+ // if removing last tab focus on previous tab
570
+ else {
571
+ const prevTabIndex = (tabCount - 2) * 2;
572
+ tabRef.current.parentElement.childNodes[prevTabIndex]?.focus();
573
+ }
574
+ }
555
575
  };
556
576
  const handleKeyDown = event => {
557
577
  if (dismissable && match.match(event, keys.Delete)) {
@@ -560,20 +580,31 @@ const Tab = /*#__PURE__*/React.forwardRef(function Tab(_ref5, forwardRef) {
560
580
  onKeyDown?.(event);
561
581
  };
562
582
  const DismissIcon = /*#__PURE__*/React__default["default"].createElement("div", {
563
- tabIndex: -1,
564
- "aria-hidden": true,
565
- className: cx__default["default"](`${prefix}--tabs__nav-item--close-icon`, {
566
- [`${prefix}--visually-hidden`]: !dismissable
583
+ className: cx__default["default"]({
584
+ [`${prefix}--tabs__nav-item--close`]: dismissable,
585
+ [`${prefix}--tabs__nav-item--close--hidden`]: !dismissable
586
+ })
587
+ }, /*#__PURE__*/React__default["default"].createElement("button", {
588
+ type: "button",
589
+ tabIndex: selectedIndex === index && dismissable ? 0 : -1,
590
+ "aria-disabled": disabled,
591
+ "aria-hidden": selectedIndex === index && dismissable ? 'false' : 'true',
592
+ disabled: disabled,
593
+ className: cx__default["default"]({
594
+ [`${prefix}--tabs__nav-item--close-icon`]: dismissable,
595
+ [`${prefix}--visually-hidden`]: !dismissable,
596
+ [`${prefix}--tabs__nav-item--close-icon--selected`]: selectedIndex === index,
597
+ [`${prefix}--tabs__nav-item--close-icon--disabled`]: disabled
567
598
  }),
568
599
  onClick: handleClose,
569
- title: "Close tab",
600
+ title: `Remove ${typeof children === 'string' ? children : ''} tab`,
570
601
  ref: dismissIconRef
571
602
  }, /*#__PURE__*/React__default["default"].createElement(iconsReact.Close, {
572
- "aria-hidden": dismissable ? 'false' : 'true',
573
- "aria-label": "Press delete to close tab"
574
- }));
603
+ "aria-hidden": selectedIndex === index && dismissable ? 'false' : 'true',
604
+ "aria-label": `Press delete to remove ${typeof children === 'string' ? children : ''} tab`
605
+ })));
575
606
  const hasIcon = Icon ?? dismissable;
576
- return /*#__PURE__*/React__default["default"].createElement(BaseComponent, _rollupPluginBabelHelpers["extends"]({}, rest, {
607
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(BaseComponent, _rollupPluginBabelHelpers["extends"]({}, rest, {
577
608
  "aria-controls": panelId,
578
609
  "aria-disabled": disabled,
579
610
  "aria-selected": selectedIndex === index,
@@ -600,17 +631,17 @@ const Tab = /*#__PURE__*/React.forwardRef(function Tab(_ref5, forwardRef) {
600
631
  size: 16
601
632
  })), /*#__PURE__*/React__default["default"].createElement(Text.Text, {
602
633
  className: `${prefix}--tabs__nav-item-label`
603
- }, children), /*#__PURE__*/React__default["default"].createElement("div", {
634
+ }, children), !dismissable && Icon && /*#__PURE__*/React__default["default"].createElement("div", {
604
635
  className: cx__default["default"](`${prefix}--tabs__nav-item--icon`, {
605
636
  [`${prefix}--visually-hidden`]: !hasIcon
606
637
  })
607
- }, DismissIcon, !dismissable && Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
638
+ }, !dismissable && Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
608
639
  size: 16
609
640
  }))), hasSecondaryLabel && secondaryLabel && /*#__PURE__*/React__default["default"].createElement(Text.Text, {
610
641
  as: "div",
611
642
  className: `${prefix}--tabs__nav-item-secondary-label`,
612
643
  title: secondaryLabel
613
- }, secondaryLabel));
644
+ }, secondaryLabel)), DismissIcon);
614
645
  });
615
646
  Tab.propTypes = {
616
647
  /**