@carbon/react 1.84.0 → 1.85.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 (181) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +899 -829
  2. package/es/components/AILabel/index.js +6 -1
  3. package/es/components/Checkbox/Checkbox.d.ts +2 -2
  4. package/es/components/Checkbox/Checkbox.js +8 -8
  5. package/es/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
  6. package/es/components/CheckboxGroup/CheckboxGroup.js +9 -8
  7. package/es/components/CodeSnippet/CodeSnippet.js +2 -4
  8. package/es/components/ComboBox/ComboBox.d.ts +1 -1
  9. package/es/components/ComboBox/ComboBox.js +8 -7
  10. package/es/components/ComposedModal/ComposedModal.d.ts +1 -1
  11. package/es/components/ComposedModal/ComposedModal.js +15 -10
  12. package/es/components/ContainedList/ContainedList.d.ts +1 -1
  13. package/es/components/ContainedList/ContainedList.js +4 -2
  14. package/es/components/ContentSwitcher/ContentSwitcher.js +6 -5
  15. package/es/components/DataTable/DataTable.js +3 -0
  16. package/es/components/DataTable/TableDecoratorRow.d.ts +2 -2
  17. package/es/components/DataTable/TableDecoratorRow.js +8 -8
  18. package/es/components/DataTable/TableExpandRow.d.ts +1 -1
  19. package/es/components/DataTable/TableExpandRow.js +15 -6
  20. package/es/components/DataTable/TableHeader.js +10 -10
  21. package/es/components/DataTable/TableRow.js +12 -4
  22. package/es/components/DataTable/tools/normalize.js +2 -1
  23. package/es/components/DatePicker/DatePicker.d.ts +1 -1
  24. package/es/components/DatePicker/DatePicker.js +2 -2
  25. package/es/components/DatePicker/plugins/appendToPlugin.d.ts +12 -0
  26. package/es/components/DatePicker/plugins/appendToPlugin.js +9 -12
  27. package/es/components/DatePickerInput/DatePickerInput.js +8 -7
  28. package/es/components/Dialog/index.d.ts +5 -1
  29. package/es/components/Dialog/index.js +20 -0
  30. package/es/components/Dropdown/Dropdown.d.ts +1 -1
  31. package/es/components/Dropdown/Dropdown.js +8 -10
  32. package/es/components/FileUploader/FileUploaderButton.js +2 -2
  33. package/es/components/FileUploader/FileUploaderDropContainer.js +2 -2
  34. package/es/components/FileUploader/FileUploaderItem.js +2 -2
  35. package/es/components/Layer/index.d.ts +1 -3
  36. package/es/components/Layer/index.js +9 -8
  37. package/es/components/Menu/Menu.js +7 -8
  38. package/es/components/Menu/MenuItem.js +13 -2
  39. package/es/components/Modal/Modal.d.ts +2 -2
  40. package/es/components/Modal/Modal.js +20 -9
  41. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  42. package/es/components/MultiSelect/FilterableMultiSelect.js +9 -8
  43. package/es/components/MultiSelect/MultiSelect.d.ts +1 -1
  44. package/es/components/MultiSelect/MultiSelect.js +8 -7
  45. package/es/components/MultiSelect/filter.d.ts +10 -0
  46. package/es/components/MultiSelect/filter.js +21 -0
  47. package/es/components/NumberInput/NumberInput.d.ts +1 -1
  48. package/es/components/NumberInput/NumberInput.js +9 -8
  49. package/es/components/PageHeader/PageHeader.js +2 -2
  50. package/es/components/Popover/index.js +2 -1
  51. package/es/components/RadioButton/RadioButton.d.ts +2 -2
  52. package/es/components/RadioButton/RadioButton.js +8 -8
  53. package/es/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
  54. package/es/components/RadioButtonGroup/RadioButtonGroup.js +9 -8
  55. package/es/components/RadioTile/RadioTile.d.ts +1 -1
  56. package/es/components/RadioTile/RadioTile.js +8 -7
  57. package/es/components/Select/Select.d.ts +2 -2
  58. package/es/components/Select/Select.js +8 -7
  59. package/es/components/Slider/Slider.d.ts +59 -198
  60. package/es/components/Slider/Slider.js +68 -120
  61. package/es/components/Tabs/usePressable.d.ts +19 -0
  62. package/es/components/Tabs/usePressable.js +19 -33
  63. package/es/components/Tag/DismissibleTag.d.ts +1 -1
  64. package/es/components/Tag/DismissibleTag.js +9 -8
  65. package/es/components/Tag/Tag.d.ts +1 -1
  66. package/es/components/Tag/Tag.js +9 -8
  67. package/es/components/TextArea/TextArea.js +8 -7
  68. package/es/components/TextInput/TextInput.d.ts +1 -1
  69. package/es/components/TextInput/TextInput.js +20 -9
  70. package/es/components/Tile/Tile.d.ts +2 -2
  71. package/es/components/Tile/Tile.js +30 -36
  72. package/es/components/Toggletip/index.js +2 -2
  73. package/es/components/Tooltip/DefinitionTooltip.js +1 -0
  74. package/es/components/Tooltip/Tooltip.d.ts +2 -2
  75. package/es/components/Tooltip/Tooltip.js +2 -2
  76. package/es/components/TreeView/TreeNode.d.ts +22 -0
  77. package/es/components/TreeView/TreeNode.js +119 -12
  78. package/es/components/TreeView/TreeView.js +3 -3
  79. package/es/components/UIShell/Content.d.ts +5 -3
  80. package/es/components/UIShell/HeaderPanel.d.ts +2 -2
  81. package/es/components/UIShell/HeaderPanel.js +9 -5
  82. package/es/internal/Selection.js +8 -3
  83. package/es/internal/environment.js +1 -12
  84. package/{lib/internal/__mocks__/mockHTMLElement.d.ts → es/internal/index.d.ts} +2 -4
  85. package/es/internal/useResizeObserver.d.ts +1 -1
  86. package/es/internal/utils.d.ts +14 -0
  87. package/es/internal/utils.js +18 -0
  88. package/es/tools/uniqueId.d.ts +1 -6
  89. package/lib/components/AILabel/index.js +6 -1
  90. package/lib/components/Checkbox/Checkbox.d.ts +2 -2
  91. package/lib/components/Checkbox/Checkbox.js +7 -7
  92. package/lib/components/CheckboxGroup/CheckboxGroup.d.ts +2 -2
  93. package/lib/components/CheckboxGroup/CheckboxGroup.js +8 -7
  94. package/lib/components/CodeSnippet/CodeSnippet.js +2 -4
  95. package/lib/components/ComboBox/ComboBox.d.ts +1 -1
  96. package/lib/components/ComboBox/ComboBox.js +11 -10
  97. package/lib/components/ComposedModal/ComposedModal.d.ts +1 -1
  98. package/lib/components/ComposedModal/ComposedModal.js +16 -11
  99. package/lib/components/ContainedList/ContainedList.d.ts +1 -1
  100. package/lib/components/ContainedList/ContainedList.js +4 -2
  101. package/lib/components/ContentSwitcher/ContentSwitcher.js +5 -4
  102. package/lib/components/DataTable/DataTable.js +3 -0
  103. package/lib/components/DataTable/TableDecoratorRow.d.ts +2 -2
  104. package/lib/components/DataTable/TableDecoratorRow.js +8 -8
  105. package/lib/components/DataTable/TableExpandRow.d.ts +1 -1
  106. package/lib/components/DataTable/TableExpandRow.js +14 -5
  107. package/lib/components/DataTable/TableHeader.js +9 -9
  108. package/lib/components/DataTable/TableRow.js +11 -3
  109. package/lib/components/DataTable/tools/normalize.js +2 -1
  110. package/lib/components/DatePicker/DatePicker.d.ts +1 -1
  111. package/lib/components/DatePicker/DatePicker.js +1 -1
  112. package/lib/components/DatePicker/plugins/appendToPlugin.d.ts +12 -0
  113. package/lib/components/DatePicker/plugins/appendToPlugin.js +9 -12
  114. package/lib/components/DatePickerInput/DatePickerInput.js +7 -6
  115. package/lib/components/Dialog/index.d.ts +5 -1
  116. package/lib/components/Dialog/index.js +20 -0
  117. package/lib/components/Dropdown/Dropdown.d.ts +1 -1
  118. package/lib/components/Dropdown/Dropdown.js +12 -14
  119. package/lib/components/FileUploader/FileUploaderButton.js +2 -2
  120. package/lib/components/FileUploader/FileUploaderDropContainer.js +2 -2
  121. package/lib/components/FileUploader/FileUploaderItem.js +2 -2
  122. package/lib/components/Layer/index.d.ts +1 -3
  123. package/lib/components/Layer/index.js +9 -8
  124. package/lib/components/Menu/Menu.js +7 -8
  125. package/lib/components/Menu/MenuItem.js +13 -2
  126. package/lib/components/Modal/Modal.d.ts +2 -2
  127. package/lib/components/Modal/Modal.js +28 -17
  128. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +1 -1
  129. package/lib/components/MultiSelect/FilterableMultiSelect.js +13 -12
  130. package/lib/components/MultiSelect/MultiSelect.d.ts +1 -1
  131. package/lib/components/MultiSelect/MultiSelect.js +13 -12
  132. package/lib/components/MultiSelect/filter.d.ts +10 -0
  133. package/lib/components/MultiSelect/filter.js +25 -0
  134. package/lib/components/NumberInput/NumberInput.d.ts +1 -1
  135. package/lib/components/NumberInput/NumberInput.js +8 -7
  136. package/lib/components/PageHeader/PageHeader.js +2 -2
  137. package/lib/components/Popover/index.js +2 -1
  138. package/lib/components/RadioButton/RadioButton.d.ts +2 -2
  139. package/lib/components/RadioButton/RadioButton.js +7 -7
  140. package/lib/components/RadioButtonGroup/RadioButtonGroup.d.ts +2 -2
  141. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +10 -9
  142. package/lib/components/RadioTile/RadioTile.d.ts +1 -1
  143. package/lib/components/RadioTile/RadioTile.js +7 -6
  144. package/lib/components/Select/Select.d.ts +2 -2
  145. package/lib/components/Select/Select.js +7 -6
  146. package/lib/components/Slider/Slider.d.ts +59 -198
  147. package/lib/components/Slider/Slider.js +67 -119
  148. package/lib/components/Tabs/usePressable.d.ts +19 -0
  149. package/lib/components/Tabs/usePressable.js +19 -33
  150. package/lib/components/Tag/DismissibleTag.d.ts +1 -1
  151. package/lib/components/Tag/DismissibleTag.js +8 -7
  152. package/lib/components/Tag/Tag.d.ts +1 -1
  153. package/lib/components/Tag/Tag.js +8 -7
  154. package/lib/components/TextArea/TextArea.js +7 -6
  155. package/lib/components/TextInput/TextInput.d.ts +1 -1
  156. package/lib/components/TextInput/TextInput.js +19 -8
  157. package/lib/components/Tile/Tile.d.ts +2 -2
  158. package/lib/components/Tile/Tile.js +29 -35
  159. package/lib/components/Toggletip/index.js +2 -2
  160. package/lib/components/Tooltip/DefinitionTooltip.js +1 -0
  161. package/lib/components/Tooltip/Tooltip.d.ts +2 -2
  162. package/lib/components/Tooltip/Tooltip.js +2 -2
  163. package/lib/components/TreeView/TreeNode.d.ts +22 -0
  164. package/lib/components/TreeView/TreeNode.js +118 -11
  165. package/lib/components/TreeView/TreeView.js +3 -3
  166. package/lib/components/UIShell/Content.d.ts +5 -3
  167. package/lib/components/UIShell/HeaderPanel.d.ts +2 -2
  168. package/lib/components/UIShell/HeaderPanel.js +8 -4
  169. package/lib/internal/Selection.js +8 -3
  170. package/lib/internal/environment.js +1 -12
  171. package/{es/internal/__mocks__/mockHTMLElement.d.ts → lib/internal/index.d.ts} +2 -4
  172. package/lib/internal/useResizeObserver.d.ts +1 -1
  173. package/lib/internal/utils.d.ts +14 -0
  174. package/lib/internal/utils.js +22 -0
  175. package/lib/tools/uniqueId.d.ts +1 -6
  176. package/package.json +11 -20
  177. package/telemetry.yml +1 -0
  178. package/es/components/ComboBox/tools/filter.js +0 -18
  179. package/es/tools/uniqueId.js +0 -14
  180. package/lib/components/ComboBox/tools/filter.js +0 -22
  181. package/lib/tools/uniqueId.js +0 -18
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import PropTypes from 'prop-types';
10
- import React, { useContext, useRef, useState, useEffect, forwardRef } from 'react';
10
+ import React, { useContext, useRef, useState, useEffect, forwardRef, cloneElement } from 'react';
11
11
  import cx from 'classnames';
