@carbon/react 1.51.0 → 1.52.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +776 -729
  2. package/es/components/ChatButton/ChatButton.js +9 -1
  3. package/es/components/ComposedModal/ComposedModal.js +5 -4
  4. package/es/components/DataTable/TableActionList.d.ts +8 -0
  5. package/es/components/DataTable/TableActionList.js +1 -2
  6. package/es/components/DataTable/TableHead.d.ts +2 -2
  7. package/es/components/DataTable/TableToolbarContent.d.ts +1 -12
  8. package/es/components/Dropdown/Dropdown.d.ts +1 -1
  9. package/es/components/Link/Link.d.ts +5 -10
  10. package/es/components/Link/Link.js +1 -2
  11. package/es/components/Menu/Menu.d.ts +6 -6
  12. package/es/components/Menu/Menu.js +7 -3
  13. package/es/components/Menu/MenuContext.d.ts +14 -6
  14. package/es/components/Menu/MenuContext.js +3 -3
  15. package/es/components/Menu/MenuItem.d.ts +22 -31
  16. package/es/components/Menu/MenuItem.js +25 -13
  17. package/es/components/MenuButton/index.d.ts +43 -0
  18. package/es/components/MenuButton/index.js +15 -10
  19. package/es/components/Modal/Modal.js +2 -1
  20. package/es/components/Notification/Notification.d.ts +17 -1
  21. package/es/components/Notification/Notification.js +24 -9
  22. package/es/components/Toggletip/index.d.ts +1 -1
  23. package/es/components/Toggletip/index.js +4 -3
  24. package/es/components/TreeView/TreeNode.js +46 -24
  25. package/es/components/TreeView/TreeView.js +40 -13
  26. package/es/components/UIShell/Header.d.ts +24 -0
  27. package/es/components/UIShell/Header.js +1 -2
  28. package/es/components/UIShell/HeaderGlobalAction.d.ts +50 -0
  29. package/es/components/UIShell/HeaderGlobalAction.js +1 -2
  30. package/es/components/UIShell/HeaderGlobalBar.d.ts +11 -0
  31. package/es/components/UIShell/HeaderGlobalBar.js +2 -1
  32. package/es/components/UIShell/SideNavLink.d.ts +57 -0
  33. package/es/components/UIShell/SideNavLink.js +4 -4
  34. package/es/internal/useAttachedMenu.d.ts +45 -0
  35. package/es/internal/useAttachedMenu.js +1 -7
  36. package/es/tools/wrapComponent.d.ts +20 -0
  37. package/es/tools/wrapComponent.js +3 -4
  38. package/lib/components/ChatButton/ChatButton.js +9 -1
  39. package/lib/components/ComposedModal/ComposedModal.js +5 -4
  40. package/lib/components/DataTable/TableActionList.d.ts +8 -0
  41. package/lib/components/DataTable/TableActionList.js +1 -2
  42. package/lib/components/DataTable/TableHead.d.ts +2 -2
  43. package/lib/components/DataTable/TableToolbarContent.d.ts +1 -12
  44. package/lib/components/Dropdown/Dropdown.d.ts +1 -1
  45. package/lib/components/Link/Link.d.ts +5 -10
  46. package/lib/components/Link/Link.js +1 -2
  47. package/lib/components/Menu/Menu.d.ts +6 -6
  48. package/lib/components/Menu/Menu.js +6 -2
  49. package/lib/components/Menu/MenuContext.d.ts +14 -6
  50. package/lib/components/Menu/MenuContext.js +2 -6
  51. package/lib/components/Menu/MenuItem.d.ts +22 -31
  52. package/lib/components/Menu/MenuItem.js +24 -12
  53. package/lib/components/MenuButton/index.d.ts +43 -0
  54. package/lib/components/MenuButton/index.js +14 -9
  55. package/lib/components/Modal/Modal.js +2 -1
  56. package/lib/components/Notification/Notification.d.ts +17 -1
  57. package/lib/components/Notification/Notification.js +24 -9
  58. package/lib/components/Toggletip/index.d.ts +1 -1
  59. package/lib/components/Toggletip/index.js +4 -3
  60. package/lib/components/TreeView/TreeNode.js +46 -24
  61. package/lib/components/TreeView/TreeView.js +40 -13
  62. package/lib/components/UIShell/Header.d.ts +24 -0
  63. package/lib/components/UIShell/Header.js +1 -2
  64. package/lib/components/UIShell/HeaderGlobalAction.d.ts +50 -0
  65. package/lib/components/UIShell/HeaderGlobalAction.js +1 -2
  66. package/lib/components/UIShell/HeaderGlobalBar.d.ts +11 -0
  67. package/lib/components/UIShell/HeaderGlobalBar.js +2 -1
  68. package/lib/components/UIShell/SideNavLink.d.ts +57 -0
  69. package/lib/components/UIShell/SideNavLink.js +3 -3
  70. package/lib/internal/useAttachedMenu.d.ts +45 -0
  71. package/lib/internal/useAttachedMenu.js +1 -7
  72. package/lib/tools/wrapComponent.d.ts +20 -0
  73. package/lib/tools/wrapComponent.js +5 -6
  74. package/package.json +8 -8
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright IBM Corp. 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
+ import React, { ComponentProps, ReactNode } from 'react';
8
+ export interface MenuButtonProps extends ComponentProps<'div'> {
9
+ /**
10
+ * A collection of MenuItems to be rendered as actions for this MenuButton.
11
+ */
12
+ children?: ReactNode;
13
+ /**
14
+ * Additional CSS class names.
15
+ */
16
+ className?: string;
17
+ /**
18
+ * Specify whether the MenuButton should be disabled, or not.
19
+ */
20
+ disabled?: boolean;
21
+ /**
22
+ * Specify the type of button to be used as the base for the trigger button.
23
+ */
24
+ kind?: 'primary' | 'tertiary' | 'ghost';
25
+ /**
26
+ * Provide the label to be rendered on the trigger button.
27
+ */
28
+ label: string;
29
+ /**
30
+ * Experimental property. Specify how the menu should align with the button element
31
+ */
32
+ menuAlignment: 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end';
33
+ /**
34
+ * Specify the size of the button and menu.
35
+ */
36
+ size?: 'sm' | 'md' | 'lg';
37
+ /**
38
+ * Specify the tabIndex of the button.
39
+ */
40
+ tabIndex?: number;
41
+ }
42
+ declare const MenuButton: React.ForwardRefExoticComponent<Omit<MenuButtonProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
43
+ export { MenuButton };
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import React__default, { useRef, useState } from 'react';
9
+ import React__default, { forwardRef, useRef, useState } from 'react';
10
10
  import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import { ChevronDown } from '@carbon/icons-react';
