@carbon/react 1.100.0 → 1.101.0-rc.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 (118) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +966 -966
  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 +18 -10
  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/FileUploader/FileUploaderItem.d.ts +1 -1
  21. package/es/components/FileUploader/FileUploaderItem.js +3 -2
  22. package/es/components/Menu/Menu.js +8 -4
  23. package/es/components/Menu/MenuItem.d.ts +5 -1
  24. package/es/components/Menu/MenuItem.js +11 -1
  25. package/es/components/MenuButton/index.d.ts +1 -1
  26. package/es/components/MenuButton/index.js +3 -2
  27. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  28. package/es/components/MultiSelect/FilterableMultiSelect.js +7 -5
  29. package/es/components/MultiSelect/MultiSelect.js +8 -4
  30. package/es/components/Notification/Notification.js +2 -1
  31. package/es/components/NumberInput/NumberInput.d.ts +1 -1
  32. package/es/components/NumberInput/NumberInput.js +5 -4
  33. package/es/components/OverflowMenu/OverflowMenu.d.ts +1 -0
  34. package/es/components/OverflowMenu/OverflowMenu.js +8 -4
  35. package/es/components/PageHeader/PageHeader.d.ts +1 -1
  36. package/es/components/PageHeader/PageHeader.js +5 -5
  37. package/es/components/RadioButtonGroup/RadioButtonGroup.js +4 -3
  38. package/es/components/Select/Select.js +2 -1
  39. package/es/components/StructuredList/StructuredList.d.ts +1 -1
  40. package/es/components/StructuredList/StructuredList.js +2 -4
  41. package/es/components/Tabs/Tabs.d.ts +2 -2
  42. package/es/components/Tabs/Tabs.js +20 -26
  43. package/es/components/Tag/DismissibleTag.js +3 -2
  44. package/es/components/Tag/OperationalTag.js +3 -2
  45. package/es/components/Tag/SelectableTag.js +3 -2
  46. package/es/components/Tag/Tag.js +3 -2
  47. package/es/components/TextArea/TextArea.d.ts +1 -1
  48. package/es/components/TextArea/TextArea.js +6 -5
  49. package/es/components/TextInput/ControlledPasswordInput.js +7 -6
  50. package/es/components/TextInput/PasswordInput.js +5 -6
  51. package/es/components/TextInput/TextInput.js +4 -4
  52. package/es/components/TimePicker/TimePicker.js +2 -2
  53. package/es/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  54. package/es/components/Tooltip/DefinitionTooltip.js +3 -2
  55. package/es/internal/useId.js +3 -4
  56. package/es/internal/usePresence.js +3 -2
  57. package/es/internal/useResizeObserver.d.ts +1 -1
  58. package/es/internal/useResizeObserver.js +5 -7
  59. package/es/tools/events.d.ts +1 -1
  60. package/lib/components/AILabel/index.d.ts +1 -1
  61. package/lib/components/AILabel/index.js +1 -12
  62. package/lib/components/Checkbox/Checkbox.js +5 -3
  63. package/lib/components/CheckboxGroup/CheckboxGroup.js +4 -3
  64. package/lib/components/CodeSnippet/CodeSnippet.d.ts +1 -1
  65. package/lib/components/ComboBox/ComboBox.js +18 -10
  66. package/lib/components/ComboButton/index.d.ts +1 -1
  67. package/lib/components/ComboButton/index.js +2 -1
  68. package/lib/components/ComposedModal/ComposedModal.js +16 -21
  69. package/lib/components/ComposedModal/ModalHeader.d.ts +2 -2
  70. package/lib/components/ComposedModal/ModalHeader.js +1 -1
  71. package/lib/components/Copy/Copy.d.ts +1 -1
  72. package/lib/components/CopyButton/CopyButton.d.ts +1 -1
  73. package/lib/components/DataTable/DataTable.d.ts +2 -0
  74. package/lib/components/DataTable/DataTable.js +6 -5
  75. package/lib/components/DataTable/Table.d.ts +1 -1
  76. package/lib/components/DataTable/Table.js +10 -4
  77. package/lib/components/DataTable/state/sorting.d.ts +4 -2
  78. package/lib/components/FileUploader/FileUploaderItem.d.ts +1 -1
  79. package/lib/components/FileUploader/FileUploaderItem.js +2 -1
  80. package/lib/components/Menu/Menu.js +7 -3
  81. package/lib/components/Menu/MenuItem.d.ts +5 -1
  82. package/lib/components/Menu/MenuItem.js +11 -1
  83. package/lib/components/MenuButton/index.d.ts +1 -1
  84. package/lib/components/MenuButton/index.js +2 -1
  85. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  86. package/lib/components/MultiSelect/FilterableMultiSelect.js +6 -4
  87. package/lib/components/MultiSelect/MultiSelect.js +7 -3
  88. package/lib/components/Notification/Notification.js +2 -1
  89. package/lib/components/NumberInput/NumberInput.d.ts +1 -1
  90. package/lib/components/NumberInput/NumberInput.js +5 -4
  91. package/lib/components/OverflowMenu/OverflowMenu.d.ts +1 -0
  92. package/lib/components/OverflowMenu/OverflowMenu.js +7 -3
  93. package/lib/components/PageHeader/PageHeader.d.ts +1 -1
  94. package/lib/components/PageHeader/PageHeader.js +4 -4
  95. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +4 -3
  96. package/lib/components/Select/Select.js +2 -1
  97. package/lib/components/StructuredList/StructuredList.d.ts +1 -1
  98. package/lib/components/StructuredList/StructuredList.js +2 -4
  99. package/lib/components/Tabs/Tabs.d.ts +2 -2
  100. package/lib/components/Tabs/Tabs.js +15 -21
  101. package/lib/components/Tag/DismissibleTag.js +2 -1
  102. package/lib/components/Tag/OperationalTag.js +2 -1
  103. package/lib/components/Tag/SelectableTag.js +2 -1
  104. package/lib/components/Tag/Tag.js +2 -1
  105. package/lib/components/TextArea/TextArea.d.ts +1 -1
  106. package/lib/components/TextArea/TextArea.js +6 -5
  107. package/lib/components/TextInput/ControlledPasswordInput.js +7 -6
  108. package/lib/components/TextInput/PasswordInput.js +5 -6
  109. package/lib/components/TextInput/TextInput.js +4 -4
  110. package/lib/components/TimePicker/TimePicker.js +2 -2
  111. package/lib/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  112. package/lib/components/Tooltip/DefinitionTooltip.js +3 -2
  113. package/lib/internal/useId.js +2 -3
  114. package/lib/internal/usePresence.js +2 -1
  115. package/lib/internal/useResizeObserver.d.ts +1 -1
  116. package/lib/internal/useResizeObserver.js +4 -6
  117. package/lib/tools/events.d.ts +1 -1
  118. package/package.json +8 -8