12
12
  import deprecate from '../../prop-types/deprecate.js';
13
13
  import { WarningFilled, WarningAltFilled } from '@carbon/icons-react';
@@ -20,6 +20,8 @@ import { useMergedRefs } from '../../internal/useMergedRefs.js';
20
20
  import { useId } from '../../internal/useId.js';
21
21
  import { noopFn } from '../../internal/noopFn.js';
22
22
  import '../Text/index.js';
23
+ import { AILabel } from '../AILabel/index.js';
24
+ import { isComponentElement } from '../../internal/utils.js';
23
25
  import { Text } from '../Text/Text.js';
24
26
 
25
27
  const frFn = forwardRef;
@@ -258,12 +260,11 @@ const TextArea = frFn((props, forwardRef) => {
258
260
  }));
259
261
 
260
262
  // AILabel is always size `mini`
261
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
262
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
263
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
264
- size: 'mini'
265
- });
266
- }
263
+ const candidate = slug ?? decorator;
264
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
265
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
266
+ size: 'mini'
267
+ }) : null;
267
268
  return /*#__PURE__*/React.createElement("div", {
268
269
  className: formItemClasses
269
270
  }, /*#__PURE__*/React.createElement("div", {
@@ -4,7 +4,7 @@
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
6
  */
7
- import React, { ReactNode } from 'react';
7
+ import React, { type ReactNode } from 'react';
8
8
  type ExcludedAttributes = 'defaultValue' | 'id' | 'size' | 'value';
9
9
  export interface TextInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, ExcludedAttributes> {
10
10
  /**
@@ -6,16 +6,19 @@
6
6
  */
7
7
 
8
8
  import PropTypes from 'prop-types';
9
- import React, { useState, useContext, useRef, useEffect } from 'react';
9
+ import React, { useRef, useState, useEffect, useContext, cloneElement } from 'react';
10
10
  import cx from 'classnames';
11
11
  import { useNormalizedInputProps } from '../../internal/useNormalizedInputProps.js';
12
12
  import deprecate from '../../prop-types/deprecate.js';
13
13
  import { textInputProps } from './util.js';
14
14
  import '../FluidForm/FluidForm.js';
15
15
  import { FormContext } from '../FluidForm/FormContext.js';
16
+ import { useMergedRefs } from '../../internal/useMergedRefs.js';
16
17
  import { usePrefix } from '../../internal/usePrefix.js';
17
18
  import { getAnnouncement } from '../../internal/getAnnouncement.js';
18
19
  import '../Text/index.js';
20
+ import { AILabel } from '../AILabel/index.js';
21
+ import { isComponentElement } from '../../internal/utils.js';
19
22
  import { Text } from '../Text/Text.js';
20
23
 
21
24
  const TextInput = /*#__PURE__*/React.forwardRef(function TextInput({
@@ -48,7 +51,16 @@ const TextInput = /*#__PURE__*/React.forwardRef(function TextInput({
48
51
  defaultValue,
49
52
  value
50
53
  } = rest;
51
- const [textCount, setTextCount] = useState(defaultValue?.toString().length || value?.toString().length || 0);
54
+ const inputRef = useRef(null);
55
+ const mergedRef = useMergedRefs([ref, inputRef]);
56
+ function getInitialTextCount() {
57
+ const targetValue = defaultValue || value || inputRef.current?.value || '';
58
+ return targetValue.toString().length;
59
+ }
60
+ const [textCount, setTextCount] = useState(getInitialTextCount());
61
+ useEffect(() => {
62
+ setTextCount(getInitialTextCount());
63
+ }, [value, defaultValue, enableCounter]);
52
64
  const normalizedProps = useNormalizedInputProps({
53
65
  id,
54
66
  readOnly,
@@ -81,7 +93,7 @@ const TextInput = /*#__PURE__*/React.forwardRef(function TextInput({
81
93
  },
82
94
  placeholder,
83
95
  type,
84
- ref,
96
+ ref: mergedRef,
85
97
  className: textInputClasses,
86
98
  title: placeholder,
87
99
  disabled: normalizedProps.disabled,
@@ -179,12 +191,11 @@ const TextInput = /*#__PURE__*/React.forwardRef(function TextInput({
179
191
  const Icon = normalizedProps.icon;
180
192
 
181
193
  // AILabel is always size `mini`
182
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
183
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
184
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
185
- size: 'mini'
186
- });
187
- }
194
+ const candidate = slug ?? decorator;
195
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
196
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
197
+ size: 'mini'
198
+ }) : null;
188
199
  return /*#__PURE__*/React.createElement("div", {
189
200
  className: inputWrapperClasses
190
201
  }, !inline ? labelWrapper : /*#__PURE__*/React.createElement("div", {
@@ -4,7 +4,7 @@
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
6
  */
7
- import React, { type ChangeEvent, type HTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react';
7
+ import React, { type HTMLAttributes, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react';
8
8
  export interface TileProps extends HTMLAttributes<HTMLDivElement> {
9
9
  children?: ReactNode;
10
10
  className?: string;
@@ -105,7 +105,7 @@ export interface SelectableTileProps extends HTMLAttributes<HTMLDivElement> {
105
105
  /**
106
106
  * The empty handler of the `<input>`.
107
107
  */
108
- onChange?(event: ChangeEvent<HTMLDivElement>, selected?: boolean, id?: string): void;
108
+ onChange?(event: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>, selected?: boolean, id?: string): void;
109
109
  /**
110
110
  * Specify the function to run when the SelectableTile is clicked
111
111
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { useState, useRef, useEffect } from 'react';
9
+ import React, { useState, useEffect, useCallback, useRef, cloneElement } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { AiLabel, CheckboxCheckedFilled, Checkbox, ChevronDown, ArrowRight, Error } from '@carbon/icons-react';
@@ -22,6 +22,8 @@ import { useMergedRefs } from '../../internal/useMergedRefs.js';
22
22
  import { useFeatureFlag } from '../FeatureFlags/index.js';
23
23
  import { useId } from '../../internal/useId.js';
24
24
  import '../Text/index.js';
25
+ import { AILabel } from '../AILabel/index.js';
26
+ import { isComponentElement } from '../../internal/utils.js';
25
27
  import { Text } from '../Text/Text.js';
26
28
 
27
29
  var _CheckboxCheckedFille, _Checkbox, _ChevronDown, _ChevronDown2;
@@ -224,7 +226,11 @@ const SelectableTile = /*#__PURE__*/React.forwardRef(function SelectableTile({
224
226
  const clickHandler = onClick;
225
227
  const keyDownHandler = onKeyDown;
226
228
  const [isSelected, setIsSelected] = useState(selected);
227
- const [prevSelected, setPrevSelected] = useState(selected);
229
+
230
+ // Use useEffect to sync with prop changes instead of render-time logic
231
+ useEffect(() => {
232
+ setIsSelected(selected);
233
+ }, [selected]);
228
234
  const classes = cx(`${prefix}--tile`, `${prefix}--tile--selectable`, {
229
235
  [`${prefix}--tile--is-selected`]: isSelected,
230
236
  [`${prefix}--tile--light`]: light,
@@ -234,50 +240,40 @@ const SelectableTile = /*#__PURE__*/React.forwardRef(function SelectableTile({
234
240
  [`${prefix}--tile--decorator`]: decorator,
235
241
  [`${prefix}--tile--decorator-rounded`]: decorator && hasRoundedCorners
236
242
  }, className);
243
+
244
+ // Single function to handle selection changes
245
+ const handleSelectionChange = useCallback((evt, newSelected) => {
246
+ setIsSelected(newSelected);
247
+ onChange(evt, newSelected, id);
248
+ }, [onChange, id]);
237
249
  function handleClick(evt) {
238
250
  evt.preventDefault();
239
251
  evt?.persist?.();
240
- if (normalizedDecorator && decoratorRef.current && decoratorRef.current.contains(evt.target)) {
252
+ if (normalizedDecorator && decoratorRef.current && evt.target instanceof Node && decoratorRef.current.contains(evt.target)) {
241
253
  return;
242
254
  }
243
- setIsSelected(prevSelected => {
244
- const newSelected = !prevSelected;
245
- onChange(evt, newSelected, id);
246
- return newSelected;
247
- });
255
+ const newSelected = !isSelected;
256
+ handleSelectionChange(evt, newSelected);
248
257
  clickHandler(evt);
249
258
  }
250
259
  function handleKeyDown(evt) {
251
260
  evt?.persist?.();
252
261
  if (matches(evt, [Enter, Space])) {
253
262
  evt.preventDefault();
254
- setIsSelected(prevSelected => {
255
- const newSelected = !prevSelected;
256
- onChange(evt, newSelected, id);
257
- return newSelected;
258
- });
263
+ const newSelected = !isSelected;
264
+ handleSelectionChange(evt, newSelected);
259
265
  }
260
266
  keyDownHandler(evt);
261
267
  }
262
- function handleChange(event) {
263
- const newSelected = event.target.checked;
264
- setIsSelected(newSelected);
265
- onChange(event, newSelected, id);
266
- }
267
- if (selected !== prevSelected) {
268
- setIsSelected(selected);
269
- setPrevSelected(selected);
270
- }
271
268
 
272
269
  // AILabel is always size `xs`
273
270
  const decoratorRef = useRef(null);
274
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
275
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
276
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
277
- size: 'xs',
278
- ref: decoratorRef
279
- });
280
- }
271
+ const candidate = slug ?? decorator;
272
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
273
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
274
+ size: 'xs',
275
+ ref: decoratorRef
276
+ }) : null;
281
277
  return (
282
278
  /*#__PURE__*/
283
279
  // eslint-disable-next-line jsx-a11y/interactive-supports-focus
@@ -292,7 +288,6 @@ const SelectableTile = /*#__PURE__*/React.forwardRef(function SelectableTile({
292
288
  tabIndex: !disabled ? tabIndex : undefined,
293
289
  ref: ref,
294
290
  id: id,
295
- onChange: !disabled ? handleChange : undefined,
296
291
  title: title
297
292
  }, rest), /*#__PURE__*/React.createElement("span", {
298
293
  className: `${prefix}--tile__checkmark ${prefix}--tile__checkmark--persistent`
@@ -505,12 +500,11 @@ const ExpandableTile = /*#__PURE__*/React.forwardRef(function ExpandableTile({
505
500
  const belowTheFoldId = useId('expandable-tile-interactive');
506
501
 
507
502
  // AILabel is always size `xs`
508
- let normalizedDecorator = /*#__PURE__*/React.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
509
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
510
- normalizedDecorator = /*#__PURE__*/React.cloneElement(normalizedDecorator, {
511
- size: 'xs'
512
- });
513
- }
503
+ const candidate = slug ?? decorator;
504
+ const candidateIsAILabel = isComponentElement(candidate, AILabel);
505
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
506
+ size: 'xs'
507
+ }) : null;
514
508
  return interactive ? /*#__PURE__*/React.createElement("div", _extends({
515
509
  ref: ref,
516
510
  className: interactiveClassNames
@@ -88,6 +88,7 @@ function Toggletip({
88
88
  buttonProps: {
89
89
  'aria-expanded': open,
90
90
  'aria-controls': id,
91
+ 'aria-describedby': open ? id : undefined,
91
92
  onClick: actions.toggle
92
93
  },
93
94
  contentProps: {
@@ -259,8 +260,7 @@ const ToggletipContent = /*#__PURE__*/React.forwardRef(function ToggletipContent
259
260
  return /*#__PURE__*/React.createElement(PopoverContent, _extends({
260
261
  className: customClassName
261
262
  }, toggletip?.contentProps, {
262
- ref: ref,
263
- "aria-live": "polite"
263
+ ref: ref
264
264
  }), /*#__PURE__*/React.createElement("div", {
265
265
  className: `${prefix}--toggletip-content`
266
266
  }, children));
@@ -57,6 +57,7 @@ const DefinitionTooltip = ({
57
57
  }, /*#__PURE__*/React.createElement("button", _extends({}, rest, {
58
58
  className: cx(`${prefix}--definition-term`, triggerClassName),
59
59
  "aria-controls": tooltipId,
60
+ "aria-describedby": tooltipId,
60
61
  "aria-expanded": isOpen,
61
62
  onBlur: () => {
62
63
  setOpen(false);
@@ -4,7 +4,7 @@
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
6
  */
7
- import React from 'react';
7
+ import React, { type JSX } from 'react';
8
8
  import { Popover, PopoverAlignment } from '../Popover';
9
9
  import { PolymorphicComponentPropWithRef } from '../../internal/PolymorphicProps';
10
10
  interface TooltipBaseProps {
@@ -15,7 +15,7 @@ interface TooltipBaseProps {
15
15
  /**
16
16
  * Pass in the child to which the tooltip will be applied
17
17
  */
18
- children?: React.ReactElement<any>;
18
+ children?: React.ReactElement<JSX.IntrinsicElements[keyof JSX.IntrinsicElements]>;
19
19
  /**
20
20
  * Specify an optional className to be applied to the container node
21
21
  */
@@ -55,7 +55,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef(({
55
55
 
56
56
  // An `aria-label` takes precedence over `aria-describedby`, but when it's
57
57
  // needed and the user doesn't specify one, the fallback `id` is used.
58
- const labelledBy = hasAriaLabel ? null : hasLabel ? ariaLabelledBy ?? id : undefined;
58
+ const labelledBy = hasAriaLabel ? undefined : hasLabel ? ariaLabelledBy ?? id : undefined;
59
59
 
60
60
  // If `aria-label` is present, use any provided `aria-describedby`.
61
61
  // If not, fallback to child's `aria-describedby` or the tooltip `id` if needed.
@@ -175,7 +175,7 @@ const Tooltip = /*#__PURE__*/React.forwardRef(({
175
175
  open: open
176
176
  }), /*#__PURE__*/React.createElement("div", {
177
177
  className: `${prefix}--tooltip-trigger__wrapper`
178
- }, child !== undefined ? /*#__PURE__*/React.cloneElement(child, {
178
+ }, typeof child !== 'undefined' ? /*#__PURE__*/React.cloneElement(child, {
179
179
  ...triggerProps,
180
180
  ...getChildEventHandlers(child.props)
181
181
  }) : null), /*#__PURE__*/React.createElement(PopoverContent, {
@@ -78,6 +78,17 @@ export type TreeNodeProps = {
78
78
  * Optional: The URL the TreeNode is linking to
79
79
  */
80
80
  href?: string;
81
+ /**
82
+ *
83
+ * Specify how the trigger should align with the tooltip when text is truncated
84
+ */
85
+ align?: 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
86
+ /**
87
+ * **Experimental**: Will attempt to automatically align the floating
88
+ * element to avoid collisions with the viewport and being clipped by
89
+ * ancestor elements.
90
+ */
91
+ autoAlign?: boolean;
81
92
  } & Omit<React.LiHTMLAttributes<HTMLElement>, 'onSelect'>;
82
93
  declare const TreeNode: React.ForwardRefExoticComponent<{
83
94
  /**
@@ -152,5 +163,16 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
152
163
  * Optional: The URL the TreeNode is linking to
153
164
  */
154
165
  href?: string;
166
+ /**
167
+ *
168
+ * Specify how the trigger should align with the tooltip when text is truncated
169
+ */
170
+ align?: "top" | "bottom" | "left" | "right" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "left-end" | "left-start" | "right-end" | "right-start";
171
+ /**
172
+ * **Experimental**: Will attempt to automatically align the floating
173
+ * element to avoid collisions with the viewport and being clipped by
174
+ * ancestor elements.
175
+ */
176
+ autoAlign?: boolean;
155
177
  } & Omit<React.LiHTMLAttributes<HTMLElement>, "onSelect"> & React.RefAttributes<HTMLElement>>;
156
178
  export default TreeNode;
@@ -9,14 +9,83 @@ import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js
9
9
  import { CaretDown } from '@carbon/icons-react';
10
10
  import cx from 'classnames';
11
11
  import PropTypes from 'prop-types';
12
- import React, { useRef, useState, useEffect } from 'react';
12
+ import React, { useRef, useState, useEffect, useCallback } from 'react';
13
13
  import { ArrowLeft, ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
14
14
  import { matches, match } from '../../internal/keyboard/match.js';
15
15
  import { useControllableState } from '../../internal/useControllableState.js';
16
16
  import { usePrefix } from '../../internal/usePrefix.js';
17
- import { uniqueId } from '../../tools/uniqueId.js';
17
+ import { useId } from '../../internal/useId.js';
18
18
  import { useFeatureFlag } from '../FeatureFlags/index.js';
19
+ import { IconButton } from '../IconButton/index.js';
19
20
 
21
+ const extractTextContent = node => {
22
+ if (node === null || node === undefined) return '';
23
+ if (typeof node === 'string') return node;
24
+ if (typeof node === 'number') return String(node);
25
+ if (typeof node === 'boolean') return String(node);
26
+ if (Array.isArray(node)) {
27
+ return node.map(extractTextContent).join('');
28
+ }
29
+ if (/*#__PURE__*/React.isValidElement(node)) {
30
+ const element = node;
31
+ const children = element.props.children;
32
+ return extractTextContent(children);
33
+ }
34
+ return '';
35
+ };
36
+ const useEllipsisCheck = (label, detailsWrapperRef) => {
37
+ const [isEllipsisApplied, setIsEllipsisApplied] = useState(false);
38
+ const labelTextRef = useRef(null);
39
+ const checkEllipsis = useCallback(() => {
40
+ const element = labelTextRef.current;
41
+ if (!element) {
42
+ setIsEllipsisApplied(false);
43
+ return;
44
+ }
45
+ if (element.offsetWidth === 0) {
46
+ setIsEllipsisApplied(false);
47
+ return;
48
+ }
49
+ const checkElement = detailsWrapperRef.current || element;
50
+ if (checkElement && checkElement.offsetWidth > 0) {
51
+ const isTextTruncated = element.scrollWidth > checkElement.offsetWidth;
52
+ setIsEllipsisApplied(isTextTruncated);
53
+ } else {
54
+ setIsEllipsisApplied(false);
55
+ }
56
+ }, [detailsWrapperRef]);
57
+ useEffect(() => {
58
+ let animationFrameId;
59
+ animationFrameId = requestAnimationFrame(checkEllipsis);
60
+ let resizeObserver;
61
+ if (typeof window !== 'undefined' && typeof window.ResizeObserver !== 'undefined' && labelTextRef.current) {
62
+ resizeObserver = new window.ResizeObserver(() => {
63
+ requestAnimationFrame(checkEllipsis);
64
+ });
65
+ resizeObserver.observe(labelTextRef.current);
66
+ if (detailsWrapperRef.current) {
67
+ resizeObserver.observe(detailsWrapperRef.current);
68
+ }
69
+ }
70
+ return () => {
71
+ cancelAnimationFrame(animationFrameId);
72
+ if (resizeObserver) {
73
+ if (labelTextRef.current) {
74
+ resizeObserver.unobserve(labelTextRef.current);
75
+ }
76
+ if (detailsWrapperRef.current) {
77
+ resizeObserver.unobserve(detailsWrapperRef.current);
78
+ }
79
+ resizeObserver.disconnect();
80
+ }
81
+ };
82
+ }, [checkEllipsis, detailsWrapperRef]);
83
+ return {
84
+ labelTextRef,
85
+ isEllipsisApplied,
86
+ tooltipText: extractTextContent(label)
87
+ };
88
+ };
20
89
  const TreeNode = /*#__PURE__*/React.forwardRef(({
21
90
  active,
22
91
  children,
@@ -35,15 +104,22 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
35
104
  selected: propSelected,
36
105
  value,
37
106
  href,
107
+ align = 'bottom',
108
+ autoAlign = false,
38
109
  ...rest
39
110
  }, forwardedRef) => {
40
- // These are provided by the parent TreeView component
41
111
  const depth = propDepth;
42
112
  const selected = propSelected;
113
+ const detailsWrapperRef = useRef(null);
114
+ const {
115
+ labelTextRef,
116
+ isEllipsisApplied,
117
+ tooltipText
118
+ } = useEllipsisCheck(label, detailsWrapperRef);
43
119
  const enableTreeviewControllable = useFeatureFlag('enable-treeview-controllable');
44
120
  const {
45
121
  current: id
46
- } = useRef(nodeId || uniqueId());
122
+ } = useRef(nodeId || useId());
47
123
  const controllableExpandedState = useControllableState({
48
124
  value: isExpanded,
49
125
  onChange: newValue => {
@@ -61,6 +137,25 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
61
137
  const currentNode = useRef(null);
62
138
  const currentNodeLabel = useRef(null);
63
139
  const prefix = usePrefix();
140
+ const renderLabelText = () => {
141
+ if (isEllipsisApplied && tooltipText) {
142
+ return /*#__PURE__*/React.createElement(IconButton, {
143
+ label: tooltipText,
144
+ kind: "ghost",
145
+ align: align,
146
+ autoAlign: autoAlign,
147
+ className: `${prefix}--tree-node__label__text-button`,
148
+ wrapperClasses: `${prefix}--popover-container`
149
+ }, /*#__PURE__*/React.createElement("span", {
150
+ ref: labelTextRef,
151
+ className: `${prefix}--tree-node__label__text`
152
+ }, label));
153
+ }
154
+ return /*#__PURE__*/React.createElement("span", {
155
+ ref: labelTextRef,
156
+ className: `${prefix}--tree-node__label__text`
157
+ }, label);
158
+ };
64
159
  const setRefs = element => {
65
160
  currentNode.current = element;
66
161
  if (typeof forwardedRef === 'function') {
@@ -72,7 +167,7 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
72
167
  function enhanceTreeNodes(children) {
73
168
  return React.Children.map(children, node => {
74
169
  if (! /*#__PURE__*/React.isValidElement(node)) return node;
75
- const isTreeNode = node.type.displayName === 'TreeNode';
170
+ const isTreeNode = node.type === TreeNode;
76
171
  if (isTreeNode) {
77
172
  return /*#__PURE__*/React.cloneElement(node, {
78
173
  active,
@@ -300,7 +395,7 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
300
395
  ref: currentNodeLabel
301
396
  }, Icon && /*#__PURE__*/React.createElement(Icon, {
302
397
  className: `${prefix}--tree-node__icon`
303
- }), label)));
398
+ }), renderLabelText())));
304
399
  } else {
305
400
  return /*#__PURE__*/React.createElement("li", _extends({}, treeNodeProps, {
306
401
  ref: setRefs
@@ -309,7 +404,7 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
309
404
  ref: currentNodeLabel
310
405
  }, Icon && /*#__PURE__*/React.createElement(Icon, {
311
406
  className: `${prefix}--tree-node__icon`
312
- }), label));
407
+ }), renderLabelText()));
313
408
  }
314
409
  }
315
410
  if (href) {
@@ -332,10 +427,11 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
332
427
  }, /*#__PURE__*/React.createElement(CaretDown, {
333
428
  className: toggleClasses
334
429
  })), /*#__PURE__*/React.createElement("span", {
335
- className: `${prefix}--tree-node__label__details`
430
+ className: `${prefix}--tree-node__label__details`,
431
+ ref: detailsWrapperRef
336
432
  }, Icon && /*#__PURE__*/React.createElement(Icon, {
337
433
  className: `${prefix}--tree-node__icon`
338
- }), label))), /*#__PURE__*/React.createElement("ul", {
434
+ }), renderLabelText()))), /*#__PURE__*/React.createElement("ul", {
339
435
  id: `${id}-subtree`,
340
436
  role: "group",
341
437
  className: cx(`${prefix}--tree-node__children`, {
@@ -358,10 +454,11 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
358
454
  }, /*#__PURE__*/React.createElement(CaretDown, {
359
455
  className: toggleClasses
360
456
  })), /*#__PURE__*/React.createElement("span", {
361
- className: `${prefix}--tree-node__label__details`
457
+ className: `${prefix}--tree-node__label__details`,
458
+ ref: detailsWrapperRef
362
459
  }, Icon && /*#__PURE__*/React.createElement(Icon, {
363
460
  className: `${prefix}--tree-node__icon`
364
- }), label)), /*#__PURE__*/React.createElement("ul", {
461
+ }), renderLabelText())), /*#__PURE__*/React.createElement("ul", {
365
462
  id: `${id}-subtree`,
366
463
  role: "group",
367
464
  className: cx(`${prefix}--tree-node__children`, {
@@ -444,7 +541,17 @@ TreeNode.propTypes = {
444
541
  /**
445
542
  * Optional: The URL the TreeNode is linking to
446
543
  */
447
- href: PropTypes.string
544
+ href: PropTypes.string,
545
+ /**
546
+ * Specify how the tooltip should align when text is truncated
547
+ */
548
+ align: PropTypes.oneOf(['top', 'bottom', 'left', 'right', 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']),
549
+ /**
550
+ * **Experimental**: Will attempt to automatically align the floating
551
+ * element to avoid collisions with the viewport and being clipped by
552
+ * ancestor elements.
553
+ */
554
+ autoAlign: PropTypes.bool
448
555
  };
449
556
  TreeNode.displayName = 'TreeNode';
450
557
 
@@ -13,7 +13,7 @@ import { ArrowUp, ArrowDown, Home, End } from '../../internal/keyboard/keys.js';
13
13
  import { matches, match } from '../../internal/keyboard/match.js';
14
14
  import { useControllableState } from '../../internal/useControllableState.js';
15
15
  import { usePrefix } from '../../internal/usePrefix.js';
16
- import { uniqueId } from '../../tools/uniqueId.js';
16
+ import { useId } from '../../internal/useId.js';
17
17
  import { useFeatureFlag } from '../FeatureFlags/index.js';
18
18
  import TreeNode from './TreeNode.js';
19
19
 
@@ -33,7 +33,7 @@ const TreeView = ({
33
33
  const enableTreeviewControllable = useFeatureFlag('enable-treeview-controllable');
34
34
  const {
35
35
  current: treeId
36
- } = useRef(rest.id || uniqueId());
36
+ } = useRef(rest.id || useId());
37
37
  const prefix = usePrefix();
38
38
  const treeClasses = cx(className, `${prefix}--tree`, {
39
39
  // @ts-ignore - will always be false according to prop types
@@ -112,7 +112,7 @@ const TreeView = ({
112
112
  function enhanceTreeNodes(children) {
113
113
  return React.Children.map(children, child => {
114
114
  if (! /*#__PURE__*/React.isValidElement(child)) return child;
115
- const isTreeNode = child.type.displayName === 'TreeNode';
115
+ const isTreeNode = child.type === TreeNode;
116
116
  if (isTreeNode) {
117
117
  const node = child;
118
118
  const sharedNodeProps = {
@@ -75,6 +75,8 @@ declare const Content: {
75
75
  inert?: boolean | undefined;
76
76
  inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined;
77
77
  is?: string | undefined;
78
+ exportparts?: string | undefined;
79
+ part?: string | undefined;
78
80
  "aria-activedescendant"?: string | undefined;
79
81
  "aria-atomic"?: (boolean | "true" | "false") | undefined;
80
82
  "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined;
@@ -149,7 +151,7 @@ declare const Content: {
149
151
  onBlurCapture?: React.FocusEventHandler<HTMLElement> | undefined;
150
152
  onChange?: React.FormEventHandler<HTMLElement> | undefined;
151
153
  onChangeCapture?: React.FormEventHandler<HTMLElement> | undefined;
152
- onBeforeInput?: React.FormEventHandler<HTMLElement> | undefined;
154
+ onBeforeInput?: React.InputEventHandler<HTMLElement> | undefined;
153
155
  onBeforeInputCapture?: React.FormEventHandler<HTMLElement> | undefined;
154
156
  onInput?: React.FormEventHandler<HTMLElement> | undefined;
155
157
  onInputCapture?: React.FormEventHandler<HTMLElement> | undefined;
@@ -199,8 +201,6 @@ declare const Content: {
199
201
  onProgressCapture?: React.ReactEventHandler<HTMLElement> | undefined;
200
202
  onRateChange?: React.ReactEventHandler<HTMLElement> | undefined;
201
203
  onRateChangeCapture?: React.ReactEventHandler<HTMLElement> | undefined;
202
- onResize?: React.ReactEventHandler<HTMLElement> | undefined;
203
- onResizeCapture?: React.ReactEventHandler<HTMLElement> | undefined;
204
204
  onSeeked?: React.ReactEventHandler<HTMLElement> | undefined;
205
205
  onSeekedCapture?: React.ReactEventHandler<HTMLElement> | undefined;
206
206
  onSeeking?: React.ReactEventHandler<HTMLElement> | undefined;
@@ -281,6 +281,8 @@ declare const Content: {
281
281
  onLostPointerCaptureCapture?: React.PointerEventHandler<HTMLElement> | undefined;
282
282
  onScroll?: React.UIEventHandler<HTMLElement> | undefined;
283
283
  onScrollCapture?: React.UIEventHandler<HTMLElement> | undefined;
284
+ onScrollEnd?: React.UIEventHandler<HTMLElement> | undefined;
285
+ onScrollEndCapture?: React.UIEventHandler<HTMLElement> | undefined;
284
286
  onWheel?: React.WheelEventHandler<HTMLElement> | undefined;
285
287
  onWheelCapture?: React.WheelEventHandler<HTMLElement> | undefined;
286
288
  onAnimationStart?: React.AnimationEventHandler<HTMLElement> | undefined;
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Copyright IBM Corp. 2016, 2023
2
+ * Copyright IBM Corp. 2016, 2025
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
6
  */
7
- import React, { ReactNode } from 'react';
7
+ import React, { type ReactNode } from 'react';
8
8
  export interface HeaderPanelProps {
9
9
  /**
10
10
  * Specify whether focus and blur listeners are added. They are by default.