@@ -22,7 +22,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
22
22
  const spacing = 0; // top and bottom spacing between the button and the menu. in px
23
23
  const validButtonKinds = ['primary', 'tertiary', 'ghost'];
24
24
  const defaultButtonKind = 'primary';
25
- const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_ref, forwardRef) {
25
+ const MenuButton = /*#__PURE__*/forwardRef(function MenuButton(_ref, forwardRef) {
26
26
  let {
27
27
  children,
28
28
  className,
@@ -58,10 +58,12 @@ const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_r
58
58
  }
59
59
  }
60
60
  function handleOpen() {
61
- menuRef.current.style.inlineSize = `${width}px`;
62
- menuRef.current.style.minInlineSize = `${width}px`;
63
- if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
64
- menuRef.current.style.inlineSize = `fit-content`;
61
+ if (menuRef.current) {
62
+ menuRef.current.style.inlineSize = `${width}px`;
63
+ menuRef.current.style.minInlineSize = `${width}px`;
64
+ if (menuAlignment !== 'bottom' && menuAlignment !== 'top') {
65
+ menuRef.current.style.inlineSize = `fit-content`;
66
+ }
65
67
  }
66
68
  }
67
69
  const containerClasses = cx(`${prefix}--menu-button__container`, className);
@@ -69,23 +71,22 @@ const MenuButton = /*#__PURE__*/React__default.forwardRef(function MenuButton(_r
69
71
  [`${prefix}--menu-button__trigger--open`]: open
70
72
  });
71
73
  const menuClasses = cx(`${prefix}--menu-button__${menuAlignment}`);
72
- const buttonKind = validButtonKinds.includes(kind) ? kind : defaultButtonKind;
73
74
  return /*#__PURE__*/React__default.createElement("div", _extends({}, rest, {
74
75
  ref: ref,
75
- "aria-owns": open ? id : null,
76
+ "aria-owns": open ? id : undefined,
76
77
  className: containerClasses
77
78
  }), /*#__PURE__*/React__default.createElement(Button, {
78
79
  className: triggerClasses,
79
80
  size: size,
80
81
  tabIndex: tabIndex,
81
- kind: buttonKind,
82
+ kind: kind,
82
83
  renderIcon: ChevronDown,
83
84
  disabled: disabled,
84
85
  "aria-haspopup": true,
85
86
  "aria-expanded": open,
86
87
  onClick: handleClick,
87
88
  onMouseDown: handleMousedown,
88
- "aria-controls": open ? id : null
89
+ "aria-controls": open ? id : undefined
89
90
  }, label), /*#__PURE__*/React__default.createElement(Menu, {
90
91
  containerRef: triggerRef,
91
92
  menuAlignment: menuAlignment,
@@ -118,6 +119,7 @@ MenuButton.propTypes = {
118
119
  /**
119
120
  * Specify the type of button to be used as the base for the trigger button.
120
121
  */
122
+ // @ts-ignore-next-line -- avoid spurious (?) TS2322 error
121
123
  kind: PropTypes.oneOf(validButtonKinds),
122
124
  /**
123
125
  * Provide the label to be renderd on the trigger button.
@@ -126,14 +128,17 @@ MenuButton.propTypes = {
126
128
  /**
127
129
  * Experimental property. Specify how the menu should align with the button element
128
130
  */
131
+ // @ts-ignore-next-line -- avoid spurious (?) TS2322 error
129
132
  menuAlignment: PropTypes.oneOf(['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end']),
130
133
  /**
131
134
  * Specify the size of the button and menu.
132
135
  */
136
+ // @ts-ignore-next-line -- avoid spurious (?) TS2322 error
133
137
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
134
138
  /**
135
139
  * Specify the tabIndex of the button.
136
140
  */
141
+ // @ts-ignore-next-line -- avoid spurious (?) TS2322 error
137
142
  tabIndex: PropTypes.number
138
143
  };
139
144
 
@@ -86,6 +86,7 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
86
86
  return !onSecondarySubmit && element === secondaryButton.current || element.classList.contains(modalCloseButtonClass);
87
87
  }
88
88
  function handleKeyDown(evt) {
89
+ evt.stopPropagation();
89
90
  if (open) {
90
91
  if (match(evt, Escape)) {
91
92
  onRequestClose(evt);
@@ -97,6 +98,7 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
97
98
  }
98
99
  function handleMousedown(evt) {
99
100
  const target = evt.target;
101
+ evt.stopPropagation();
100
102
  if (innerModal.current && !innerModal.current.contains(target) && !elementOrParentIsFloatingMenu(target, selectorsFloatingMenus) && !preventCloseOnClickOutside) {
101
103
  onRequestClose(evt);
102
104
  }
@@ -228,7 +230,6 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
228
230
  className: modalCloseButtonClass,
229
231
  label: closeButtonLabel,
230
232
  onClick: onRequestClose,
231
- title: closeButtonLabel,
232
233
  "aria-label": closeButtonLabel,
233
234
  align: "left",
234
235
  ref: button
@@ -518,6 +518,10 @@ export declare namespace ActionableNotification {
518
518
  * ==================
519
519
  */
520
520
  export interface StaticNotificationProps extends HTMLAttributes<HTMLDivElement> {
521
+ /**
522
+ * Pass in the action button label that will be rendered within the ActionableNotification.
523
+ */
524
+ actionButtonLabel?: string;
521
525
  /**
522
526
  * Specify the content
523
527
  */
@@ -534,6 +538,10 @@ export interface StaticNotificationProps extends HTMLAttributes<HTMLDivElement>
534
538
  * Specify whether you are using the low contrast variant of the StaticNotification.
535
539
  */
536
540
  lowContrast?: boolean;
541
+ /**
542
+ * Provide a function that is called when the action is clicked
543
+ */
544
+ onActionButtonClick?(): void;
537
545
  /**
538
546
  * Provide a description for "status" icon that can be read by screen readers
539
547
  */
@@ -551,9 +559,13 @@ export interface StaticNotificationProps extends HTMLAttributes<HTMLDivElement>
551
559
  */
552
560
  titleId?: string;
553
561
  }
554
- export declare function StaticNotification({ children, title, titleId, subtitle, statusIconDescription, className, kind, lowContrast, ...rest }: StaticNotificationProps): import("react/jsx-runtime").JSX.Element;
562
+ export declare function StaticNotification({ actionButtonLabel, children, onActionButtonClick, title, titleId, subtitle, statusIconDescription, className, kind, lowContrast, ...rest }: StaticNotificationProps): import("react/jsx-runtime").JSX.Element;
555
563
  export declare namespace StaticNotification {
556
564
  var propTypes: {
565
+ /**
566
+ * Pass in the action button label that will be rendered within the ActionableNotification.
567
+ */
568
+ actionButtonLabel: PropTypes.Requireable<string>;
557
569
  /**
558
570
  * Specify the content
559
571
  */
@@ -570,6 +582,10 @@ export declare namespace StaticNotification {
570
582
  * Specify whether you are using the low contrast variant of the StaticNotification.
571
583
  */
572
584
  lowContrast: PropTypes.Requireable<boolean>;
585
+ /**
586
+ * Provide a function that is called when the action is clicked
587
+ */
588
+ onActionButtonClick: PropTypes.Requireable<(...args: any[]) => any>;
573
589
  /**
574
590
  * Provide a description for "status" icon that can be read by screen readers
575
591
  */
@@ -685,7 +685,9 @@ ActionableNotification.propTypes = {
685
685
 
686
686
  function StaticNotification(_ref8) {
687
687
  let {
688
+ actionButtonLabel,
688
689
  children,
690
+ onActionButtonClick,
689
691
  title,
690
692
  titleId,
691
693
  subtitle,
@@ -697,10 +699,10 @@ function StaticNotification(_ref8) {
697
699
  } = _ref8;
698
700
  const prefix = usePrefix();
699
701
  const containerClassName = cx(className, {
700
- [`${prefix}--inline-notification`]: true,
701
- [`${prefix}--inline-notification--low-contrast`]: lowContrast,
702
- [`${prefix}--inline-notification--${kind}`]: kind,
703
- [`${prefix}--inline-notification--hide-close-button`]: true
702
+ [`${prefix}--actionable-notification`]: true,
703
+ [`${prefix}--actionable-notification--low-contrast`]: lowContrast,
704
+ [`${prefix}--actionable-notification--${kind}`]: kind,
705
+ [`${prefix}--actionable-notification--hide-close-button`]: true
704
706
  });
705
707
  const ref = useRef(null);
706
708
  useInteractiveChildrenNeedDescription(ref, `interactive child node(s) should have an \`aria-describedby\` property with a value matching the value of \`titleId\``);
@@ -709,23 +711,32 @@ function StaticNotification(_ref8) {
709
711
  }, rest, {
710
712
  className: containerClassName
711
713
  }), /*#__PURE__*/React__default.createElement("div", {
712
- className: `${prefix}--inline-notification__details`
714
+ className: `${prefix}--actionable-notification__details`
713
715
  }, /*#__PURE__*/React__default.createElement(NotificationIcon, {
714
716
  notificationType: "inline",
715
717
  kind: kind,
716
718
  iconDescription: statusIconDescription || `${kind} icon`
717
719
  }), /*#__PURE__*/React__default.createElement("div", {
718
- className: `${prefix}--inline-notification__text-wrapper`
720
+ className: `${prefix}--actionable-notification__text-wrapper`
719
721
  }, title && /*#__PURE__*/React__default.createElement(Text, {
720
722
  as: "div",
721
723
  id: titleId,
722
- className: `${prefix}--inline-notification__title`
724
+ className: `${prefix}--actionable-notification__title`
723
725
  }, title), subtitle && /*#__PURE__*/React__default.createElement(Text, {
724
726
  as: "div",
725
- className: `${prefix}--inline-notification__subtitle`
726
- }, subtitle), children)));
727
+ className: `${prefix}--actionable-notification__subtitle`
728
+ }, subtitle), children)), /*#__PURE__*/React__default.createElement("div", {
729
+ className: `${prefix}--actionable-notification__button-wrapper`
730
+ }, actionButtonLabel && /*#__PURE__*/React__default.createElement(NotificationActionButton, {
731
+ onClick: onActionButtonClick,
732
+ inline: true
733
+ }, actionButtonLabel)));
727
734
  }
728
735
  StaticNotification.propTypes = {
736
+ /**
737
+ * Pass in the action button label that will be rendered within the ActionableNotification.
738
+ */
739
+ actionButtonLabel: PropTypes.string,
729
740
  /**
730
741
  * Specify the content
731
742
  */
@@ -742,6 +753,10 @@ StaticNotification.propTypes = {
742
753
  * Specify whether you are using the low contrast variant of the StaticNotification.
743
754
  */
744
755
  lowContrast: PropTypes.bool,
756
+ /**
757
+ * Provide a function that is called when the action is clicked
758
+ */
759
+ onActionButtonClick: PropTypes.func,
745
760
  /**
746
761
  * Provide a description for "status" icon that can be read by screen readers
747
762
  */
@@ -47,7 +47,7 @@ interface ToggletipProps<E extends ElementType> {
47
47
  * is responsible for coordinating between interactions with the button and the
48
48
  * visibility of the content
49
49
  */
50
- export declare function Toggletip<E extends ElementType = 'span'>({ align, as, autoAlign, className: customClassName, children, defaultOpen, }: ToggletipProps<E>): import("react/jsx-runtime").JSX.Element;
50
+ export declare function Toggletip<E extends ElementType = 'span'>({ align, as, autoAlign, className: customClassName, children, defaultOpen, ...rest }: ToggletipProps<E>): import("react/jsx-runtime").JSX.Element;
51
51
  export declare namespace Toggletip {
52
52
  var propTypes: {
53
53
  /**
@@ -66,7 +66,8 @@ function Toggletip(_ref2) {
66
66
  autoAlign,
67
67
  className: customClassName,
68
68
  children,
69
- defaultOpen = false
69
+ defaultOpen = false,
70
+ ...rest
70
71
  } = _ref2;
71
72
  const ref = useRef(null);
72
73
  const [open, setOpen] = useState(defaultOpen);
@@ -128,7 +129,7 @@ function Toggletip(_ref2) {
128
129
  });
129
130
  return /*#__PURE__*/React__default.createElement(ToggletipContext.Provider, {
130
131
  value: value
131
- }, /*#__PURE__*/React__default.createElement(Popover, {
132
+ }, /*#__PURE__*/React__default.createElement(Popover, _extends({
132
133
  align: align,
133
134
  as: as,
134
135
  caret: true,
@@ -140,7 +141,7 @@ function Toggletip(_ref2) {
140
141
  onBlur: handleBlur,
141
142
  ref: ref,
142
143
  autoAlign: autoAlign
143
- }, children));
144
+ }, rest), children));
144
145
  }
145
146
  Toggletip.propTypes = {
146
147
  /**
@@ -12,6 +12,8 @@ import { CaretDown } from '@carbon/icons-react';
12
12
  import cx from 'classnames';
13
13
  import uniqueId from '../../tools/uniqueId.js';
14
14
  import { usePrefix } from '../../internal/usePrefix.js';
15
+ import { useControllableState } from '../../internal/useControllableState.js';
16
+ import { useFeatureFlag } from '../FeatureFlags/index.js';
15
17
  import { matches, match } from '../../internal/keyboard/match.js';
16
18
  import { ArrowLeft, ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
17
19
 
@@ -24,6 +26,7 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
24
26
  disabled,
25
27
  id: nodeId,
26
28
  isExpanded,
29
+ defaultIsExpanded,
27
30
  label,
28
31
  onNodeFocusEvent,
29
32
  onSelect: onNodeSelect,
@@ -34,10 +37,17 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
34
37
  value,
35
38
  ...rest
36
39
  } = _ref;
40
+ const enableTreeviewControllable = useFeatureFlag('enable-treeview-controllable');
37
41
  const {
38
42
  current: id
39
43
  } = useRef(nodeId || uniqueId());
40
- const [expanded, setExpanded] = useState(isExpanded);
44
+ const controllableExpandedState = useControllableState({
45
+ value: isExpanded,
46
+ onChange: onToggle,
47
+ defaultValue: defaultIsExpanded
48
+ });
49
+ const uncontrollableExpandedState = useState(isExpanded);
50
+ const [expanded, setExpanded] = enableTreeviewControllable ? controllableExpandedState : uncontrollableExpandedState;
41
51
  const currentNode = useRef(null);
42
52
  const currentNodeLabel = useRef(null);
43
53
  const prefix = usePrefix();
@@ -73,12 +83,14 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
73
83
 
74
84
  // Prevent the node from being selected
75
85
  event.stopPropagation();
76
- onToggle?.(event, {
77
- id,
78
- isExpanded: !expanded,
79
- label,
80
- value
81
- });
86
+ if (!enableTreeviewControllable) {
87
+ onToggle?.(event, {
88
+ id,
89
+ isExpanded: !expanded,
90
+ label,
91
+ value
92
+ });
93
+ }
82
94
  setExpanded(!expanded);
83
95
  }
84
96
  function handleClick(event) {
@@ -115,12 +127,14 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
115
127
  return findParentTreeNode(node.parentNode);
116
128
  };
117
129
  if (children && expanded) {
118
- onToggle?.(event, {
119
- id,
120
- isExpanded: false,
121
- label,
122
- value
123
- });
130
+ if (!enableTreeviewControllable) {
131
+ onToggle?.(event, {
132
+ id,
133
+ isExpanded: false,
134
+ label,
135
+ value
136
+ });
137
+ }
124
138
  setExpanded(false);
125
139
  } else {
126
140
  /**
@@ -138,12 +152,14 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
138
152
  */
139
153
  currentNode.current.lastChild.firstChild.focus();
140
154
  } else {
141
- onToggle?.(event, {
142
- id,
143
- isExpanded: true,
144
- label,
145
- value
146
- });
155
+ if (!enableTreeviewControllable) {
156
+ onToggle?.(event, {
157
+ id,
158
+ isExpanded: true,
159
+ label,
160
+ value
161
+ });
162
+ }
147
163
  setExpanded(true);
148
164
  }
149
165
  }
@@ -194,10 +210,11 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
194
210
  currentNodeLabel.current.style.marginInlineStart = `-${calcOffset()}rem`;
195
211
  currentNodeLabel.current.style.paddingInlineStart = `${calcOffset()}rem`;
196
212
  }
197
-
198
- // sync props and state
199
- setExpanded(isExpanded);
200
- }, [children, depth, Icon, isExpanded]);
213
+ if (!enableTreeviewControllable) {
214
+ // sync props and state
215
+ setExpanded(isExpanded);
216
+ }
217
+ }, [children, depth, Icon, isExpanded, enableTreeviewControllable, setExpanded]);
201
218
  const treeNodeProps = {
202
219
  ...rest,
203
220
  ['aria-current']: isActive || null,
@@ -260,7 +277,12 @@ TreeNode.propTypes = {
260
277
  */
261
278
  className: PropTypes.string,
262
279
  /**
263
- * * **Note:** this is controlled by the parent TreeView component, do not set manually.
280
+ * **[Experimental]** The default expansion state of the node.
281
+ * *This is only supported with the `enable-treeview-controllable` feature flag!*
282
+ */
283
+ defaultIsExpanded: PropTypes.bool,
284
+ /**
285
+ * **Note:** this is controlled by the parent TreeView component, do not set manually.
264
286
  * TreeNode depth to determine spacing
265
287
  */
266
288
  depth: PropTypes.number,
@@ -11,6 +11,8 @@ import PropTypes from 'prop-types';
11
11
  import cx from 'classnames';
12
12
  import uniqueId from '../../tools/uniqueId.js';
13
13
  import { usePrefix } from '../../internal/usePrefix.js';
14
+ import { useControllableState } from '../../internal/useControllableState.js';
15
+ import { useFeatureFlag } from '../FeatureFlags/index.js';
14
16
  import { matches, match } from '../../internal/keyboard/match.js';
15
17
  import { ArrowUp, ArrowDown, Home, End } from '../../internal/keyboard/keys.js';
16
18
 
@@ -22,11 +24,13 @@ function TreeView(_ref) {
22
24
  hideLabel = false,
23
25
  label,
24
26
  multiselect = false,
27
+ onActivate,
25
28
  onSelect,
26
- selected: preselected = [],
29
+ selected: preselected,
27
30
  size = 'sm',
28
31
  ...rest
29
32
  } = _ref;
33
+ const enableTreeviewControllable = useFeatureFlag('enable-treeview-controllable');
30
34
  const {
31
35
  current: treeId
32
36
  } = useRef(rest.id || uniqueId());
@@ -36,8 +40,20 @@ function TreeView(_ref) {
36
40
  });
37
41
  const treeRootRef = useRef(null);
38
42
  const treeWalker = useRef(treeRootRef?.current);
39
- const [selected, setSelected] = useState(preselected);
40
- const [active, setActive] = useState(prespecifiedActive);
43
+ const controllableSelectionState = useControllableState({
44
+ value: preselected,
45
+ onChange: onSelect,
46
+ defaultValue: []
47
+ });
48
+ const uncontrollableSelectionState = useState(preselected ?? []);
49
+ const [selected, setSelected] = enableTreeviewControllable ? controllableSelectionState : uncontrollableSelectionState;
50
+ const controllableActiveState = useControllableState({
51
+ value: prespecifiedActive,
52
+ onChange: onActivate,
53
+ defaultValue: undefined
54
+ });
55
+ const uncontrollableActiveState = useState(prespecifiedActive);
56
+ const [active, setActive] = enableTreeviewControllable ? controllableActiveState : uncontrollableActiveState;
41
57
  function resetNodeTabIndices() {
42
58
  Array.prototype.forEach.call(treeRootRef?.current?.querySelectorAll('[tabIndex="0"]') ?? [], item => {
43
59
  item.tabIndex = -1;
@@ -54,14 +70,18 @@ function TreeView(_ref) {
54
70
  } else {
55
71
  setSelected(selected.filter(selectedId => selectedId !== nodeId));
56
72
  }
57
- onSelect?.(event, node);
73
+ if (!enableTreeviewControllable) {
74
+ onSelect?.(event, node);
75
+ }
58
76
  } else {
59
77
  setSelected([nodeId]);
60
78
  setActive(nodeId);
61
- onSelect?.(event, {
62
- activeNodeId: nodeId,
63
- ...node
64
- });
79
+ if (!enableTreeviewControllable) {
80
+ onSelect?.(event, {
81
+ activeNodeId: nodeId,
82
+ ...node
83
+ });
84
+ }
65
85
  }
66
86
  }
67
87
  function handleFocusEvent(event) {
@@ -167,11 +187,13 @@ function TreeView(_ref) {
167
187
  });
168
188
  }, [prefix]);
169
189
  const useActiveAndSelectedOnMount = () => useEffect(() => {
170
- if (preselected.length) {
171
- setSelected(preselected);
172
- }
173
- if (prespecifiedActive) {
174
- setActive(prespecifiedActive);
190
+ if (!enableTreeviewControllable) {
191
+ if (preselected?.length) {
192
+ setSelected(preselected);
193
+ }
194
+ if (prespecifiedActive) {
195
+ setActive(prespecifiedActive);
196
+ }
175
197
  }
176
198
  }, []);
177
199
  useActiveAndSelectedOnMount();
@@ -216,6 +238,11 @@ TreeView.propTypes = {
216
238
  * If `multiselect` is `false` then only one node can be selected at a time
217
239
  */
218
240
  multiselect: PropTypes.bool,
241
+ /**
242
+ * **[Experimental]** Callback function that is called when any node is activated.
243
+ * *This is only supported with the `enable-treeview-controllable` feature flag!*
244
+ */
245
+ onActivate: PropTypes.func,
219
246
  /**
220
247
  * Callback function that is called when any node is selected
221
248
  */
@@ -0,0 +1,24 @@
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
+ import React, { ReactNode } from 'react';
8
+ interface HeaderProps {
9
+ children?: ReactNode;
10
+ /**
11
+ * Required props for the accessibility label of the header
12
+ */
13
+ 'aria-label'?: string;
14
+ /**
15
+ * Required props for the accessibility label of the header
16
+ */
17
+ 'aria-labelledby'?: string;
18
+ /**
19
+ * Optionally provide a custom class name that is applied to the underlying <header>
20
+ */
21
+ className?: string;
22
+ }
23
+ declare const Header: React.FC<HeaderProps>;
24
+ export default Header;
@@ -34,6 +34,5 @@ Header.propTypes = {
34
34
  */
35
35
  className: PropTypes.string
36
36
  };
37
- var Header$1 = Header;
38
37
 
39
- export { Header$1 as default };
38
+ export { Header as default };
@@ -0,0 +1,50 @@
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
+ import React, { ReactNode } from 'react';
8
+ interface HeaderGlobalActionProps {
9
+ /**
10
+ * Required props for the accessibility label of the button
11
+ */
12
+ 'aria-label'?: string;
13
+ /**
14
+ * Required props for the accessibility label of the button
15
+ */
16
+ 'aria-labelledby'?: string;
17
+ /**
18
+ * Provide a custom icon for this global action
19
+ */
20
+ children: ReactNode;
21
+ /**
22
+ * Optionally provide a custom class name that is applied to the underlying
23
+ * button
24
+ */
25
+ className?: string;
26
+ /**
27
+ * Specify whether the action is currently active
28
+ */
29
+ isActive?: boolean;
30
+ /**
31
+ * Optionally provide an onClick handler that is called when the underlying
32
+ * button fires it's onclick event
33
+ */
34
+ onClick?: () => void;
35
+ /**
36
+ * Specify the alignment of the tooltip to the icon-only button.
37
+ * Can be one of: start, center, or end.
38
+ */
39
+ tooltipAlignment?: 'start' | 'center' | 'end';
40
+ }
41
+ /**
42
+ * HeaderGlobalAction is used as a part of the `HeaderGlobalBar`. It is
43
+ * essentially an Icon Button with an additional state to indicate whether it is
44
+ * "active". The active state comes from when a user clicks on the global action
45
+ * which should trigger a panel to appear.
46
+ *
47
+ * Note: children passed to this component should be an Icon.
48
+ */
49
+ declare const HeaderGlobalAction: React.FC<HeaderGlobalActionProps>;
50
+ export default HeaderGlobalAction;
@@ -84,6 +84,5 @@ HeaderGlobalAction.propTypes = {
84
84
  tooltipAlignment: PropTypes.oneOf(['start', 'center', 'end'])
85
85
  };
86
86
  HeaderGlobalAction.displayName = 'HeaderGlobalAction';
87
- var HeaderGlobalAction$1 = HeaderGlobalAction;
88
87
 
89
- export { HeaderGlobalAction$1 as default };
88
+ export { HeaderGlobalAction as default };
@@ -0,0 +1,11 @@
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
+ * Generic container for `HeaderGlobalAction` components
9
+ */
10
+ declare const HeaderGlobalBar: (props: import("../../types/common").ReactAttr<"div">) => import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
11
+ export default HeaderGlobalBar;
@@ -10,7 +10,8 @@ import wrapComponent from '../../tools/wrapComponent.js';
10
10
  /**
11
11
  * Generic container for `HeaderGlobalAction` components
12
12
  */
13
- var HeaderGlobalBar = wrapComponent({
13
+
14
+ const HeaderGlobalBar = wrapComponent({
14
15
  name: 'HeaderGlobalBar',
15
16
  className: prefix => `${prefix}--header__global`,
16
17
  type: 'div'