@carbon/react 1.85.1 → 1.86.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 (189) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +842 -842
  2. package/es/components/AILabel/index.js +1 -1
  3. package/es/components/Accordion/AccordionItem.d.ts +1 -1
  4. package/es/components/Accordion/AccordionItem.js +1 -1
  5. package/es/components/Checkbox/Checkbox.js +1 -1
  6. package/es/components/CheckboxGroup/CheckboxGroup.js +1 -1
  7. package/es/components/CodeSnippet/CodeSnippet.d.ts +2 -2
  8. package/es/components/CodeSnippet/CodeSnippet.js +1 -1
  9. package/es/components/ComboBox/ComboBox.js +1 -1
  10. package/es/components/ComposedModal/ComposedModal.js +1 -1
  11. package/es/components/ContentSwitcher/ContentSwitcher.d.ts +1 -1
  12. package/es/components/ContentSwitcher/ContentSwitcher.js +1 -1
  13. package/es/components/DataTable/DataTable.d.ts +230 -170
  14. package/es/components/DataTable/DataTable.js +508 -519
  15. package/es/components/DataTable/TableContainer.d.ts +9 -1
  16. package/es/components/DataTable/TableContainer.js +7 -1
  17. package/es/components/DataTable/TableExpandHeader.d.ts +1 -1
  18. package/es/components/DataTable/TableExpandHeader.js +1 -1
  19. package/es/components/DataTable/TableSelectAll.d.ts +2 -2
  20. package/es/components/DataTable/TableSelectAll.js +1 -1
  21. package/es/components/DataTable/TableSelectRow.d.ts +2 -2
  22. package/es/components/DataTable/TableSelectRow.js +1 -1
  23. package/es/components/DataTable/TableToolbar.d.ts +1 -1
  24. package/es/components/DataTable/TableToolbar.js +1 -1
  25. package/es/components/DataTable/TableToolbarMenu.d.ts +2 -18
  26. package/es/components/DataTable/TableToolbarMenu.js +0 -1
  27. package/es/components/DataTable/index.d.ts +1 -1
  28. package/es/components/DataTable/state/getDerivedStateFromProps.js +5 -1
  29. package/es/components/DatePicker/DatePicker.js +1 -1
  30. package/es/components/DatePickerInput/DatePickerInput.js +1 -1
  31. package/es/components/Dropdown/Dropdown.js +1 -1
  32. package/es/components/FeatureFlags/index.d.ts +2 -2
  33. package/es/components/FeatureFlags/index.js +1 -1
  34. package/es/components/FileUploader/FileUploaderButton.d.ts +1 -1
  35. package/es/components/FileUploader/FileUploaderButton.js +1 -1
  36. package/es/components/FileUploader/FileUploaderDropContainer.d.ts +2 -2
  37. package/es/components/FileUploader/FileUploaderDropContainer.js +1 -1
  38. package/es/components/FluidTextArea/FluidTextArea.d.ts +1 -1
  39. package/es/components/FluidTextArea/FluidTextArea.js +1 -1
  40. package/es/components/InlineCheckbox/InlineCheckbox.js +1 -1
  41. package/es/components/ListBox/ListBox.js +1 -1
  42. package/es/components/Loading/Loading.d.ts +1 -1
  43. package/es/components/Loading/Loading.js +1 -1
  44. package/es/components/Menu/Menu.js +1 -1
  45. package/es/components/Modal/Modal.js +1 -1
  46. package/es/components/MultiSelect/FilterableMultiSelect.js +2 -2
  47. package/es/components/MultiSelect/MultiSelect.js +1 -1
  48. package/es/components/Notification/Notification.d.ts +4 -4
  49. package/es/components/Notification/Notification.js +1 -1
  50. package/es/components/NumberInput/NumberInput.d.ts +7 -0
  51. package/es/components/NumberInput/NumberInput.js +80 -25
  52. package/es/components/OverflowMenu/OverflowMenu.d.ts +2 -6
  53. package/es/components/OverflowMenu/OverflowMenu.js +1 -1
  54. package/es/components/Pagination/Pagination.js +22 -5
  55. package/es/components/RadioButton/RadioButton.js +1 -1
  56. package/es/components/RadioButtonGroup/RadioButtonGroup.js +1 -1
  57. package/es/components/RadioTile/RadioTile.js +1 -1
  58. package/es/components/Search/Search.js +1 -1
  59. package/es/components/Select/Select.js +1 -1
  60. package/es/components/Slider/Slider.js +1 -1
  61. package/es/components/StructuredList/StructuredList.d.ts +5 -5
  62. package/es/components/StructuredList/StructuredList.js +1 -1
  63. package/es/components/Tabs/Tabs.d.ts +1 -1
  64. package/es/components/Tabs/Tabs.js +1 -1
  65. package/es/components/Tag/DismissibleTag.js +1 -1
  66. package/es/components/Tag/Tag.js +1 -1
  67. package/es/components/TextArea/TextArea.js +1 -1
  68. package/es/components/TextInput/ControlledPasswordInput.js +1 -1
  69. package/es/components/TextInput/PasswordInput.js +1 -1
  70. package/es/components/TextInput/TextInput.js +1 -1
  71. package/es/components/Tile/Tile.js +1 -1
  72. package/es/components/TileGroup/TileGroup.d.ts +5 -5
  73. package/es/components/TimePicker/TimePicker.d.ts +8 -0
  74. package/es/components/TimePicker/TimePicker.js +6 -4
  75. package/es/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  76. package/es/components/Tooltip/DefinitionTooltip.js +1 -1
  77. package/es/components/TreeView/TreeContext.d.ts +19 -0
  78. package/es/components/TreeView/TreeContext.js +13 -0
  79. package/es/components/TreeView/TreeNode.d.ts +4 -4
  80. package/es/components/TreeView/TreeNode.js +56 -108
  81. package/es/components/TreeView/TreeView.js +42 -79
  82. package/es/components/UIShell/HeaderMenu.js +1 -1
  83. package/es/components/UIShell/HeaderMenuItem.d.ts +1 -1
  84. package/es/components/UIShell/HeaderMenuItem.js +1 -1
  85. package/es/components/UIShell/HeaderName.d.ts +1 -1
  86. package/es/components/UIShell/Link.d.ts +2 -2
  87. package/es/components/UIShell/Link.js +1 -1
  88. package/es/components/UIShell/Switcher.d.ts +1 -1
  89. package/es/components/UIShell/Switcher.js +39 -12
  90. package/es/index.js +1 -1
  91. package/es/internal/useNoInteractiveChildren.d.ts +25 -0
  92. package/es/internal/useNoInteractiveChildren.js +39 -32
  93. package/es/prop-types/deprecate.d.ts +17 -0
  94. package/es/prop-types/deprecate.js +22 -12
  95. package/lib/components/AILabel/index.js +2 -2
  96. package/lib/components/Accordion/AccordionItem.d.ts +1 -1
  97. package/lib/components/Accordion/AccordionItem.js +1 -1
  98. package/lib/components/Checkbox/Checkbox.js +1 -1
  99. package/lib/components/CheckboxGroup/CheckboxGroup.js +1 -1
  100. package/lib/components/CodeSnippet/CodeSnippet.d.ts +2 -2
  101. package/lib/components/CodeSnippet/CodeSnippet.js +2 -2
  102. package/lib/components/ComboBox/ComboBox.js +3 -3
  103. package/lib/components/ComposedModal/ComposedModal.js +1 -1
  104. package/lib/components/ContentSwitcher/ContentSwitcher.d.ts +1 -1
  105. package/lib/components/ContentSwitcher/ContentSwitcher.js +1 -1
  106. package/lib/components/DataTable/DataTable.d.ts +230 -170
  107. package/lib/components/DataTable/DataTable.js +507 -518
  108. package/lib/components/DataTable/TableContainer.d.ts +9 -1
  109. package/lib/components/DataTable/TableContainer.js +7 -1
  110. package/lib/components/DataTable/TableExpandHeader.d.ts +1 -1
  111. package/lib/components/DataTable/TableExpandHeader.js +1 -1
  112. package/lib/components/DataTable/TableSelectAll.d.ts +2 -2
  113. package/lib/components/DataTable/TableSelectAll.js +1 -1
  114. package/lib/components/DataTable/TableSelectRow.d.ts +2 -2
  115. package/lib/components/DataTable/TableSelectRow.js +1 -1
  116. package/lib/components/DataTable/TableToolbar.d.ts +1 -1
  117. package/lib/components/DataTable/TableToolbar.js +1 -1
  118. package/lib/components/DataTable/TableToolbarMenu.d.ts +2 -18
  119. package/lib/components/DataTable/TableToolbarMenu.js +0 -1
  120. package/lib/components/DataTable/index.d.ts +1 -1
  121. package/lib/components/DataTable/state/getDerivedStateFromProps.js +5 -1
  122. package/lib/components/DatePicker/DatePicker.js +1 -1
  123. package/lib/components/DatePickerInput/DatePickerInput.js +1 -1
  124. package/lib/components/Dropdown/Dropdown.js +3 -3
  125. package/lib/components/FeatureFlags/index.d.ts +2 -2
  126. package/lib/components/FeatureFlags/index.js +1 -1
  127. package/lib/components/FileUploader/FileUploaderButton.d.ts +1 -1
  128. package/lib/components/FileUploader/FileUploaderButton.js +1 -1
  129. package/lib/components/FileUploader/FileUploaderDropContainer.d.ts +2 -2
  130. package/lib/components/FileUploader/FileUploaderDropContainer.js +2 -2
  131. package/lib/components/FluidTextArea/FluidTextArea.d.ts +1 -1
  132. package/lib/components/FluidTextArea/FluidTextArea.js +1 -1
  133. package/lib/components/InlineCheckbox/InlineCheckbox.js +1 -1
  134. package/lib/components/ListBox/ListBox.js +1 -1
  135. package/lib/components/Loading/Loading.d.ts +1 -1
  136. package/lib/components/Loading/Loading.js +1 -1
  137. package/lib/components/Menu/Menu.js +1 -1
  138. package/lib/components/Modal/Modal.js +1 -1
  139. package/lib/components/MultiSelect/FilterableMultiSelect.js +5 -5
  140. package/lib/components/MultiSelect/MultiSelect.js +2 -2
  141. package/lib/components/Notification/Notification.d.ts +4 -4
  142. package/lib/components/Notification/Notification.js +4 -4
  143. package/lib/components/NumberInput/NumberInput.d.ts +7 -0
  144. package/lib/components/NumberInput/NumberInput.js +81 -26
  145. package/lib/components/OverflowMenu/OverflowMenu.d.ts +2 -6
  146. package/lib/components/OverflowMenu/OverflowMenu.js +2 -2
  147. package/lib/components/Pagination/Pagination.js +21 -4
  148. package/lib/components/RadioButton/RadioButton.js +1 -1
  149. package/lib/components/RadioButtonGroup/RadioButtonGroup.js +1 -1
  150. package/lib/components/RadioTile/RadioTile.js +2 -2
  151. package/lib/components/Search/Search.js +1 -1
  152. package/lib/components/Select/Select.js +2 -2
  153. package/lib/components/Slider/Slider.js +1 -1
  154. package/lib/components/StructuredList/StructuredList.d.ts +5 -5
  155. package/lib/components/StructuredList/StructuredList.js +4 -4
  156. package/lib/components/Tabs/Tabs.d.ts +1 -1
  157. package/lib/components/Tabs/Tabs.js +1 -1
  158. package/lib/components/Tag/DismissibleTag.js +1 -1
  159. package/lib/components/Tag/Tag.js +4 -4
  160. package/lib/components/TextArea/TextArea.js +2 -2
  161. package/lib/components/TextInput/ControlledPasswordInput.js +1 -1
  162. package/lib/components/TextInput/PasswordInput.js +1 -1
  163. package/lib/components/TextInput/TextInput.js +2 -2
  164. package/lib/components/Tile/Tile.js +9 -9
  165. package/lib/components/TileGroup/TileGroup.d.ts +5 -5
  166. package/lib/components/TimePicker/TimePicker.d.ts +8 -0
  167. package/lib/components/TimePicker/TimePicker.js +6 -4
  168. package/lib/components/Tooltip/DefinitionTooltip.d.ts +1 -1
  169. package/lib/components/Tooltip/DefinitionTooltip.js +1 -1
  170. package/lib/components/TreeView/TreeContext.d.ts +19 -0
  171. package/lib/components/TreeView/TreeContext.js +18 -0
  172. package/lib/components/TreeView/TreeNode.d.ts +4 -4
  173. package/lib/components/TreeView/TreeNode.js +55 -107
  174. package/lib/components/TreeView/TreeView.js +41 -78
  175. package/lib/components/UIShell/HeaderMenu.js +1 -1
  176. package/lib/components/UIShell/HeaderMenuItem.d.ts +1 -1
  177. package/lib/components/UIShell/HeaderMenuItem.js +1 -1
  178. package/lib/components/UIShell/HeaderName.d.ts +1 -1
  179. package/lib/components/UIShell/Link.d.ts +2 -2
  180. package/lib/components/UIShell/Link.js +1 -1
  181. package/lib/components/UIShell/Switcher.d.ts +1 -1
  182. package/lib/components/UIShell/Switcher.js +38 -11
  183. package/lib/index.js +1 -1
  184. package/lib/internal/useNoInteractiveChildren.d.ts +25 -0
  185. package/lib/internal/useNoInteractiveChildren.js +39 -32
  186. package/lib/prop-types/deprecate.d.ts +17 -0
  187. package/lib/prop-types/deprecate.js +22 -12
  188. package/package.json +3 -3
  189. package/telemetry.yml +15 -14
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2025
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import { type MouseEvent } from 'react';
8
+ import type { TreeNodeProps } from './TreeNode';
9
+ interface TreeContextProps {
10
+ active?: string | number;
11
+ multiselect?: boolean;
12
+ onActivate?: (nodeId?: string | number) => void;
13
+ onTreeSelect?: (event: MouseEvent, node?: Partial<TreeNodeProps>) => void;
14
+ selected?: Array<string | number>;
15
+ size?: 'xs' | 'sm';
16
+ }
17
+ export declare const TreeContext: import("react").Context<TreeContextProps | null>;
18
+ export declare const DepthContext: import("react").Context<number>;
19
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Copyright IBM Corp. 2016, 2023
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import { createContext } from 'react';
9
+
10
+ const TreeContext = /*#__PURE__*/createContext(null);
11
+ const DepthContext = /*#__PURE__*/createContext(-1);
12
+
13
+ export { DepthContext, TreeContext };
@@ -52,11 +52,11 @@ export type TreeNodeProps = {
52
52
  /**
53
53
  * Callback function for when the node is selected
54
54
  */
55
- onSelect?: (event: React.MouseEvent, node?: TreeNodeProps) => void;
55
+ onSelect?: (event: React.MouseEvent, node?: Omit<TreeNodeProps, 'children'>) => void;
56
56
  /**
57
57
  * Callback function for when a parent node is expanded or collapsed
58
58
  */
59
- onToggle?: (event: React.MouseEvent, node?: TreeNodeProps) => void;
59
+ onToggle?: (event: React.MouseEvent | React.KeyboardEvent, node?: Omit<TreeNodeProps, 'children'>) => void;
60
60
  /**
61
61
  * Callback function for when any node in the tree is selected
62
62
  */
@@ -137,11 +137,11 @@ declare const TreeNode: React.ForwardRefExoticComponent<{
137
137
  /**
138
138
  * Callback function for when the node is selected
139
139
  */
140
- onSelect?: (event: React.MouseEvent, node?: TreeNodeProps) => void;
140
+ onSelect?: (event: React.MouseEvent, node?: Omit<TreeNodeProps, "children">) => void;
141
141
  /**
142
142
  * Callback function for when a parent node is expanded or collapsed
143
143
  */
144
- onToggle?: (event: React.MouseEvent, node?: TreeNodeProps) => void;
144
+ onToggle?: (event: React.MouseEvent | React.KeyboardEvent, node?: Omit<TreeNodeProps, "children">) => void;
145
145
  /**
146
146
  * Callback function for when any node in the tree is selected
147
147
  */
@@ -9,7 +9,7 @@ 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, useCallback } from 'react';
12
+ import React, { useContext, 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';
@@ -17,6 +17,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
17
17
  import { useId } from '../../internal/useId.js';
18
18
  import { useFeatureFlag } from '../FeatureFlags/index.js';
19
19
  import { IconButton } from '../IconButton/index.js';
20
+ import { TreeContext, DepthContext } from './TreeContext.js';
20
21
 
21
22
  const extractTextContent = node => {
22
23
  if (node === null || node === undefined) return '';
@@ -87,29 +88,36 @@ const useEllipsisCheck = (label, detailsWrapperRef) => {
87
88
  };
88
89
  };
89
90
  const TreeNode = /*#__PURE__*/React.forwardRef(({
90
- active,
91
91
  children,
92
92
  className,
93
- depth: propDepth,
94
93
  disabled,
95
94
  id: nodeId,
96
95
  isExpanded,
97
96
  defaultIsExpanded,
98
97
  label,
99
- onNodeFocusEvent,
100
98
  onSelect: onNodeSelect,
101
99
  onToggle,
102
- onTreeSelect,
103
100
  renderIcon: Icon,
104
- selected: propSelected,
105
101
  value,
106
102
  href,
107
103
  align = 'bottom',
108
104
  autoAlign = false,
105
+ // These props are fallback props if the TreeContext is not available or only TreeNode is used as a standalone component
106
+ active: propActive,
107
+ depth: propDepth,
108
+ selected: propSelected,
109
+ onTreeSelect: propOnTreeSelect,
110
+ onNodeFocusEvent,
109
111
  ...rest
110
112
  }, forwardedRef) => {
111
- const depth = propDepth;
112
- const selected = propSelected;
113
+ const treeContext = useContext(TreeContext);
114
+ const contextDepth = useContext(DepthContext);
115
+
116
+ // Prioritize direct props, and fall back to context values.
117
+ const depth = propDepth ?? (contextDepth !== -1 ? contextDepth : 0);
118
+ const active = propActive ?? treeContext?.active;
119
+ const selected = propSelected ?? treeContext?.selected ?? [];
120
+ const onTreeSelect = propOnTreeSelect ?? treeContext?.onTreeSelect;
113
121
  const detailsWrapperRef = useRef(null);
114
122
  const {
115
123
  labelTextRef,
@@ -164,30 +172,8 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
164
172
  forwardedRef.current = element;
165
173
  }
166
174
  };
167
- function enhanceTreeNodes(children) {
168
- return React.Children.map(children, node => {
169
- if (! /*#__PURE__*/React.isValidElement(node)) return node;
170
- const isTreeNode = node.type === TreeNode;
171
- if (isTreeNode) {
172
- return /*#__PURE__*/React.cloneElement(node, {
173
- active,
174
- depth: depth + 1,
175
- disabled: disabled || node.props.disabled,
176
- onTreeSelect,
177
- onNodeFocusEvent,
178
- selected,
179
- tabIndex: node.props.disabled ? null : -1
180
- });
181
- }
182
- const newChildren = enhanceTreeNodes(node.props.children);
183
- return /*#__PURE__*/React.cloneElement(node, {
184
- children: newChildren
185
- });
186
- });
187
- }
188
- const nodesWithProps = enhanceTreeNodes(children);
189
175
  const isActive = active === id;
190
- const isSelected = selected.includes(id);
176
+ const isSelected = selected?.includes(id) ?? false;
191
177
  const treeNodeClasses = cx(className, `${prefix}--tree-node`, {
192
178
  [`${prefix}--tree-node--active`]: isActive,
193
179
  [`${prefix}--tree-node--disabled`]: disabled,
@@ -289,7 +275,7 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
289
275
  * When focus is on an expanded parent node, move focus to the first
290
276
  * child node
291
277
  */
292
- getFocusableNode(href ? currentNode.current?.parentElement?.lastChild?.firstChild : currentNode.current?.lastChild?.firstChild).focus();
278
+ getFocusableNode(href ? currentNode.current?.parentElement?.lastChild?.firstChild : currentNode.current?.lastChild?.firstChild)?.focus();
293
279
  } else {
294
280
  if (!enableTreeviewControllable) {
295
281
  onToggle?.(event, {
@@ -324,12 +310,12 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
324
310
  rest?.onKeyDown?.(event);
325
311
  }
326
312
  function handleFocusEvent(event) {
327
- if (event.type === 'blur') {
328
- rest?.onBlur?.(event);
329
- }
330
313
  if (event.type === 'focus') {
331
314
  rest?.onFocus?.(event);
332
315
  }
316
+ if (event.type === 'blur') {
317
+ rest?.onBlur?.(event);
318
+ }
333
319
  onNodeFocusEvent?.(event);
334
320
  }
335
321
  useEffect(() => {
@@ -369,6 +355,7 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
369
355
  setExpanded(isExpanded ?? false);
370
356
  }
371
357
  }, [children, depth, Icon, isExpanded, enableTreeviewControllable, setExpanded]);
358
+ const tabIndex = disabled ? undefined : rest.tabIndex ?? -1;
372
359
  const treeNodeProps = {
373
360
  ...rest,
374
361
  ['aria-current']: !href ? isActive || undefined : isActive ? 'page' : undefined,
@@ -377,95 +364,56 @@ const TreeNode = /*#__PURE__*/React.forwardRef(({
377
364
  ['aria-owns']: children ? `${id}-subtree` : undefined,
378
365
  className: treeNodeClasses,
379
366
  id,
380
- onBlur: handleFocusEvent,
381
367
  onClick: handleClick,
382
- onFocus: handleFocusEvent,
383
368
  onKeyDown: handleKeyDown,
384
- role: 'treeitem'
369
+ role: 'treeitem',
370
+ tabIndex,
371
+ onFocus: handleFocusEvent,
372
+ onBlur: handleFocusEvent
385
373
  };
386
- if (!children) {
387
- if (href) {
388
- return /*#__PURE__*/React.createElement("li", {
389
- role: "none"
390
- }, /*#__PURE__*/React.createElement("a", _extends({}, treeNodeProps, {
391
- ref: setRefs,
392
- href: !disabled ? href : undefined
393
- }), /*#__PURE__*/React.createElement("div", {
394
- className: `${prefix}--tree-node__label`,
395
- ref: currentNodeLabel
396
- }, Icon && /*#__PURE__*/React.createElement(Icon, {
397
- className: `${prefix}--tree-node__icon`
398
- }), renderLabelText())));
399
- } else {
400
- return /*#__PURE__*/React.createElement("li", _extends({}, treeNodeProps, {
401
- ref: setRefs
402
- }), /*#__PURE__*/React.createElement("div", {
403
- className: `${prefix}--tree-node__label`,
404
- ref: currentNodeLabel
405
- }, Icon && /*#__PURE__*/React.createElement(Icon, {
406
- className: `${prefix}--tree-node__icon`
407
- }), renderLabelText()));
408
- }
409
- }
374
+ const nodeContent = /*#__PURE__*/React.createElement("div", {
375
+ className: `${prefix}--tree-node__label`,
376
+ ref: currentNodeLabel
377
+ }, children && /*#__PURE__*/React.createElement("span", {
378
+ className: `${prefix}--tree-parent-node__toggle`,
379
+ onClick: handleToggleClick
380
+ }, /*#__PURE__*/React.createElement(CaretDown, {
381
+ className: toggleClasses
382
+ })), /*#__PURE__*/React.createElement("span", {
383
+ className: `${prefix}--tree-node__label__details`
384
+ }, Icon && /*#__PURE__*/React.createElement(Icon, {
385
+ className: `${prefix}--tree-node__icon`
386
+ }), renderLabelText()));
410
387
  if (href) {
411
388
  return /*#__PURE__*/React.createElement("li", {
412
389
  role: "none",
413
- className: `${prefix}--tree-node-link-parent`
390
+ className: children ? `${prefix}--tree-node-link-parent` : ''
414
391
  }, /*#__PURE__*/React.createElement("a", _extends({}, treeNodeProps, {
415
392
  "aria-expanded": !!expanded,
416
393
  ref: setRefs,
417
394
  href: !disabled ? href : undefined
418
- }), /*#__PURE__*/React.createElement("div", {
419
- className: `${prefix}--tree-node__label`,
420
- ref: currentNodeLabel
421
- }, /*#__PURE__*/React.createElement("span", {
422
- className: `${prefix}--tree-parent-node__toggle`
423
- // @ts-ignore
424
- ,
425
- disabled: disabled,
426
- onClick: handleToggleClick
427
- }, /*#__PURE__*/React.createElement(CaretDown, {
428
- className: toggleClasses
429
- })), /*#__PURE__*/React.createElement("span", {
430
- className: `${prefix}--tree-node__label__details`,
431
- ref: detailsWrapperRef
432
- }, Icon && /*#__PURE__*/React.createElement(Icon, {
433
- className: `${prefix}--tree-node__icon`
434
- }), renderLabelText()))), /*#__PURE__*/React.createElement("ul", {
435
- id: `${id}-subtree`,
436
- role: "group",
437
- className: cx(`${prefix}--tree-node__children`, {
438
- [`${prefix}--tree-node--hidden`]: !expanded
439
- })
440
- }, nodesWithProps));
441
- } else {
442
- return /*#__PURE__*/React.createElement("li", _extends({}, treeNodeProps, {
443
- "aria-expanded": !!expanded,
444
- ref: setRefs
445
- }), /*#__PURE__*/React.createElement("div", {
446
- className: `${prefix}--tree-node__label`,
447
- ref: currentNodeLabel
448
- }, /*#__PURE__*/React.createElement("span", {
449
- className: `${prefix}--tree-parent-node__toggle`
450
- // @ts-ignore
451
- ,
452
- disabled: disabled,
453
- onClick: handleToggleClick
454
- }, /*#__PURE__*/React.createElement(CaretDown, {
455
- className: toggleClasses
456
- })), /*#__PURE__*/React.createElement("span", {
457
- className: `${prefix}--tree-node__label__details`,
458
- ref: detailsWrapperRef
459
- }, Icon && /*#__PURE__*/React.createElement(Icon, {
460
- className: `${prefix}--tree-node__icon`
461
- }), renderLabelText())), /*#__PURE__*/React.createElement("ul", {
395
+ }), nodeContent), children && /*#__PURE__*/React.createElement("ul", {
462
396
  id: `${id}-subtree`,
463
397
  role: "group",
464
398
  className: cx(`${prefix}--tree-node__children`, {
465
399
  [`${prefix}--tree-node--hidden`]: !expanded
466
400
  })
467
- }, nodesWithProps));
401
+ }, /*#__PURE__*/React.createElement(DepthContext.Provider, {
402
+ value: depth + 1
403
+ }, children)));
468
404
  }
405
+ return /*#__PURE__*/React.createElement("li", _extends({}, treeNodeProps, {
406
+ "aria-expanded": children ? !!expanded : undefined,
407
+ ref: setRefs
408
+ }), nodeContent, children && /*#__PURE__*/React.createElement("ul", {
409
+ id: `${id}-subtree`,
410
+ role: "group",
411
+ className: cx(`${prefix}--tree-node__children`, {
412
+ [`${prefix}--tree-node--hidden`]: !expanded
413
+ })
414
+ }, /*#__PURE__*/React.createElement(DepthContext.Provider, {
415
+ value: depth + 1
416
+ }, children)));
469
417
  });
470
418
  TreeNode.propTypes = {
471
419
  /**
@@ -8,7 +8,7 @@
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, useEffect } from 'react';
11
+ import React, { useRef, useState, useEffect, useMemo } from 'react';
12
12
  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';
@@ -16,6 +16,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
16
16
  import { useId } from '../../internal/useId.js';
17
17
  import { useFeatureFlag } from '../FeatureFlags/index.js';
18
18
  import TreeNode from './TreeNode.js';
19
+ import { TreeContext, DepthContext } from './TreeContext.js';
19
20
 
20
21
  const TreeView = ({
21
22
  active: prespecifiedActive,
@@ -37,10 +38,11 @@ const TreeView = ({
37
38
  const prefix = usePrefix();
38
39
  const treeClasses = cx(className, `${prefix}--tree`, {
39
40
  // @ts-ignore - will always be false according to prop types
41
+
40
42
  [`${prefix}--tree--${size}`]: size !== 'default'
41
43
  });
42
44
  const treeRootRef = useRef(null);
43
- const treeWalker = useRef(treeRootRef?.current);
45
+ const treeWalker = useRef(null);
44
46
  const controllableSelectionState = useControllableState({
45
47
  value: preselected,
46
48
  onChange: newSelected => {
@@ -86,56 +88,14 @@ const TreeView = ({
86
88
  }
87
89
  }
88
90
  }
89
- function handleFocusEvent(event) {
90
- if (event.type === 'blur') {
91
- const {
92
- relatedTarget: currentFocusedNode,
93
- target: prevFocusedNode
94
- } = event;
95
- if (treeRootRef?.current?.contains(currentFocusedNode)) {
96
- prevFocusedNode.tabIndex = -1;
97
- }
98
- }
99
- if (event.type === 'focus') {
100
- resetNodeTabIndices();
101
- const {
102
- relatedTarget: prevFocusedNode,
103
- target: currentFocusedNode
104
- } = event;
105
- if (treeRootRef?.current?.contains(prevFocusedNode)) {
106
- prevFocusedNode.tabIndex = -1;
107
- }
108
- currentFocusedNode.tabIndex = 0;
91
+
92
+ // Set the first non-disabled node to be tabbable
93
+ useEffect(() => {
94
+ const firstNode = treeRootRef.current?.querySelector(`.${prefix}--tree-node:not(.${prefix}--tree-node--disabled)`);
95
+ if (firstNode instanceof HTMLElement) {
96
+ firstNode.tabIndex = 0;
109
97
  }
110
- }
111
- let focusTarget = false;
112
- function enhanceTreeNodes(children) {
113
- return React.Children.map(children, child => {
114
- if (! /*#__PURE__*/React.isValidElement(child)) return child;
115
- const isTreeNode = child.type === TreeNode;
116
- if (isTreeNode) {
117
- const node = child;
118
- const sharedNodeProps = {
119
- active,
120
- depth: 0,
121
- onNodeFocusEvent: handleFocusEvent,
122
- onTreeSelect: handleTreeSelect,
123
- selected,
124
- tabIndex: node.props.disabled ? undefined : -1
125
- };
126
- if (!focusTarget && !node.props.disabled) {
127
- sharedNodeProps.tabIndex = 0;
128
- focusTarget = true;
129
- }
130
- return /*#__PURE__*/React.cloneElement(child, sharedNodeProps);
131
- }
132
- const newChildren = enhanceTreeNodes(child.props.children);
133
- return /*#__PURE__*/React.cloneElement(child, {
134
- children: newChildren
135
- });
136
- });
137
- }
138
- const nodesWithProps = enhanceTreeNodes(children);
98
+ }, [children, prefix]);
139
99
  function handleKeyDown(event) {
140
100
  event.stopPropagation();
141
101
  if (matches(event, [ArrowUp, ArrowDown, Home, End])) {
@@ -159,12 +119,12 @@ const TreeView = ({
159
119
  const nodeIds = [];
160
120
  if (matches(event, [Home, End])) {
161
121
  if (multiselect && event.shiftKey && event.ctrlKey && treeWalker.current.currentNode instanceof Element && !treeWalker.current.currentNode.getAttribute('aria-disabled') && !treeWalker.current.currentNode.classList.contains(`${prefix}--tree-node--hidden`)) {
162
- nodeIds.push(treeWalker.current.currentNode?.id);
122
+ nodeIds.push(treeWalker.current.currentNode.id);
163
123
  }
164
124
  while (match(event, Home) ? treeWalker.current.previousNode() : treeWalker.current.nextNode()) {
165
125
  nextFocusNode = treeWalker.current.currentNode;
166
126
  if (multiselect && event.shiftKey && event.ctrlKey && nextFocusNode instanceof Element && !nextFocusNode.getAttribute('aria-disabled') && !nextFocusNode.classList.contains(`${prefix}--tree-node--hidden`)) {
167
- nodeIds.push(nextFocusNode?.id);
127
+ nodeIds.push(nextFocusNode.id);
168
128
  }
169
129
  }
170
130
  }
@@ -175,7 +135,7 @@ const TreeView = ({
175
135
  treeWalker.current.currentNode = treeWalker.current.root;
176
136
  while (treeWalker.current.nextNode()) {
177
137
  if (treeWalker.current.currentNode instanceof Element && !treeWalker.current.currentNode.getAttribute('aria-disabled') && !treeWalker.current.currentNode.classList.contains(`${prefix}--tree-node--hidden`)) {
178
- nodeIds.push(treeWalker.current.currentNode?.id);
138
+ nodeIds.push(treeWalker.current.currentNode.id);
179
139
  }
180
140
  }
181
141
  }
@@ -191,38 +151,41 @@ const TreeView = ({
191
151
  rest?.onKeyDown?.(event);
192
152
  }
193
153
  useEffect(() => {
194
- treeWalker.current = treeWalker.current ?? document.createTreeWalker(treeRootRef?.current, NodeFilter.SHOW_ELEMENT, {
195
- acceptNode: function (node) {
196
- if (!(node instanceof Element)) {
154
+ if (treeRootRef.current && !treeWalker.current) {
155
+ treeWalker.current = document.createTreeWalker(treeRootRef.current, NodeFilter.SHOW_ELEMENT, {
156
+ acceptNode: function (node) {
157
+ if (!(node instanceof Element)) {
158
+ return NodeFilter.FILTER_SKIP;
159
+ }
160
+ if (node.classList.contains(`${prefix}--tree-node--disabled`) || node.classList.contains(`${prefix}--tree-node--hidden`)) {
161
+ return NodeFilter.FILTER_REJECT;
162
+ }
163
+ if (node.matches(`.${prefix}--tree-node`)) {
164
+ return NodeFilter.FILTER_ACCEPT;
165
+ }
197
166
  return NodeFilter.FILTER_SKIP;
198
167
  }
199
- if (node.classList.contains(`${prefix}--tree-node--disabled`) || node.classList.contains(`${prefix}--tree-node--hidden`)) {
200
- return NodeFilter.FILTER_REJECT;
201
- }
202
- if (node.matches(`.${prefix}--tree-node`)) {
203
- return NodeFilter.FILTER_ACCEPT;
204
- }
205
- return NodeFilter.FILTER_SKIP;
206
- }
207
- });
208
- }, [prefix]);
209
- const useActiveAndSelectedOnMount = () => useEffect(() => {
210
- if (!enableTreeviewControllable) {
211
- if (preselected?.length) {
212
- setSelected(preselected);
213
- }
214
- if (prespecifiedActive) {
215
- setActive(prespecifiedActive);
216
- }
168
+ });
217
169
  }
218
- }, []);
219
- useActiveAndSelectedOnMount();
170
+ }, [prefix]);
220
171
  const labelId = `${treeId}__label`;
221
172
  const TreeLabel = () => !hideLabel ? /*#__PURE__*/React.createElement("label", {
222
173
  id: labelId,
223
174
  className: `${prefix}--label`
224
175
  }, label) : null;
225
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TreeLabel, null), /*#__PURE__*/React.createElement("ul", _extends({}, rest, {
176
+ const treeContextValue = useMemo(() => ({
177
+ active,
178
+ multiselect,
179
+ onActivate: setActive,
180
+ onTreeSelect: handleTreeSelect,
181
+ selected,
182
+ size
183
+ }), [active, multiselect, setActive, handleTreeSelect, selected, size]);
184
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TreeLabel, null), /*#__PURE__*/React.createElement(TreeContext.Provider, {
185
+ value: treeContextValue
186
+ }, /*#__PURE__*/React.createElement(DepthContext.Provider, {
187
+ value: 0
188
+ }, /*#__PURE__*/React.createElement("ul", _extends({}, rest, {
226
189
  "aria-label": hideLabel ? label : undefined,
227
190
  "aria-labelledby": !hideLabel ? labelId : undefined,
228
191
  "aria-multiselectable": multiselect || undefined,
@@ -230,7 +193,7 @@ const TreeView = ({
230
193
  onKeyDown: handleKeyDown,
231
194
  ref: treeRootRef,
232
195
  role: "tree"
233
- }), nodesWithProps));
196
+ }), children))));
234
197
  };
235
198
  TreeView.propTypes = {
236
199
  /**
@@ -14,7 +14,7 @@ import { Enter, Space, Escape } from '../../internal/keyboard/keys.js';
14
14
  import { matches } from '../../internal/keyboard/match.js';
15
15
  import { AriaLabelPropType } from '../../prop-types/AriaPropTypes.js';
16
16
  import { PrefixContext } from '../../internal/usePrefix.js';
17
- import deprecate from '../../prop-types/deprecate.js';
17
+ import { deprecate } from '../../prop-types/deprecate.js';
18
18
  import { composeEventHandlers } from '../../tools/events.js';
19
19
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
20
20
 
@@ -1,5 +1,5 @@
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.
@@ -11,7 +11,7 @@ import React, { forwardRef } from 'react';
11
11
  import cx from 'classnames';
12
12
  import Link, { LinkPropTypes } from './Link.js';
13
13
  import { usePrefix } from '../../internal/usePrefix.js';
14
- import deprecate from '../../prop-types/deprecate.js';
14
+ import { deprecate } from '../../prop-types/deprecate.js';
15
15
 
16
16
  const HeaderMenuItem = /*#__PURE__*/forwardRef(function HeaderMenuItem({
17
17
  className,
@@ -32,7 +32,7 @@ declare namespace HeaderName {
32
32
  */
33
33
  prefix: PropTypes.Requireable<string>;
34
34
  as: PropTypes.Requireable<PropTypes.ReactComponentLike>;
35
- element: (props: any, propName: any, componentName: any, ...rest: any[]) => any;
35
+ element: (props: Record<string, any>, propName: string, componentName: string, ...rest: any[]) => any;
36
36
  isSideNavExpanded: PropTypes.Requireable<boolean>;
37
37
  };
38
38
  }
@@ -1,5 +1,5 @@
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.
@@ -40,7 +40,7 @@ declare const LinkPropTypes: {
40
40
  * @deprecated Use `as` instead
41
41
  *
42
42
  */
43
- element: (props: any, propName: any, componentName: any, ...rest: any[]) => any;
43
+ element: (props: Record<string, any>, propName: string, componentName: string, ...rest: any[]) => any;
44
44
  /**
45
45
  * Property to indicate if the side nav container is open (or not). Use to
46
46
  * keep local state and styling in step with the SideNav expansion state.
@@ -8,7 +8,7 @@
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import PropTypes from 'prop-types';
10
10
  import React from 'react';
11
- import deprecate from '../../prop-types/deprecate.js';
11
+ import { deprecate } from '../../prop-types/deprecate.js';
12
12
 
13
13
  // First define the component without generics
14
14
 
@@ -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
  export interface BaseSwitcherProps {
9
9
  /**
10
10
  * expects to receive <SwitcherItem />
@@ -6,13 +6,40 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React, { forwardRef, useRef } from 'react';
9
+ import React, { forwardRef, useRef, Children, isValidElement, cloneElement } from 'react';
10
10
  import cx from 'classnames';
11
11
  import { usePrefix } from '../../internal/usePrefix.js';
12
12
  import { useMergedRefs } from '../../internal/useMergedRefs.js';
13
13
  import PropTypes from 'prop-types';
14
14
  import { AriaLabelPropType } from '../../prop-types/AriaPropTypes.js';
15
+ import './Content.js';
16
+ import './Header.js';
17
+ import './HeaderContainer.js';
18
+ import './HeaderGlobalAction.js';
19
+ import './HeaderGlobalBar.js';
20
+ import './HeaderMenu.js';
21
+ import './HeaderMenuButton.js';
22
+ import './HeaderMenuItem.js';
23
+ import './HeaderName.js';
24
+ import './HeaderNavigation.js';
25
+ import './HeaderPanel.js';
26
+ import './HeaderSideNavItems.js';
15
27
  import SwitcherItem from './SwitcherItem.js';
28
+ import SwitcherDivider from './SwitcherDivider.js';
29
+ import './SkipToContent.js';
30
+ import './SideNav.js';
31
+ import './SideNavDetails.js';
32
+ import './SideNavDivider.js';
33
+ import './SideNavFooter.js';
34
+ import './SideNavHeader.js';
35
+ import './SideNavIcon.js';
36
+ import './SideNavItem.js';
37
+ import './SideNavItems.js';
38
+ import './SideNavLink.js';
39
+ import './SideNavLinkText.js';
40
+ import './SideNavMenu.js';
41
+ import './SideNavMenuItem.js';
42
+ import './SideNavSwitcher.js';
16
43
 
17
44
  const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
18
45
  const switcherRef = useRef(null);
@@ -36,8 +63,8 @@ const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
36
63
  currentIndex,
37
64
  direction
38
65
  }) => {
39
- const enabledIndices = React.Children.toArray(children).reduce((acc, curr, i) => {
40
- if (/*#__PURE__*/React.isValidElement(curr) && Object.keys(curr.props).length !== 0 && curr.type === SwitcherItem) {
66
+ const enabledIndices = Children.toArray(children).reduce((acc, child, i) => {
67
+ if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherItem && Object.keys(child.props).length) {
41
68
  acc.push(i);
42
69
  }
43
70
  return acc;
@@ -63,21 +90,21 @@ const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
63
90
  switcherItem.focus();
64
91
  }
65
92
  };
66
- const childrenWithProps = React.Children.toArray(children).map((child, index) => {
67
- // only setup click handlers if onChange event is passed
68
- if (/*#__PURE__*/React.isValidElement(child) && child.type === SwitcherItem) {
69
- return /*#__PURE__*/React.cloneElement(child, {
93
+ const childrenWithProps = Children.toArray(children).map((child, index) => {
94
+ if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherItem) {
95
+ return /*#__PURE__*/cloneElement(child, {
70
96
  handleSwitcherItemFocus,
71
97
  index,
72
98
  key: index,
73
99
  expanded
74
100
  });
75
101
  }
76
- return /*#__PURE__*/React.cloneElement(child, {
77
- index,
78
- key: index,
79
- expanded
80
- });
102
+ if (/*#__PURE__*/isValidElement(child) && child.type === SwitcherDivider) {
103
+ return /*#__PURE__*/cloneElement(child, {
104
+ key: index
105
+ });
106
+ }
107
+ return child;
81
108
  });
82
109
  return /*#__PURE__*/React.createElement("ul", _extends({
83
110
  ref: ref,