@carbon/react 1.100.0 → 1.101.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 (134) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +953 -953
  2. package/es/components/AILabel/index.d.ts +1 -1
  3. package/es/components/AILabel/index.js +1 -12
  4. package/es/components/Checkbox/Checkbox.js +5 -3
  5. package/es/components/CheckboxGroup/CheckboxGroup.js +4 -3
  6. package/es/components/CodeSnippet/CodeSnippet.d.ts +1 -1
  7. package/es/components/ComboBox/ComboBox.js +25 -12
  8. package/es/components/ComboButton/index.d.ts +1 -1
  9. package/es/components/ComboButton/index.js +3 -2
  10. package/es/components/ComposedModal/ComposedModal.js +17 -22
  11. package/es/components/ComposedModal/ModalHeader.d.ts +2 -2
  12. package/es/components/ComposedModal/ModalHeader.js +1 -1
  13. package/es/components/Copy/Copy.d.ts +1 -1
  14. package/es/components/CopyButton/CopyButton.d.ts +1 -1
  15. package/es/components/DataTable/DataTable.d.ts +2 -0
  16. package/es/components/DataTable/DataTable.js +6 -5
  17. package/es/components/DataTable/Table.d.ts +1 -1
  18. package/es/components/DataTable/Table.js +10 -4
  19. package/es/components/DataTable/state/sorting.d.ts +4 -2
  20. package/es/components/Dropdown/Dropdown.js +4 -4
  21. package/es/components/ExpandableSearch/ExpandableSearch.js +1 -1
  22. package/es/components/FileUploader/FileUploaderItem.d.ts +1 -1
  23. package/es/components/FileUploader/FileUploaderItem.js +3 -2
  24. package/es/components/ListBox/test-helpers.d.ts +71 -0
  25. package/es/components/Menu/Menu.js +8 -4
  26. package/es/components/Menu/MenuItem.d.ts +5 -1
  27. package/es/components/Menu/MenuItem.js +11 -1
  28. package/es/components/MenuButton/index.d.ts +1 -1
  29. package/es/components/MenuButton/index.js +3 -2
  30. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  31. package/es/components/MultiSelect/FilterableMultiSelect.js +8 -6
  32. package/es/components/MultiSelect/MultiSelect.js +8 -4
  33. package/es/components/Notification/Notification.js +2 -1
  34. package/es/components/NumberInput/NumberInput.d.ts +1 -1
  35. package/es/components/NumberInput/NumberInput.js +6 -5
  36. package/es/components/OverflowMenu/OverflowMenu.d.ts +1 -0
  37. package/es/components/OverflowMenu/OverflowMenu.js +8 -4
  38. package/es/components/PageHeader/PageHeader.d.ts +1 -1
  39. package/es/components/PageHeader/PageHeader.js +5 -5
  40. package/es/components/Popover/index.js +1 -1
  41. package/es/components/ProgressIndicator/ProgressIndicator.d.ts +1 -1
  42. package/es/components/ProgressIndicator/ProgressIndicator.js +1 -1
  43. package/es/components/RadioButtonGroup/RadioButtonGroup.js +4 -3
  44. package/es/components/Search/Search.d.ts +1 -1
  45. package/es/components/Search/Search.js +1 -1
  46. package/es/components/Select/Select.js +3 -2
  47. package/es/components/StructuredList/StructuredList.d.ts +1 -1
  48. package/es/components/StructuredList/StructuredList.js +2 -4
  49. package/es/components/Tabs/Tabs.d.ts +2 -2
  50. package/es/components/Tabs/Tabs.js +20 -26
  51. package/es/components/Tag/DismissibleTag.js +3 -2
  52. package/es/components/Tag/OperationalTag.js +3 -2
  53. package/es/components/Tag/SelectableTag.js +3 -2
  54. package/es/components/Tag/Tag.js +3 -2
  55. package/es/components/TextArea/TextArea.d.ts +2 -2
  56. package/es/components/TextArea/TextArea.js +7 -6
  57. package/es/components/TextInput/ControlledPasswordInput.js +7 -6
  58. package/es/components/TextInput/PasswordInput.js +5 -6
  59. package/es/components/TextInput/TextInput.js +4 -4
  60. package/es/components/TimePicker/TimePicker.js +2 -2
  61. package/es/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  62. package/es/components/Tooltip/DefinitionTooltip.js +3 -2
  63. package/es/internal/useId.js +3 -4
  64. package/es/internal/usePresence.js +3 -2
  65. package/es/internal/useResizeObserver.d.ts +1 -1
  66. package/es/internal/useResizeObserver.js +5 -7
  67. package/es/tools/events.d.ts +1 -1
  68. package/lib/components/AILabel/index.d.ts +1 -1
  69. package/lib/components/AILabel/index.js +1 -12
  70. package/lib/components/Checkbox/Checkbox.js +5 -3
  71. package/lib/components/CheckboxGroup/CheckboxGroup.js +4 -3
  72. package/lib/components/CodeSnippet/CodeSnippet.d.ts +1 -1
  73. package/lib/components/ComboBox/ComboBox.js +25 -12
  74. package/lib/components/ComboButton/index.d.ts +1 -1
  75. package/lib/components/ComboButton/index.js +2 -1
  76. package/lib/components/ComposedModal/ComposedModal.js +16 -21
  77. package/lib/components/ComposedModal/ModalHeader.d.ts +2 -2
  78. package/lib/components/ComposedModal/ModalHeader.js +1 -1
  79. package/lib/components/Copy/Copy.d.ts +1 -1
  80. package/lib/components/CopyButton/CopyButton.d.ts +1 -1
  81. package/lib/components/DataTable/DataTable.d.ts +2 -0
  82. package/lib/components/DataTable/DataTable.js +6 -5
  83. package/lib/components/DataTable/Table.d.ts +1 -1
  84. package/lib/components/DataTable/Table.js +10 -4
  85. package/lib/components/DataTable/state/sorting.d.ts +4 -2
  86. package/lib/components/Dropdown/Dropdown.js +4 -4
  87. package/lib/components/ExpandableSearch/ExpandableSearch.js +1 -1
  88. package/lib/components/FileUploader/FileUploaderItem.d.ts +1 -1
  89. package/lib/components/FileUploader/FileUploaderItem.js +2 -1
  90. package/lib/components/ListBox/test-helpers.d.ts +71 -0
  91. package/lib/components/Menu/Menu.js +7 -3
  92. package/lib/components/Menu/MenuItem.d.ts +5 -1
  93. package/lib/components/Menu/MenuItem.js +11 -1
  94. package/lib/components/MenuButton/index.d.ts +1 -1
  95. package/lib/components/MenuButton/index.js +2 -1
  96. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  97. package/lib/components/MultiSelect/FilterableMultiSelect.js +7 -5
  98. package/lib/components/MultiSelect/MultiSelect.js +7 -3
  99. package/lib/components/Notification/Notification.js +2 -1
  100. package/lib/components/NumberInput/NumberInput.d.ts +1 -1
  101. package/lib/components/NumberInput/NumberInput.js +6 -5
  102. package/lib/components/OverflowMenu/OverflowMenu.d.ts +1 -0
  103. package/lib/components/OverflowMenu/OverflowMenu.js +7 -3
  104. package/lib/components/PageHeader/PageHeader.d.ts +1 -1
  105. package/lib/components/PageHeader/PageHeader.js +4 -4
  106. package/lib/components/Popover/index.js +1 -1
  107. package/lib/components/ProgressIndicator/ProgressIndicator.d.ts +1 -1
  108. package/lib/components/ProgressIndicator/ProgressIndicator.js +1 -1
  109. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +4 -3
  110. package/lib/components/Search/Search.d.ts +1 -1
  111. package/lib/components/Search/Search.js +1 -1
  112. package/lib/components/Select/Select.js +3 -2
  113. package/lib/components/StructuredList/StructuredList.d.ts +1 -1
  114. package/lib/components/StructuredList/StructuredList.js +2 -4
  115. package/lib/components/Tabs/Tabs.d.ts +2 -2
  116. package/lib/components/Tabs/Tabs.js +15 -21
  117. package/lib/components/Tag/DismissibleTag.js +2 -1
  118. package/lib/components/Tag/OperationalTag.js +2 -1
  119. package/lib/components/Tag/SelectableTag.js +2 -1
  120. package/lib/components/Tag/Tag.js +2 -1
  121. package/lib/components/TextArea/TextArea.d.ts +2 -2
  122. package/lib/components/TextArea/TextArea.js +7 -6
  123. package/lib/components/TextInput/ControlledPasswordInput.js +7 -6
  124. package/lib/components/TextInput/PasswordInput.js +5 -6
  125. package/lib/components/TextInput/TextInput.js +4 -4
  126. package/lib/components/TimePicker/TimePicker.js +2 -2
  127. package/lib/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  128. package/lib/components/Tooltip/DefinitionTooltip.js +3 -2
  129. package/lib/internal/useId.js +2 -3
  130. package/lib/internal/usePresence.js +2 -1
  131. package/lib/internal/useResizeObserver.d.ts +1 -1
  132. package/lib/internal/useResizeObserver.js +4 -6
  133. package/lib/tools/events.d.ts +1 -1
  134. package/package.json +9 -9
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -23,20 +23,9 @@ const AILabelContent = /*#__PURE__*/React.forwardRef(function AILabelContent({
23
23
  }, ref // eslint-disable-line @typescript-eslint/no-unused-vars -- https://github.com/carbon-design-system/carbon/issues/20452
24
24
  ) {
25
25
  const prefix = usePrefix();
26
- const hasAILabelActions = React.Children.toArray(children).some(child => {
27
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
28
- const item = child;
29
- // TODO: Is there supposed to be a `return` here? If so, this issue would
30
- // have been caught by ESLint. It's concerning that this code is 7 months
31
- // old and no one has noticed any issues with it. It also makes me question
32
- // whether the code is necessary.
33
- // https://github.com/carbon-design-system/carbon/issues/18991
34
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- https://github.com/carbon-design-system/carbon/issues/20452
35
- item.type === AILabelActions;
36
- });
37
26
  const aiLabelContentClasses = cx(className, {
38
27
  [`${prefix}--ai-label-content`]: true,
39
- [`${prefix}--ai-label-content--with-actions`]: hasAILabelActions
28
+ [`${prefix}--ai-label-content--with-actions`]: false
40
29
  });
41
30
  return /*#__PURE__*/React.createElement(ToggletipContent, {
42
31
  className: aiLabelContentClasses
@@ -42,11 +42,12 @@ const Checkbox = /*#__PURE__*/React.forwardRef(({
42
42
  const showWarning = !readOnly && !invalid && warn;
43
43
  const showHelper = !invalid && !warn;
44
44
  const checkboxGroupInstanceId = useId();
45
- const helperId = !helperText ? undefined : `checkbox-helper-text-${checkboxGroupInstanceId}`;
46
- const helper = helperText ? /*#__PURE__*/React.createElement("div", {
45
+ const hasHelper = typeof helperText !== 'undefined' && helperText !== null;
46
+ const helperId = !hasHelper ? undefined : `checkbox-helper-text-${checkboxGroupInstanceId}`;
47
+ const helper = hasHelper && /*#__PURE__*/React.createElement("div", {
47
48
  id: helperId,
48
49
  className: `${prefix}--form__helper-text`
49
- }, helperText) : null;
50
+ }, helperText);
50
51
  const wrapperClasses = cx(`${prefix}--form-item`, `${prefix}--checkbox-wrapper`, className, {
51
52
  [`${prefix}--checkbox-wrapper--readonly`]: readOnly,
52
53
  [`${prefix}--checkbox-wrapper--invalid`]: !readOnly && invalid,
@@ -106,6 +107,7 @@ const Checkbox = /*#__PURE__*/React.forwardRef(({
106
107
  className: `${prefix}--checkbox-label`,
107
108
  title: title
108
109
  }, /*#__PURE__*/React.createElement(Text, {
110
+ as: "div",
109
111
  className: innerLabelClasses
110
112
  }, labelText, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
111
113
  className: `${prefix}--checkbox-wrapper-inner--decorator`
@@ -38,11 +38,12 @@ const CheckboxGroup = ({
38
38
  const showWarning = !readOnly && !invalid && warn;
39
39
  const showHelper = !invalid && !warn;
40
40
  const checkboxGroupInstanceId = useId();
41
- const helperId = !helperText ? undefined : `checkbox-group-helper-text-${checkboxGroupInstanceId}`;
42
- const helper = helperText ? /*#__PURE__*/React.createElement("div", {
41
+ const hasHelper = typeof helperText !== 'undefined' && helperText !== null;
42
+ const helperId = !hasHelper ? undefined : `checkbox-group-helper-text-${checkboxGroupInstanceId}`;
43
+ const helper = hasHelper && /*#__PURE__*/React.createElement("div", {
43
44
  id: helperId,
44
45
  className: `${prefix}--form__helper-text`
45
- }, helperText) : null;
46
+ }, helperText);
46
47
  const fieldsetClasses = cx(`${prefix}--checkbox-group`, className, {
47
48
  [`${prefix}--checkbox-group--${orientation}`]: orientation === 'horizontal',
48
49
  [`${prefix}--checkbox-group--readonly`]: readOnly,
@@ -111,7 +111,7 @@ declare namespace CodeSnippet {
111
111
  /**
112
112
  * Specify how the trigger should align with the tooltip
113
113
  */
114
- align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
114
+ align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
115
115
  /**
116
116
  * Specify a label to be read by screen readers on the containing textbox
117
117
  * node
@@ -23,6 +23,7 @@ import { useId } from '../../internal/useId.js';
23
23
  import { mergeRefs } from '../../tools/mergeRefs.js';
24
24
  import { deprecate } from '../../prop-types/deprecate.js';
25
25
  import { usePrefix } from '../../internal/usePrefix.js';
26
+ import { useNormalizedInputProps } from '../../internal/useNormalizedInputProps.js';
26
27
  import '../FluidForm/FluidForm.js';
27
28
  import { FormContext } from '../FluidForm/FormContext.js';
28
29
  import { useFloating, autoUpdate, flip, hide } from '@floating-ui/react';
@@ -247,8 +248,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
247
248
  useEffect(() => {
248
249
  if (prevInputValue.current !== inputValue) {
249
250
  prevInputValue.current = inputValue;
250
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- https://github.com/carbon-design-system/carbon/issues/20452
251
- onInputChange && onInputChange(inputValue);
251
+ onInputChange?.(inputValue);
252
252
  }
253
253
  // eslint-disable-next-line react-hooks/exhaustive-deps -- https://github.com/carbon-design-system/carbon/issues/20452
254
254
  }, [inputValue]);
@@ -423,11 +423,19 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
423
423
  event?.persist?.();
424
424
  }
425
425
  };
426
- const showWarning = !invalid && warn;
426
+ const normalizedProps = useNormalizedInputProps({
427
+ id,
428
+ readOnly,
429
+ disabled: disabled || false,
430
+ invalid: invalid || false,
431
+ invalidText,
432
+ warn: warn || false,
433
+ warnText
434
+ });
427
435
  const className = cx(`${prefix}--combo-box`, {
428
436
  [`${prefix}--combo-box--invalid--focused`]: invalid && isFocused,
429
437
  [`${prefix}--list-box--up`]: direction === 'top',
430
- [`${prefix}--combo-box--warning`]: showWarning,
438
+ [`${prefix}--combo-box--warning`]: normalizedProps.warn,
431
439
  [`${prefix}--combo-box--readonly`]: readOnly,
432
440
  [`${prefix}--autoalign`]: enableFloatingStyles
433
441
  });
@@ -597,7 +605,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
597
605
  // The input should be described by the appropriate message text id
598
606
  // when both the message is supplied *and* when the component is in
599
607
  // the matching state (invalid, warn, etc).
600
- const ariaDescribedBy = invalid && invalidText && invalidTextId || warn && warnText && warnTextId || helperText && !isFluid && helperTextId || undefined;
608
+ const ariaDescribedBy = normalizedProps.invalid && invalidText && invalidTextId || normalizedProps.warn && warnText && warnTextId || helperText && !isFluid && helperTextId || undefined;
601
609
 
602
610
  // Memoize the value of getMenuProps to avoid an infinite loop
603
611
  const menuProps = useMemo(() => getMenuProps({
@@ -625,13 +633,13 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
625
633
  onBlur: handleFocus,
626
634
  className: className,
627
635
  disabled: disabled,
628
- invalid: invalid,
636
+ invalid: normalizedProps.invalid,
629
637
  invalidText: invalidText,
630
638
  invalidTextId: invalidTextId,
631
639
  isOpen: isOpen,
632
640
  light: light,
633
641
  size: size,
634
- warn: warn,
642
+ warn: normalizedProps.warn,
635
643
  ref: enableFloatingStyles ? refs.setReference : null,
636
644
  warnText: warnText,
637
645
  warnTextId: warnTextId
@@ -733,9 +741,9 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
733
741
  }), rest, readOnlyEventHandlers, {
734
742
  readOnly: readOnly,
735
743
  "aria-describedby": ariaDescribedBy
736
- })), invalid && /*#__PURE__*/React.createElement(WarningFilled, {
744
+ })), normalizedProps.invalid && /*#__PURE__*/React.createElement(WarningFilled, {
737
745
  className: `${prefix}--list-box__invalid-icon`
738
- }), showWarning && /*#__PURE__*/React.createElement(WarningAltFilled, {
746
+ }), normalizedProps.warn && /*#__PURE__*/React.createElement(WarningAltFilled, {
739
747
  className: `${prefix}--list-box__invalid-icon ${prefix}--list-box__invalid-icon--warning`
740
748
  }), inputValue && /*#__PURE__*/React.createElement(ListBoxSelection, {
741
749
  clearSelection: () => {
@@ -773,18 +781,23 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
773
781
  const {
774
782
  'aria-disabled': unusedAriaDisabled,
775
783
  // eslint-disable-line @typescript-eslint/no-unused-vars
784
+ 'aria-selected': unusedAriaSelected,
785
+ // eslint-disable-line @typescript-eslint/no-unused-vars
776
786
  ...modifiedItemProps
777
787
  } = itemProps;
788
+ const isSelected = isEqual(currentSelectedItem, item);
778
789
  return /*#__PURE__*/React.createElement(ListBox.MenuItem, _extends({
779
790
  key: itemProps.id,
780
- isActive: isEqual(currentSelectedItem, item),
791
+ isActive: isSelected,
781
792
  isHighlighted: highlightedIndex === index,
782
793
  title: title,
783
794
  disabled: disabled
784
- }, modifiedItemProps), itemToElement ? itemToElement(item) : itemToString(item), isEqual(currentSelectedItem, item) && /*#__PURE__*/React.createElement(Checkmark, {
795
+ }, modifiedItemProps, {
796
+ "aria-selected": isSelected
797
+ }), itemToElement ? itemToElement(item) : itemToString(item), isSelected && /*#__PURE__*/React.createElement(Checkmark, {
785
798
  className: `${prefix}--list-box__menu-item__selected-icon`
786
799
  }));
787
- }) : null)), helperText && !invalid && !warn && !isFluid && /*#__PURE__*/React.createElement(Text, {
800
+ }) : null)), helperText && !normalizedProps.invalid && !normalizedProps.warn && !isFluid && /*#__PURE__*/React.createElement(Text, {
788
801
  as: "div",
789
802
  id: helperTextId,
790
803
  className: helperClasses
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2023, 2025
2
+ * Copyright IBM Corp. 2023, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { useRef, useLayoutEffect } from 'react';
9
+ import React, { useRef } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { ChevronDown } from '@carbon/icons-react';
@@ -18,6 +18,7 @@ import '../Menu/MenuItem.js';
18
18
  import { useAttachedMenu } from '../../internal/useAttachedMenu.js';
19
19
  import { useId } from '../../internal/useId.js';
20
20
  import { usePrefix } from '../../internal/usePrefix.js';
21
+ import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
21
22
  import { flip, hide, size, useFloating, autoUpdate } from '@floating-ui/react';
22
23
  import { useFeatureFlag } from '../FeatureFlags/index.js';
23
24
  import { mergeRefs } from '../../tools/mergeRefs.js';
@@ -94,7 +95,7 @@ const ComboButton = /*#__PURE__*/React.forwardRef(function ComboButton({
94
95
  handleMousedown: handleTriggerMousedown,
95
96
  handleClose
96
97
  } = useAttachedMenu(containerRef);
97
- useLayoutEffect(() => {
98
+ useIsomorphicEffect(() => {
98
99
  const updatedFloatingStyles = {
99
100
  ...floatingStyles,
100
101
  visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
@@ -6,9 +6,8 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { useRef, useContext, useEffect, Children, cloneElement } from 'react';
9
+ import React, { useRef, useContext, useEffect, cloneElement, Children } from 'react';
10
10
  import { useResizeObserver } from '../../internal/useResizeObserver.js';
11
- import { isElement } from 'react-is';
12
11
  import PropTypes from 'prop-types';
13
12
  import { Layer } from '../Layer/index.js';
14
13
  import { ModalHeader } from './ModalHeader.js';
@@ -259,29 +258,25 @@ const ComposedModalDialog = /*#__PURE__*/React.forwardRef(function ComposedModal
259
258
  const containerClass = cx(`${prefix}--modal-container`, size && `${prefix}--modal-container--${size}`, isFullWidth && `${prefix}--modal-container--full-width`, containerClassName);
260
259
 
261
260
  // Generate aria-label based on Modal Header label if one is not provided (L253)
261
+ //
262
+ // TODO: Confirm whether `ModalHeader` `label` should allow `ReactNode`. If
263
+ // so, define how to derive a string for `aria-label`.
262
264
  let generatedAriaLabel;
263
265
  const childrenWithProps = React.Children.toArray(children).map(child => {
264
- switch (true) {
265
- case isElement(child) && child.type === /*#__PURE__*/React.createElement(ModalHeader).type:
266
- {
267
- const el = child;
268
- generatedAriaLabel = el.props.label;
269
- return /*#__PURE__*/React.cloneElement(el, {
270
- closeModal
271
- });
272
- }
273
- case isElement(child) && child.type === /*#__PURE__*/React.createElement(ModalFooter).type:
274
- {
275
- const el = child;
276
- return /*#__PURE__*/React.cloneElement(el, {
277
- closeModal,
278
- inputref: button,
279
- danger
280
- });
281
- }
282
- default:
283
- return child;
266
+ if (isComponentElement(child, ModalHeader)) {
267
+ generatedAriaLabel = child.props.label;
268
+ return /*#__PURE__*/cloneElement(child, {
269
+ closeModal
270
+ });
271
+ }
272
+ if (isComponentElement(child, ModalFooter)) {
273
+ return /*#__PURE__*/cloneElement(child, {
274
+ closeModal,
275
+ inputref: button,
276
+ danger
277
+ });
284
278
  }
279
+ return child;
285
280
  });
286
281
 
287
282
  // Modals without a footer are considered passive and carry limitations as
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2023
2
+ * Copyright IBM Corp. 2016, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -40,7 +40,7 @@ export interface ModalHeaderProps extends DivProps {
40
40
  /**
41
41
  * Specify an optional label to be displayed
42
42
  */
43
- label?: ReactNode;
43
+ label?: string;
44
44
  /**
45
45
  * Specify an optional className to be applied to the modal header label
46
46
  */
@@ -94,7 +94,7 @@ ModalHeader.propTypes = {
94
94
  /**
95
95
  * Specify an optional label to be displayed
96
96
  */
97
- label: PropTypes.node,
97
+ label: PropTypes.string,
98
98
  /**
99
99
  * Specify an optional className to be applied to the modal header label
100
100
  */
@@ -50,7 +50,7 @@ declare namespace Copy {
50
50
  /**
51
51
  * Specify how the trigger should align with the tooltip
52
52
  */
53
- align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
53
+ align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
54
54
  /**
55
55
  * **Experimental**: Will attempt to automatically align the tooltip. Requires
56
56
  * React v17+
@@ -51,7 +51,7 @@ declare namespace CopyButton {
51
51
  /**
52
52
  * Specify how the trigger should align with the tooltip
53
53
  */
54
- align: PropTypes.Requireable<string> | PropTypes.Validator<string>;
54
+ align: PropTypes.Requireable<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top"> | PropTypes.Validator<import("@floating-ui/utils").Placement | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left-bottom" | "left-top" | "right-bottom" | "right-top">;
55
55
  /**
56
56
  * **Experimental**: Will attempt to automatically align the tooltip. Requires
57
57
  * React v17+
@@ -51,6 +51,7 @@ export interface DataTableHeader {
51
51
  header: ReactNode;
52
52
  slug?: ReactElement;
53
53
  decorator?: ReactElement;
54
+ isSortable?: boolean;
54
55
  }
55
56
  export interface DataTableRenderProps<RowType, ColTypes extends any[]> {
56
57
  /**
@@ -435,6 +436,7 @@ export declare const DataTable: {
435
436
  headers: PropTypes.Validator<(PropTypes.InferProps<{
436
437
  key: PropTypes.Validator<string>;
437
438
  header: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
439
+ isSortable: PropTypes.Requireable<boolean>;
438
440
  }> | null | undefined)[]>;
439
441
  /**
440
442
  * Specify whether the table should be able to be sorted by its headers
@@ -96,7 +96,7 @@ const DataTable = props => {
96
96
  render,
97
97
  translateWithId: t = defaultTranslateWithId,
98
98
  size,
99
- isSortable: isSortableProp,
99
+ isSortable,
100
100
  useZebraStyles,
101
101
  useStaticWidth,
102
102
  stickyHeader,
@@ -135,7 +135,7 @@ const DataTable = props => {
135
135
  const getHeaderProps = ({
136
136
  header,
137
137
  onClick,
138
- isSortable = isSortableProp,
138
+ isSortable: headerIsSortable,
139
139
  ...rest
140
140
  }) => {
141
141
  const {
@@ -151,7 +151,7 @@ const DataTable = props => {
151
151
  ...rest,
152
152
  key,
153
153
  sortDirection,
154
- isSortable,
154
+ isSortable: headerIsSortable ?? header.isSortable ?? isSortable,
155
155
  isSortHeader: sortHeaderKey === key,
156
156
  slug,
157
157
  decorator,
@@ -310,7 +310,7 @@ const DataTable = props => {
310
310
  return {
311
311
  useZebraStyles,
312
312
  size: size ?? 'lg',
313
- isSortable: isSortableProp,
313
+ isSortable,
314
314
  useStaticWidth,
315
315
  stickyHeader,
316
316
  overflowMenuOnHover: overflowMenuOnHover ?? false,
@@ -600,7 +600,8 @@ DataTable.propTypes = {
600
600
  */
601
601
  headers: PropTypes.arrayOf(PropTypes.shape({
602
602
  key: PropTypes.string.isRequired,
603
- header: PropTypes.node.isRequired
603
+ header: PropTypes.node.isRequired,
604
+ isSortable: PropTypes.bool
604
605
  })).isRequired,
605
606
  /**
606
607
  * Specify whether the table should be able to be sorted by its headers
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -70,12 +70,18 @@ const Table = ({
70
70
  [`${prefix}--data-table--visible-overflow-menu`]: !overflowMenuOnHover
71
71
  });
72
72
  const toggleTableBodyAlignmentClass = useCallback((alignTop = false) => {
73
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- https://github.com/carbon-design-system/carbon/issues/20452
74
- alignTop ? tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-body`) : tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-body`);
73
+ if (alignTop) {
74
+ tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-body`);
75
+ } else {
76
+ tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-body`);
77
+ }
75
78
  }, [prefix]);
76
79
  const toggleTableHeaderAlignmentClass = useCallback((alignTop = false) => {
77
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- https://github.com/carbon-design-system/carbon/issues/20452
78
- alignTop ? tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-header`) : tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-header`);
80
+ if (alignTop) {
81
+ tableRef.current?.classList.add(`${prefix}--data-table--top-aligned-header`);
82
+ } else {
83
+ tableRef.current?.classList.remove(`${prefix}--data-table--top-aligned-header`);
84
+ }
79
85
  }, [prefix]);
80
86
  const setTableAlignment = useCallback(() => {
81
87
  if (experimentalAutoAlign) {
@@ -43,7 +43,8 @@ export declare const getNextSortDirection: (prevHeader: string, currentHeader: s
43
43
  * @param state - Current table state.
44
44
  * @param key - Header key to sort by.
45
45
  */
46
- export declare const getNextSortState: <ColTypes extends any[]>(props: Props, state: State<ColTypes>, { key }: {
46
+ export declare const getNextSortState: <ColTypes extends any[]>(// eslint-disable-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
47
+ props: Props, state: State<ColTypes>, { key }: {
47
48
  key: string;
48
49
  }) => Pick<State<ColTypes>, "sortHeaderKey" | "sortDirection" | "rowIds">;
49
50
  /**
@@ -54,5 +55,6 @@ export declare const getNextSortState: <ColTypes extends any[]>(props: Props, st
54
55
  * @param key - Header key to sort by.
55
56
  * @param sortDirection - Sort direction to apply.
56
57
  */
57
- export declare const getSortedState: <ColTypes extends any[]>({ locale, sortRow }: Props, { rowIds, cellsById, initialRowOrder }: State<ColTypes>, key: string, sortDirection: DataTableSortState) => Pick<State<ColTypes>, "rowIds" | "sortDirection" | "sortHeaderKey">;
58
+ export declare const getSortedState: <ColTypes extends any[]>(// eslint-disable-line @typescript-eslint/no-explicit-any -- https://github.com/carbon-design-system/carbon/issues/20452
59
+ { locale, sortRow }: Props, { rowIds, cellsById, initialRowOrder }: State<ColTypes>, key: string, sortDirection: DataTableSortState) => Pick<State<ColTypes>, "rowIds" | "sortDirection" | "sortHeaderKey">;
58
60
  export {};
@@ -260,7 +260,7 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
260
260
  className: helperClasses
261
261
  }, helperText) : null;
262
262
  const handleFocus = evt => {
263
- setIsFocused(evt.type === 'focus' && !selectedItem ? true : false);
263
+ setIsFocused(evt.type === 'focus' && !selectedItem);
264
264
  };
265
265
  const buttonRef = useRef(null);
266
266
  const mergedRef = mergeRefs(toggleButtonProps.ref, ref, buttonRef);
@@ -349,10 +349,10 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
349
349
  size: size$1,
350
350
  className: className,
351
351
  invalid: normalizedProps.invalid,
352
- invalidText: isFluid ? invalidText : undefined,
352
+ invalidText: invalidText,
353
353
  invalidTextId: normalizedProps.invalidId,
354
354
  warn: normalizedProps.warn,
355
- warnText: isFluid ? warnText : undefined,
355
+ warnText: warnText,
356
356
  warnTextId: normalizedProps.warnId,
357
357
  light: light,
358
358
  isOpen: isOpen,
@@ -398,7 +398,7 @@ const Dropdown = /*#__PURE__*/React.forwardRef(({
398
398
  }, itemProps), itemToElement ? itemToElement(item) : itemToString(item), selectedItem === item && /*#__PURE__*/React.createElement(Checkmark, {
399
399
  className: `${prefix}--list-box__menu-item__selected-icon`
400
400
  }));
401
- }))), !inline && !isFluid && !normalizedProps.validation && helper, !inline && !isFluid && normalizedProps.validation);
401
+ }))), !inline && !isFluid && !normalizedProps.validation && helper);
402
402
  });
403
403
 
404
404
  // Workaround problems with forwardRef() and generics. In the long term, should stop using forwardRef().
@@ -28,7 +28,7 @@ const ExpandableSearch = frFn((props, forwardedRef) => {
28
28
  ...rest
29
29
  } = props;
30
30
  const [expanded, setExpanded] = useState(isExpanded || false);
31
- const [hasContent, setHasContent] = useState(defaultValue ? true : false);
31
+ const [hasContent, setHasContent] = useState(Boolean(defaultValue));
32
32
  const searchRef = useRef(null);
33
33
  const prefix = usePrefix();
34
34
  function handleBlur(evt) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2025
2
+ * Copyright IBM Corp. 2016, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -8,13 +8,14 @@
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import cx from 'classnames';
10
10
  import PropTypes from 'prop-types';
11
- import React, { useRef, useState, useLayoutEffect } from 'react';
11
+ import React, { useRef, useState } from 'react';
12
12
  import Filename from './Filename.js';
13
13
  import { Enter, Space } from '../../internal/keyboard/keys.js';
14
14
  import { matches } from '../../internal/keyboard/match.js';
15
15
  import { useId } from '../../internal/useId.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
17
17
  import { noopFn } from '../../internal/noopFn.js';
18
+ import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
18
19
  import { Text } from '../Text/Text.js';
19
20
  import '../Text/TextDirection.js';
20
21
  import '../Tooltip/DefinitionTooltip.js';
@@ -58,7 +59,7 @@ function FileUploaderItem({
58
59
  setIsEllipsisApplied(isActive);
59
60
  return isActive;
60
61
  };
61
- useLayoutEffect(() => {
62
+ useIsomorphicEffect(() => {
62
63
  isEllipsisActive(textRef.current);
63
64
  }, [prefix, name]);
64
65
  return /*#__PURE__*/React.createElement("span", _extends({
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2026
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 '@testing-library/jest-dom/jest-globals';
8
+ export declare const findListBoxNode: () => Element | null;
9
+ export declare const findMenuNode: () => Element | null;
10
+ export declare const findMenuItemNode: (index: number) => Element;
11
+ export declare const findMenuIconNode: () => Element | null;
12
+ export declare const findFieldNode: () => Element | null;
13
+ export declare const findComboboxNode: () => Element | null;
14
+ export declare const findPopupNode: () => Element | null;
15
+ export declare const openMenu: () => Promise<void>;
16
+ export declare const assertMenuOpen: (mockProps: {
17
+ items: unknown[];
18
+ }) => void;
19
+ export declare const assertMenuClosed: () => void;
20
+ /**
21
+ * 'GenericItem' corresponds to an item in a collection that is passed to
22
+ * `MultiSelect` that is in a predictable shape and works with the default
23
+ * `itemToString` function.
24
+ */
25
+ export declare const generateGenericItem: (index: number) => {
26
+ id: string;
27
+ label: string;
28
+ value: number;
29
+ };
30
+ /**
31
+ * 'CustomItem' corresponds to a potentially different item structure that might
32
+ * be passed into `MultiSelect` that we would need to supply a custom
33
+ * `itemToString` method for.
34
+ */
35
+ export declare const generateCustomItem: (index: number) => {
36
+ field: string;
37
+ value: string;
38
+ };
39
+ /**
40
+ * Generates an array of values generated by the `generator` function.
41
+ */
42
+ export declare const generateItems: <T>(amount: number, generator: (index: number) => T) => T[];
43
+ export declare const customItemToString: ({ field, }: {
44
+ field: string;
45
+ value: string;
46
+ }) => string;
47
+ /**
48
+ * This object contains two sets of three items that share the same root
49
+ * word in different portions of the string (beginning, middle, end):
50
+ *
51
+ * - 'struct'
52
+ * - 'port'
53
+ *
54
+ * Separated by a disabled item, these derivative words are helpful when
55
+ * testing fuzzy search functions and components that do substring filtering.
56
+ */
57
+ export declare const cognateItems: ({
58
+ id: string;
59
+ text: string;
60
+ disabled?: undefined;
61
+ } | {
62
+ id: string;
63
+ text: string;
64
+ disabled: boolean;
65
+ })[];
66
+ /**
67
+ * Flushes microtasks to ensure element position state is settled
68
+ * From https://floating-ui.com/docs/react#testing
69
+ * More context here: https://github.com/floating-ui/react-popper/issues/368#issuecomment-1340413010
70
+ */
71
+ export declare const waitForPosition: () => Promise<void>;
@@ -10,7 +10,7 @@ import cx from 'classnames';
10
10
  import PropTypes from 'prop-types';
11
11
  import React, { forwardRef, useRef, useContext, useReducer, useMemo, useState, useEffect } from 'react';
12
12
  import { createPortal } from 'react-dom';
13
- import { Escape, ArrowLeft, ArrowUp, ArrowDown } from '../../internal/keyboard/keys.js';
13
+ import { Escape, Tab, ArrowLeft, ArrowUp, ArrowDown } from '../../internal/keyboard/keys.js';
14
14
  import { match } from '../../internal/keyboard/match.js';
15
15
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
@@ -48,6 +48,8 @@ const Menu = /*#__PURE__*/forwardRef(function Menu({
48
48
  const [childState, childDispatch] = useReducer(menuReducer, {
49
49
  ...context.state,
50
50
  isRoot: false,
51
+ hasIcons: false,
52
+ hasSelectableItems: false,
51
53
  size,
52
54
  requestCloseRoot: isRoot ? handleClose : context.state.requestCloseRoot
53
55
  });
@@ -110,9 +112,9 @@ const Menu = /*#__PURE__*/forwardRef(function Menu({
110
112
  function handleKeyDown(e) {
111
113
  e.stopPropagation();
112
114
 
113
- // if the user presses escape or this is a submenu
114
- // and the user presses ArrowLeft, close it
115
- if ((match(e, Escape) || !isRoot && match(e, ArrowLeft)) && onClose) {
115
+ // If the user presses escape or tab, or this is a submenu and the user presses ArrowLeft, close it.
116
+ if ((match(e, Escape) || match(e, Tab) || !isRoot && match(e, ArrowLeft)) && onClose) {
117
+ e.preventDefault();
116
118
  handleClose();
117
119
  } else {
118
120
  focusItem(e);
@@ -246,6 +248,8 @@ const Menu = /*#__PURE__*/forwardRef(function Menu({
246
248
  }
247
249
  return [fitValue(ranges.x, 'x') ?? -1, fitValue(ranges.y, 'y') ?? -1];
248
250
  }
251
+
252
+ // When a menu is opened, focus the first item.
249
253
  useEffect(() => {
250
254
  if (open) {
251
255
  const raf = requestAnimationFrame(() => {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Copyright IBM Corp. 2023, 2025
2
+ * Copyright IBM Corp. 2023, 2026
3
3
  *
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
@@ -14,6 +14,10 @@ export interface MenuItemProps extends LiHTMLAttributes<HTMLLIElement> {
14
14
  * Additional CSS class names.
15
15
  */
16
16
  className?: string;
17
+ /**
18
+ * Specify the message read by screen readers for the danger menu item variant
19
+ */
20
+ dangerDescription?: string;
17
21
  /**
18
22
  * Specify whether the MenuItem is disabled or not.
19
23
  */