@@ -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: () => {
@@ -784,7 +792,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
784
792
  }, modifiedItemProps), itemToElement ? itemToElement(item) : itemToString(item), isEqual(currentSelectedItem, item) && /*#__PURE__*/React.createElement(Checkmark, {
785
793
  className: `${prefix}--list-box__menu-item__selected-icon`
786
794
  }));
787
- }) : null)), helperText && !invalid && !warn && !isFluid && /*#__PURE__*/React.createElement(Text, {
795
+ }) : null)), helperText && !normalizedProps.invalid && !normalizedProps.warn && !isFluid && /*#__PURE__*/React.createElement(Text, {
788
796
  as: "div",
789
797
  id: helperTextId,
790
798
  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 {};
@@ -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({
@@ -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
  */
@@ -16,6 +16,7 @@ import { match } from '../../internal/keyboard/match.js';
16
16
  import { useControllableState } from '../../internal/useControllableState.js';
17
17
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
18
18
  import { usePrefix } from '../../internal/usePrefix.js';
19
+ import { useId } from '../../internal/useId.js';
19
20
  import { Menu } from './Menu.js';
20
21
  import { MenuContext } from './MenuContext.js';
21
22
  import '../LayoutDirection/LayoutDirection.js';
@@ -28,6 +29,7 @@ var _Checkmark, _CaretLeft, _CaretRight;
28
29
  const MenuItem = /*#__PURE__*/forwardRef(function MenuItem({
29
30
  children,
30
31
  className,
32
+ dangerDescription = 'danger',
31
33
  disabled,
32
34
  kind = 'default',
33
35
  label,
@@ -164,6 +166,7 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem({
164
166
  }
165
167
  });
166
168
  }, [floatingStyles, refs.floating]);
169
+ const assistiveId = useId('danger-description');
167
170
  return /*#__PURE__*/React.createElement(FloatingFocusManager, {
168
171
  context: floatingContext,
169
172
  order: ['reference', 'floating'],
@@ -188,7 +191,10 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem({
188
191
  }, IconElement && /*#__PURE__*/React.createElement(IconElement, null)), /*#__PURE__*/React.createElement(Text, {
189
192
  as: "div",
190
193
  className: `${prefix}--menu-item__label`
191
- }, label), shortcut && !hasChildren && /*#__PURE__*/React.createElement("div", {
194
+ }, label), isDanger && /*#__PURE__*/React.createElement("span", {
195
+ id: assistiveId,
196
+ className: `${prefix}--visually-hidden`
197
+ }, dangerDescription), shortcut && !hasChildren && /*#__PURE__*/React.createElement("div", {
192
198
  className: `${prefix}--menu-item__shortcut`
193
199
  }, shortcut), hasChildren && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
194
200
  className: `${prefix}--menu-item__shortcut`
@@ -211,6 +217,10 @@ MenuItem.propTypes = {
211
217
  * Additional CSS class names.
212
218
  */
213
219
  className: PropTypes.string,
220
+ /**
221
+ * Specify the message read by screen readers for the danger menu item variant
222
+ */
223
+ dangerDescription: PropTypes.string,
214
224
  /**
215
225
  * Specify whether the MenuItem is disabled or not.
216
226
  */
@@ -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, { forwardRef, useRef, useLayoutEffect } from 'react';
9
+ import React, { forwardRef, useRef } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { ChevronDown } from '@carbon/icons-react';
@@ -17,6 +17,7 @@ import '../Menu/MenuItem.js';
17
17
  import { useAttachedMenu } from '../../internal/useAttachedMenu.js';
18
18
  import { useId } from '../../internal/useId.js';
19
19
  import { usePrefix } from '../../internal/usePrefix.js';
20
+ import useIsomorphicEffect from '../../internal/useIsomorphicEffect.js';
20
21
  import { flip, size, useFloating, autoUpdate } from '@floating-ui/react';
21
22
  import { useFeatureFlag } from '../FeatureFlags/index.js';
22
23
  import { mergeRefs } from '../../tools/mergeRefs.js';
@@ -95,7 +96,7 @@ const MenuButton = /*#__PURE__*/forwardRef(({
95
96
  handleMousedown,
96
97
  handleClose
97
98
  } = useAttachedMenu(triggerRef);
98
- useLayoutEffect(() => {
99
+ useIsomorphicEffect(() => {
99
100
  Object.keys(floatingStyles).forEach(style => {
100
101
  if (refs.floating.current) {
101
102
  let value = floatingStyles[style];
@@ -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.