@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
@@ -17,9 +17,12 @@ var deprecate = require('../../prop-types/deprecate.js');
17
17
  var util = require('./util.js');
18
18
  require('../FluidForm/FluidForm.js');
19
19
  var FormContext = require('../FluidForm/FormContext.js');
20
+ var useMergedRefs = require('../../internal/useMergedRefs.js');
20
21
  var usePrefix = require('../../internal/usePrefix.js');
21
22
  var getAnnouncement = require('../../internal/getAnnouncement.js');
22
23
  require('../Text/index.js');
24
+ var index = require('../AILabel/index.js');
25
+ var utils = require('../../internal/utils.js');
23
26
  var Text = require('../Text/Text.js');
24
27
 
25
28
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -58,7 +61,16 @@ const TextInput = /*#__PURE__*/React__default["default"].forwardRef(function Tex
58
61
  defaultValue,
59
62
  value
60
63
  } = rest;
61
- const [textCount, setTextCount] = React.useState(defaultValue?.toString().length || value?.toString().length || 0);
64
+ const inputRef = React.useRef(null);
65
+ const mergedRef = useMergedRefs.useMergedRefs([ref, inputRef]);
66
+ function getInitialTextCount() {
67
+ const targetValue = defaultValue || value || inputRef.current?.value || '';
68
+ return targetValue.toString().length;
69
+ }
70
+ const [textCount, setTextCount] = React.useState(getInitialTextCount());
71
+ React.useEffect(() => {
72
+ setTextCount(getInitialTextCount());
73
+ }, [value, defaultValue, enableCounter]);
62
74
  const normalizedProps = useNormalizedInputProps.useNormalizedInputProps({
63
75
  id,
64
76
  readOnly,
@@ -91,7 +103,7 @@ const TextInput = /*#__PURE__*/React__default["default"].forwardRef(function Tex
91
103
  },
92
104
  placeholder,
93
105
  type,
94
- ref,
106
+ ref: mergedRef,
95
107
  className: textInputClasses,
96
108
  title: placeholder,
97
109
  disabled: normalizedProps.disabled,
@@ -189,12 +201,11 @@ const TextInput = /*#__PURE__*/React__default["default"].forwardRef(function Tex
189
201
  const Icon = normalizedProps.icon;
190
202
 
191
203
  // AILabel is always size `mini`
192
- let normalizedDecorator = /*#__PURE__*/React__default["default"].isValidElement(slug ?? decorator) ? slug ?? decorator : null;
193
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
194
- normalizedDecorator = /*#__PURE__*/React__default["default"].cloneElement(normalizedDecorator, {
195
- size: 'mini'
196
- });
197
- }
204
+ const candidate = slug ?? decorator;
205
+ const candidateIsAILabel = utils.isComponentElement(candidate, index.AILabel);
206
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
207
+ size: 'mini'
208
+ }) : null;
198
209
  return /*#__PURE__*/React__default["default"].createElement("div", {
199
210
  className: inputWrapperClasses
200
211
  }, !inline ? labelWrapper : /*#__PURE__*/React__default["default"].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
  */
@@ -26,6 +26,8 @@ var useMergedRefs = require('../../internal/useMergedRefs.js');
26
26
  var index = require('../FeatureFlags/index.js');
27
27
  var useId = require('../../internal/useId.js');
28
28
  require('../Text/index.js');
29
+ var index$1 = require('../AILabel/index.js');
30
+ var utils = require('../../internal/utils.js');
29
31
  var Text = require('../Text/Text.js');
30
32
 
31
33
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -234,7 +236,11 @@ const SelectableTile = /*#__PURE__*/React__default["default"].forwardRef(functio
234
236
  const clickHandler = onClick;
235
237
  const keyDownHandler = onKeyDown;
236
238
  const [isSelected, setIsSelected] = React.useState(selected);
237
- const [prevSelected, setPrevSelected] = React.useState(selected);
239
+
240
+ // Use useEffect to sync with prop changes instead of render-time logic
241
+ React.useEffect(() => {
242
+ setIsSelected(selected);
243
+ }, [selected]);
238
244
  const classes = cx__default["default"](`${prefix}--tile`, `${prefix}--tile--selectable`, {
239
245
  [`${prefix}--tile--is-selected`]: isSelected,
240
246
  [`${prefix}--tile--light`]: light,
@@ -244,50 +250,40 @@ const SelectableTile = /*#__PURE__*/React__default["default"].forwardRef(functio
244
250
  [`${prefix}--tile--decorator`]: decorator,
245
251
  [`${prefix}--tile--decorator-rounded`]: decorator && hasRoundedCorners
246
252
  }, className);
253
+
254
+ // Single function to handle selection changes
255
+ const handleSelectionChange = React.useCallback((evt, newSelected) => {
256
+ setIsSelected(newSelected);
257
+ onChange(evt, newSelected, id);
258
+ }, [onChange, id]);
247
259
  function handleClick(evt) {
248
260
  evt.preventDefault();
249
261
  evt?.persist?.();
250
- if (normalizedDecorator && decoratorRef.current && decoratorRef.current.contains(evt.target)) {
262
+ if (normalizedDecorator && decoratorRef.current && evt.target instanceof Node && decoratorRef.current.contains(evt.target)) {
251
263
  return;
252
264
  }
253
- setIsSelected(prevSelected => {
254
- const newSelected = !prevSelected;
255
- onChange(evt, newSelected, id);
256
- return newSelected;
257
- });
265
+ const newSelected = !isSelected;
266
+ handleSelectionChange(evt, newSelected);
258
267
  clickHandler(evt);
259
268
  }
260
269
  function handleKeyDown(evt) {
261
270
  evt?.persist?.();
262
271
  if (match.matches(evt, [keys.Enter, keys.Space])) {
263
272
  evt.preventDefault();
264
- setIsSelected(prevSelected => {
265
- const newSelected = !prevSelected;
266
- onChange(evt, newSelected, id);
267
- return newSelected;
268
- });
273
+ const newSelected = !isSelected;
274
+ handleSelectionChange(evt, newSelected);
269
275
  }
270
276
  keyDownHandler(evt);
271
277
  }
272
- function handleChange(event) {
273
- const newSelected = event.target.checked;
274
- setIsSelected(newSelected);
275
- onChange(event, newSelected, id);
276
- }
277
- if (selected !== prevSelected) {
278
- setIsSelected(selected);
279
- setPrevSelected(selected);
280
- }
281
278
 
282
279
  // AILabel is always size `xs`
283
280
  const decoratorRef = React.useRef(null);
284
- let normalizedDecorator = /*#__PURE__*/React__default["default"].isValidElement(slug ?? decorator) ? slug ?? decorator : null;
285
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
286
- normalizedDecorator = /*#__PURE__*/React__default["default"].cloneElement(normalizedDecorator, {
287
- size: 'xs',
288
- ref: decoratorRef
289
- });
290
- }
281
+ const candidate = slug ?? decorator;
282
+ const candidateIsAILabel = utils.isComponentElement(candidate, index$1.AILabel);
283
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
284
+ size: 'xs',
285
+ ref: decoratorRef
286
+ }) : null;
291
287
  return (
292
288
  /*#__PURE__*/
293
289
  // eslint-disable-next-line jsx-a11y/interactive-supports-focus
@@ -302,7 +298,6 @@ const SelectableTile = /*#__PURE__*/React__default["default"].forwardRef(functio
302
298
  tabIndex: !disabled ? tabIndex : undefined,
303
299
  ref: ref,
304
300
  id: id,
305
- onChange: !disabled ? handleChange : undefined,
306
301
  title: title
307
302
  }, rest), /*#__PURE__*/React__default["default"].createElement("span", {
308
303
  className: `${prefix}--tile__checkmark ${prefix}--tile__checkmark--persistent`
@@ -515,12 +510,11 @@ const ExpandableTile = /*#__PURE__*/React__default["default"].forwardRef(functio
515
510
  const belowTheFoldId = useId.useId('expandable-tile-interactive');
516
511
 
517
512
  // AILabel is always size `xs`
518
- let normalizedDecorator = /*#__PURE__*/React__default["default"].isValidElement(slug ?? decorator) ? slug ?? decorator : null;
519
- if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
520
- normalizedDecorator = /*#__PURE__*/React__default["default"].cloneElement(normalizedDecorator, {
521
- size: 'xs'
522
- });
523
- }
513
+ const candidate = slug ?? decorator;
514
+ const candidateIsAILabel = utils.isComponentElement(candidate, index$1.AILabel);
515
+ const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
516
+ size: 'xs'
517
+ }) : null;
524
518
  return interactive ? /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({
525
519
  ref: ref,
526
520
  className: interactiveClassNames
@@ -98,6 +98,7 @@ function Toggletip({
98
98
  buttonProps: {
99
99
  'aria-expanded': open,
100
100
  'aria-controls': id,
101
+ 'aria-describedby': open ? id : undefined,
101
102
  onClick: actions.toggle
102
103
  },
103
104
  contentProps: {
@@ -269,8 +270,7 @@ const ToggletipContent = /*#__PURE__*/React__default["default"].forwardRef(funct
269
270
  return /*#__PURE__*/React__default["default"].createElement(index.PopoverContent, _rollupPluginBabelHelpers["extends"]({
270
271
  className: customClassName
271
272
  }, toggletip?.contentProps, {
272
- ref: ref,
273
- "aria-live": "polite"
273
+ ref: ref
274
274
  }), /*#__PURE__*/React__default["default"].createElement("div", {
275
275
  className: `${prefix}--toggletip-content`
276
276
  }, children));
@@ -67,6 +67,7 @@ const DefinitionTooltip = ({
67
67
  }, /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({}, rest, {
68
68
  className: cx__default["default"](`${prefix}--definition-term`, triggerClassName),
69
69
  "aria-controls": tooltipId,
70
+ "aria-describedby": tooltipId,
70
71
  "aria-expanded": isOpen,
71
72
  onBlur: () => {
72
73
  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
  */
@@ -65,7 +65,7 @@ const Tooltip = /*#__PURE__*/React__default["default"].forwardRef(({
65
65
 
66
66
  // An `aria-label` takes precedence over `aria-describedby`, but when it's
67
67
  // needed and the user doesn't specify one, the fallback `id` is used.
68
- const labelledBy = hasAriaLabel ? null : hasLabel ? ariaLabelledBy ?? id : undefined;
68
+ const labelledBy = hasAriaLabel ? undefined : hasLabel ? ariaLabelledBy ?? id : undefined;
69
69
 
70
70
  // If `aria-label` is present, use any provided `aria-describedby`.
71
71
  // If not, fallback to child's `aria-describedby` or the tooltip `id` if needed.
@@ -185,7 +185,7 @@ const Tooltip = /*#__PURE__*/React__default["default"].forwardRef(({
185
185
  open: open
186
186
  }), /*#__PURE__*/React__default["default"].createElement("div", {
187
187
  className: `${prefix}--tooltip-trigger__wrapper`
188
- }, child !== undefined ? /*#__PURE__*/React__default["default"].cloneElement(child, {
188
+ }, typeof child !== 'undefined' ? /*#__PURE__*/React__default["default"].cloneElement(child, {
189
189
  ...triggerProps,
190
190
  ...getChildEventHandlers(child.props)
191
191
  }) : null), /*#__PURE__*/React__default["default"].createElement(index.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;
@@ -18,8 +18,9 @@ var keys = require('../../internal/keyboard/keys.js');
18
18
  var match = require('../../internal/keyboard/match.js');
19
19
  var useControllableState = require('../../internal/useControllableState.js');
20
20
  var usePrefix = require('../../internal/usePrefix.js');
21
- var uniqueId = require('../../tools/uniqueId.js');
21
+ var useId = require('../../internal/useId.js');
22
22
  var index = require('../FeatureFlags/index.js');
23
+ var index$1 = require('../IconButton/index.js');
23
24
 
24
25
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
25
26
 
@@ -27,6 +28,74 @@ var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
27
28
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
28
29
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
29
30
 
31
+ const extractTextContent = node => {
32
+ if (node === null || node === undefined) return '';
33
+ if (typeof node === 'string') return node;
34
+ if (typeof node === 'number') return String(node);
35
+ if (typeof node === 'boolean') return String(node);
36
+ if (Array.isArray(node)) {
37
+ return node.map(extractTextContent).join('');
38
+ }
39
+ if (/*#__PURE__*/React__default["default"].isValidElement(node)) {
40
+ const element = node;
41
+ const children = element.props.children;
42
+ return extractTextContent(children);
43
+ }
44
+ return '';
45
+ };
46
+ const useEllipsisCheck = (label, detailsWrapperRef) => {
47
+ const [isEllipsisApplied, setIsEllipsisApplied] = React.useState(false);
48
+ const labelTextRef = React.useRef(null);
49
+ const checkEllipsis = React.useCallback(() => {
50
+ const element = labelTextRef.current;
51
+ if (!element) {
52
+ setIsEllipsisApplied(false);
53
+ return;
54
+ }
55
+ if (element.offsetWidth === 0) {
56
+ setIsEllipsisApplied(false);
57
+ return;
58
+ }
59
+ const checkElement = detailsWrapperRef.current || element;
60
+ if (checkElement && checkElement.offsetWidth > 0) {
61
+ const isTextTruncated = element.scrollWidth > checkElement.offsetWidth;
62
+ setIsEllipsisApplied(isTextTruncated);
63
+ } else {
64
+ setIsEllipsisApplied(false);
65
+ }
66
+ }, [detailsWrapperRef]);
67
+ React.useEffect(() => {
68
+ let animationFrameId;
69
+ animationFrameId = requestAnimationFrame(checkEllipsis);
70
+ let resizeObserver;
71
+ if (typeof window !== 'undefined' && typeof window.ResizeObserver !== 'undefined' && labelTextRef.current) {
72
+ resizeObserver = new window.ResizeObserver(() => {
73
+ requestAnimationFrame(checkEllipsis);
74
+ });
75
+ resizeObserver.observe(labelTextRef.current);
76
+ if (detailsWrapperRef.current) {
77
+ resizeObserver.observe(detailsWrapperRef.current);
78
+ }
79
+ }
80
+ return () => {
81
+ cancelAnimationFrame(animationFrameId);
82
+ if (resizeObserver) {
83
+ if (labelTextRef.current) {
84
+ resizeObserver.unobserve(labelTextRef.current);
85
+ }
86
+ if (detailsWrapperRef.current) {
87
+ resizeObserver.unobserve(detailsWrapperRef.current);
88
+ }
89
+ resizeObserver.disconnect();
90
+ }
91
+ };
92
+ }, [checkEllipsis, detailsWrapperRef]);
93
+ return {
94
+ labelTextRef,
95
+ isEllipsisApplied,
96
+ tooltipText: extractTextContent(label)
97
+ };
98
+ };
30
99
  const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
31
100
  active,
32
101
  children,
@@ -45,15 +114,22 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
45
114
  selected: propSelected,
46
115
  value,
47
116
  href,
117
+ align = 'bottom',
118
+ autoAlign = false,
48
119
  ...rest
49
120
  }, forwardedRef) => {
50
- // These are provided by the parent TreeView component
51
121
  const depth = propDepth;
52
122
  const selected = propSelected;
123
+ const detailsWrapperRef = React.useRef(null);
124
+ const {
125
+ labelTextRef,
126
+ isEllipsisApplied,
127
+ tooltipText
128
+ } = useEllipsisCheck(label, detailsWrapperRef);
53
129
  const enableTreeviewControllable = index.useFeatureFlag('enable-treeview-controllable');
54
130
  const {
55
131
  current: id
56
- } = React.useRef(nodeId || uniqueId.uniqueId());
132
+ } = React.useRef(nodeId || useId.useId());
57
133
  const controllableExpandedState = useControllableState.useControllableState({
58
134
  value: isExpanded,
59
135
  onChange: newValue => {
@@ -71,6 +147,25 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
71
147
  const currentNode = React.useRef(null);
72
148
  const currentNodeLabel = React.useRef(null);
73
149
  const prefix = usePrefix.usePrefix();
150
+ const renderLabelText = () => {
151
+ if (isEllipsisApplied && tooltipText) {
152
+ return /*#__PURE__*/React__default["default"].createElement(index$1.IconButton, {
153
+ label: tooltipText,
154
+ kind: "ghost",
155
+ align: align,
156
+ autoAlign: autoAlign,
157
+ className: `${prefix}--tree-node__label__text-button`,
158
+ wrapperClasses: `${prefix}--popover-container`
159
+ }, /*#__PURE__*/React__default["default"].createElement("span", {
160
+ ref: labelTextRef,
161
+ className: `${prefix}--tree-node__label__text`
162
+ }, label));
163
+ }
164
+ return /*#__PURE__*/React__default["default"].createElement("span", {
165
+ ref: labelTextRef,
166
+ className: `${prefix}--tree-node__label__text`
167
+ }, label);
168
+ };
74
169
  const setRefs = element => {
75
170
  currentNode.current = element;
76
171
  if (typeof forwardedRef === 'function') {
@@ -82,7 +177,7 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
82
177
  function enhanceTreeNodes(children) {
83
178
  return React__default["default"].Children.map(children, node => {
84
179
  if (! /*#__PURE__*/React__default["default"].isValidElement(node)) return node;
85
- const isTreeNode = node.type.displayName === 'TreeNode';
180
+ const isTreeNode = node.type === TreeNode;
86
181
  if (isTreeNode) {
87
182
  return /*#__PURE__*/React__default["default"].cloneElement(node, {
88
183
  active,
@@ -310,7 +405,7 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
310
405
  ref: currentNodeLabel
311
406
  }, Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
312
407
  className: `${prefix}--tree-node__icon`
313
- }), label)));
408
+ }), renderLabelText())));
314
409
  } else {
315
410
  return /*#__PURE__*/React__default["default"].createElement("li", _rollupPluginBabelHelpers["extends"]({}, treeNodeProps, {
316
411
  ref: setRefs
@@ -319,7 +414,7 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
319
414
  ref: currentNodeLabel
320
415
  }, Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
321
416
  className: `${prefix}--tree-node__icon`
322
- }), label));
417
+ }), renderLabelText()));
323
418
  }
324
419
  }
325
420
  if (href) {
@@ -342,10 +437,11 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
342
437
  }, /*#__PURE__*/React__default["default"].createElement(iconsReact.CaretDown, {
343
438
  className: toggleClasses
344
439
  })), /*#__PURE__*/React__default["default"].createElement("span", {
345
- className: `${prefix}--tree-node__label__details`
440
+ className: `${prefix}--tree-node__label__details`,
441
+ ref: detailsWrapperRef
346
442
  }, Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
347
443
  className: `${prefix}--tree-node__icon`
348
- }), label))), /*#__PURE__*/React__default["default"].createElement("ul", {
444
+ }), renderLabelText()))), /*#__PURE__*/React__default["default"].createElement("ul", {
349
445
  id: `${id}-subtree`,
350
446
  role: "group",
351
447
  className: cx__default["default"](`${prefix}--tree-node__children`, {
@@ -368,10 +464,11 @@ const TreeNode = /*#__PURE__*/React__default["default"].forwardRef(({
368
464
  }, /*#__PURE__*/React__default["default"].createElement(iconsReact.CaretDown, {
369
465
  className: toggleClasses
370
466
  })), /*#__PURE__*/React__default["default"].createElement("span", {
371
- className: `${prefix}--tree-node__label__details`
467
+ className: `${prefix}--tree-node__label__details`,
468
+ ref: detailsWrapperRef
372
469
  }, Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
373
470
  className: `${prefix}--tree-node__icon`
374
- }), label)), /*#__PURE__*/React__default["default"].createElement("ul", {
471
+ }), renderLabelText())), /*#__PURE__*/React__default["default"].createElement("ul", {
375
472
  id: `${id}-subtree`,
376
473
  role: "group",
377
474
  className: cx__default["default"](`${prefix}--tree-node__children`, {
@@ -454,7 +551,17 @@ TreeNode.propTypes = {
454
551
  /**
455
552
  * Optional: The URL the TreeNode is linking to
456
553
  */
457
- href: PropTypes__default["default"].string
554
+ href: PropTypes__default["default"].string,
555
+ /**
556
+ * Specify how the tooltip should align when text is truncated
557
+ */
558
+ align: PropTypes__default["default"].oneOf(['top', 'bottom', 'left', 'right', 'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']),
559
+ /**
560
+ * **Experimental**: Will attempt to automatically align the floating
561
+ * element to avoid collisions with the viewport and being clipped by
562
+ * ancestor elements.
563
+ */
564
+ autoAlign: PropTypes__default["default"].bool
458
565
  };
459
566
  TreeNode.displayName = 'TreeNode';
460
567
 
@@ -17,7 +17,7 @@ var keys = require('../../internal/keyboard/keys.js');
17
17
  var match = require('../../internal/keyboard/match.js');
18
18
  var useControllableState = require('../../internal/useControllableState.js');
19
19
  var usePrefix = require('../../internal/usePrefix.js');
20
- var uniqueId = require('../../tools/uniqueId.js');
20
+ var useId = require('../../internal/useId.js');
21
21
  var index = require('../FeatureFlags/index.js');
22
22
  var TreeNode = require('./TreeNode.js');
23
23
 
@@ -43,7 +43,7 @@ const TreeView = ({
43
43
  const enableTreeviewControllable = index.useFeatureFlag('enable-treeview-controllable');
44
44
  const {
45
45
  current: treeId
46
- } = React.useRef(rest.id || uniqueId.uniqueId());
46
+ } = React.useRef(rest.id || useId.useId());
47
47
  const prefix = usePrefix.usePrefix();
48
48
  const treeClasses = cx__default["default"](className, `${prefix}--tree`, {
49
49
  // @ts-ignore - will always be false according to prop types
@@ -122,7 +122,7 @@ const TreeView = ({
122
122
  function enhanceTreeNodes(children) {
123
123
  return React__default["default"].Children.map(children, child => {
124
124
  if (! /*#__PURE__*/React__default["default"].isValidElement(child)) return child;
125
- const isTreeNode = child.type.displayName === 'TreeNode';
125
+ const isTreeNode = child.type === TreeNode["default"];
126
126
  if (isTreeNode) {
127
127
  const node = child;
128
128
  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.
@@ -18,6 +18,7 @@ var keys = require('../../internal/keyboard/keys.js');
18
18
  var match = require('../../internal/keyboard/match.js');
19
19
  var useEvent = require('../../internal/useEvent.js');
20
20
  var useMergedRefs = require('../../internal/useMergedRefs.js');
21
+ var Switcher = require('./Switcher.js');
21
22
 
22
23
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
23
24
 
@@ -68,10 +69,13 @@ const HeaderPanel = /*#__PURE__*/React__default["default"].forwardRef(function H
68
69
  };
69
70
  }
70
71
  useEvent.useWindowEvent('click', () => {
71
- const focusedElement = document.activeElement;
72
- setLastClickedElement(focusedElement);
73
- const childJsxElement = children;
74
- if (childJsxElement?.type?.displayName === 'Switcher' && !focusedElement?.closest(`.${prefix}--header-panel--expanded`) && !focusedElement?.closest(`.${prefix}--header__action`) && !headerPanelReference?.current?.classList.contains(`${prefix}--switcher`) && expanded) {
72
+ const {
73
+ activeElement
74
+ } = document;
75
+ if (!(activeElement instanceof HTMLElement)) return;
76
+ setLastClickedElement(activeElement);
77
+ const isChildASwitcher = /*#__PURE__*/React.isValidElement(children) && typeof children.type !== 'string' && children.type === Switcher["default"];
78
+ if (isChildASwitcher && !activeElement.closest(`.${prefix}--header-panel--expanded`) && !activeElement.closest(`.${prefix}--header__action`) && !headerPanelReference?.current?.classList.contains(`${prefix}--switcher`) && expanded) {
75
79
  setExpandedState(false);
76
80
  onHeaderPanelFocus();
77
81
  }
@@ -25,9 +25,14 @@ const callOnChangeHandler = ({
25
25
  }) => {
26
26
  if (isControlled) {
27
27
  if (isMounted && onChangeHandlerControlled) {
28
- onChangeHandlerControlled({
29
- selectedItems
30
- });
28
+ // Use setTimeout to defer the controlled onChange call,
29
+ // avoiding React’s warning: "Cannot update a component while rendering a different component".
30
+ // This ensures the parent state updates after rendering completes.
31
+ setTimeout(() => {
32
+ onChangeHandlerControlled({
33
+ selectedItems
34
+ });
35
+ }, 0);
31
36
  }
32
37
  } else {
33
38
  onChangeHandlerUncontrolled(selectedItems);
@@ -14,17 +14,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
14
14
  *
15
15
  * @see https://github.com/facebook/fbjs/blob/4d1751311d3f67af2dcce2e40df8512a23c7b9c6/packages/fbjs/src/core/ExecutionEnvironment.js#L12
16
16
  */
17
- const canUseDOM = !!(typeof window !== 'undefined' &&
18
- // TODO: `ssr-friendly` doesn't support ESLint v9.
19
- // https://github.com/kopiro/eslint-plugin-ssr-friendly/issues/30
20
- // https://github.com/carbon-design-system/carbon/issues/18991
21
- /*
22
- // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
23
- */
24
- window.document &&
25
- /*
26
- // eslint-disable-next-line ssr-friendly/no-dom-globals-in-module-scope
27
- */
28
- window.document.createElement);
17
+ const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
29
18
 
30
19
  exports.canUseDOM = canUseDOM;