@carbon/react 1.65.0-rc.0 → 1.66.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 (58) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +901 -866
  2. package/es/components/ChatButton/ChatButton.Skeleton.d.ts +31 -0
  3. package/es/components/ChatButton/ChatButton.Skeleton.js +1 -2
  4. package/es/components/ChatButton/ChatButton.d.ts +46 -0
  5. package/es/components/ChatButton/ChatButton.js +3 -3
  6. package/es/components/ChatButton/index.d.ts +12 -0
  7. package/es/components/Checkbox/index.js +10 -0
  8. package/es/components/ComboBox/ComboBox.js +12 -7
  9. package/es/components/ComboButton/index.js +8 -3
  10. package/es/components/ComposedModal/index.d.ts +2 -0
  11. package/es/components/DataTable/TableSlugRow.d.ts +1 -0
  12. package/es/components/DataTable/TableSlugRow.js +1 -0
  13. package/es/components/Grid/Column.js +3 -3
  14. package/es/components/ListBox/ListBoxMenuItem.d.ts +10 -1
  15. package/es/components/ListBox/next/ListBoxSelection.d.ts +106 -0
  16. package/es/components/ListBox/next/ListBoxSelection.js +12 -16
  17. package/es/components/ListBox/next/ListBoxTrigger.d.ts +31 -0
  18. package/es/components/ListBox/next/ListBoxTrigger.js +2 -4
  19. package/es/components/ListBox/next/index.d.ts +8 -0
  20. package/es/components/MultiSelect/FilterableMultiSelect.js +12 -14
  21. package/es/components/MultiSelect/MultiSelect.js +64 -49
  22. package/es/components/MultiSelect/tools/sorting.js +5 -8
  23. package/es/components/OverflowMenu/OverflowMenu.js +1 -1
  24. package/es/components/Popover/index.js +21 -4
  25. package/es/components/TreeView/TreeNode.js +41 -33
  26. package/es/components/TreeView/TreeView.d.ts +5 -3
  27. package/es/index.js +2 -2
  28. package/es/internal/Selection.js +30 -18
  29. package/es/internal/useMergedRefs.d.ts +1 -1
  30. package/lib/components/ChatButton/ChatButton.Skeleton.d.ts +31 -0
  31. package/lib/components/ChatButton/ChatButton.Skeleton.js +1 -2
  32. package/lib/components/ChatButton/ChatButton.d.ts +46 -0
  33. package/lib/components/ChatButton/ChatButton.js +4 -4
  34. package/lib/components/ChatButton/index.d.ts +12 -0
  35. package/lib/components/Checkbox/index.js +19 -0
  36. package/lib/components/ComboBox/ComboBox.js +12 -7
  37. package/lib/components/ComboButton/index.js +8 -3
  38. package/lib/components/ComposedModal/index.d.ts +2 -0
  39. package/lib/components/DataTable/TableSlugRow.d.ts +1 -0
  40. package/lib/components/DataTable/TableSlugRow.js +1 -0
  41. package/lib/components/Grid/Column.js +3 -3
  42. package/lib/components/ListBox/ListBoxMenuItem.d.ts +10 -1
  43. package/lib/components/ListBox/next/ListBoxSelection.d.ts +106 -0
  44. package/lib/components/ListBox/next/ListBoxSelection.js +11 -16
  45. package/lib/components/ListBox/next/ListBoxTrigger.d.ts +31 -0
  46. package/lib/components/ListBox/next/ListBoxTrigger.js +2 -4
  47. package/lib/components/ListBox/next/index.d.ts +8 -0
  48. package/lib/components/MultiSelect/FilterableMultiSelect.js +12 -14
  49. package/lib/components/MultiSelect/MultiSelect.js +63 -48
  50. package/lib/components/MultiSelect/tools/sorting.js +5 -8
  51. package/lib/components/OverflowMenu/OverflowMenu.js +1 -1
  52. package/lib/components/Popover/index.js +21 -4
  53. package/lib/components/TreeView/TreeNode.js +41 -33
  54. package/lib/components/TreeView/TreeView.d.ts +5 -3
  55. package/lib/index.js +4 -4
  56. package/lib/internal/Selection.js +30 -18
  57. package/lib/internal/useMergedRefs.d.ts +1 -1
  58. package/package.json +27 -24
@@ -11,7 +11,7 @@ import cx from 'classnames';
11
11
  import { useSelect } from 'downshift';
12
12
  import isEqual from 'react-fast-compare';
13
13
  import PropTypes from 'prop-types';
14
- import React__default, { useContext, useState, useLayoutEffect, useMemo } from 'react';
14
+ import React__default, { useMemo, useContext, useState, useLayoutEffect } from 'react';
15
15
  import ListBox from '../ListBox/index.js';
16
16
  import { sortingPropTypes } from './MultiSelectPropTypes.js';
17
17
  import { defaultSortItems, defaultCompareItems } from './tools/sorting.js';
@@ -22,8 +22,11 @@ import deprecate from '../../prop-types/deprecate.js';
22
22
  import { usePrefix } from '../../internal/usePrefix.js';
23
23
  import '../FluidForm/FluidForm.js';
24
24
  import { FormContext } from '../FluidForm/FormContext.js';
25
+ import Checkbox from '../Checkbox/Checkbox.js';
26
+ import '../Checkbox/Checkbox.Skeleton.js';
25
27
  import { noopFn } from '../../internal/noopFn.js';
26
28
  import { useFloating, flip, size, autoUpdate } from '@floating-ui/react';
29
+ import { hide } from '../../node_modules/@floating-ui/core/dist/floating-ui.core.mjs.js';
27
30
  import { match } from '../../internal/keyboard/match.js';
28
31
  import { ListBoxSize } from '../ListBox/ListBoxPropTypes.js';
29
32
  import { Delete, Escape, Space, ArrowDown, Enter } from '../../internal/keyboard/keys.js';
@@ -94,6 +97,23 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
94
97
  locale = 'en',
95
98
  slug
96
99
  } = _ref;
100
+ const filteredItems = useMemo(() => {
101
+ return items.filter(item => {
102
+ if (typeof item === 'object' && item !== null) {
103
+ for (const key in item) {
104
+ if (Object.hasOwn(item, key) && item[key] === undefined) {
105
+ return false; // Return false if any property has an undefined value
106
+ }
107
+ }
108
+ }
109
+ return true; // Return true if item is not an object with undefined values
110
+ });
111
+ }, [items]);
112
+ let selectAll = filteredItems.some(item => item.isSelectAll);
113
+ if ((selected ?? []).length > 0 && selectAll) {
114
+ console.warn('Warning: `selectAll` should not be used when `selectedItems` is provided. Please pass either `selectAll` or `selectedItems`, not both.');
115
+ selectAll = false;
116
+ }
97
117
  const prefix = usePrefix();
98
118
  const {
99
119
  isFluid
@@ -105,16 +125,6 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
105
125
  const [prevOpenProp, setPrevOpenProp] = useState(open);
106
126
  const [topItems, setTopItems] = useState([]);
107
127
  const [itemsCleared, setItemsCleared] = useState(false);
108
- const {
109
- selectedItems: controlledSelectedItems,
110
- onItemChange,
111
- clearSelection
112
- } = useSelection({
113
- disabled,
114
- initialSelectedItems,
115
- onChange,
116
- selectedItems: selected
117
- });
118
128
  const {
119
129
  refs,
120
130
  floatingStyles,
@@ -139,32 +149,40 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
139
149
  width: `${rects.reference.width}px`
140
150
  });
141
151
  }
142
- })],
152
+ }), hide()],
143
153
  whileElementsMounted: autoUpdate
144
154
  } : {});
145
155
  useLayoutEffect(() => {
146
156
  if (autoAlign) {
147
- Object.keys(floatingStyles).forEach(style => {
157
+ const updatedFloatingStyles = {
158
+ ...floatingStyles,
159
+ visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
160
+ };
161
+ Object.keys(updatedFloatingStyles).forEach(style => {
148
162
  if (refs.floating.current) {
149
- refs.floating.current.style[style] = floatingStyles[style];
163
+ refs.floating.current.style[style] = updatedFloatingStyles[style];
150
164
  }
151
165
  });
152
166
  }
153
167
  }, [autoAlign, floatingStyles, refs.floating, middlewareData, open]);
154
-
155
- // Filter out items with an object having undefined values
156
- const filteredItems = useMemo(() => {
157
- return items.filter(item => {
158
- if (typeof item === 'object' && item !== null) {
159
- for (const key in item) {
160
- if (Object.hasOwn(item, key) && item[key] === undefined) {
161
- return false; // Return false if any property has an undefined value
162
- }
163
- }
164
- }
165
- return true; // Return true if item is not an object with undefined values
166
- });
167
- }, [items]);
168
+ const {
169
+ selectedItems: controlledSelectedItems,
170
+ onItemChange,
171
+ clearSelection
172
+ } = useSelection({
173
+ disabled,
174
+ initialSelectedItems,
175
+ onChange,
176
+ selectedItems: selected,
177
+ selectAll,
178
+ filteredItems
179
+ });
180
+ const sortOptions = {
181
+ selectedItems: controlledSelectedItems,
182
+ itemToString,
183
+ compareItems,
184
+ locale
185
+ };
168
186
  const selectProps = {
169
187
  stateReducer,
170
188
  isOpen,
@@ -260,18 +278,13 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
260
278
  [`${prefix}--multi-select--inline`]: inline,
261
279
  [`${prefix}--multi-select--selected`]: selectedItems && selectedItems.length > 0,
262
280
  [`${prefix}--list-box--up`]: direction === 'top',
263
- [`${prefix}--multi-select--readonly`]: readOnly
281
+ [`${prefix}--multi-select--readonly`]: readOnly,
282
+ [`${prefix}--multi-select--selectall`]: selectAll
264
283
  });
265
284
 
266
285
  // needs to be capitalized for react to render it correctly
267
286
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
268
287
  const ItemToElement = itemToElement;
269
- const sortOptions = {
270
- selectedItems: controlledSelectedItems,
271
- itemToString,
272
- compareItems,
273
- locale
274
- };
275
288
  if (selectionFeedback === 'fixed') {
276
289
  sortOptions.selectedItems = [];
277
290
  } else if (selectionFeedback === 'top-after-reopen') {
@@ -334,7 +347,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
334
347
  } else {
335
348
  return {
336
349
  ...changes,
337
- highlightedIndex: props.items.indexOf(highlightedIndex)
350
+ highlightedIndex: filteredItems.indexOf(highlightedIndex)
338
351
  };
339
352
  }
340
353
  case ToggleButtonKeyDownArrowDown:
@@ -392,11 +405,12 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
392
405
  });
393
406
  }
394
407
  const itemsSelectedText = selectedItems.length > 0 && selectedItems.map(item => item?.text);
408
+ const selectedItemsLength = selectAll ? selectedItems.filter(item => !item.isSelectAll).length : selectedItems.length;
395
409
 
396
410
  // Memoize the value of getMenuProps to avoid an infinite loop
397
411
  const menuProps = useMemo(() => getMenuProps({
398
412
  ref: autoAlign ? refs.setFloating : null
399
- }), [autoAlign]);
413
+ }), [autoAlign, getMenuProps, refs.setFloating]);
400
414
  return /*#__PURE__*/React__default.createElement("div", {
401
415
  className: wrapperClasses
402
416
  }, /*#__PURE__*/React__default.createElement("label", _extends({
@@ -427,7 +441,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
427
441
  }, selectedItems.length > 0 && /*#__PURE__*/React__default.createElement(ListBox.Selection, {
428
442
  readOnly: readOnly,
429
443
  clearSelection: !disabled && !readOnly ? clearSelection : noopFn,
430
- selectionCount: selectedItems.length
444
+ selectionCount: selectedItemsLength
431
445
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
432
446
  ,
433
447
  translateWithId: translateWithId,
@@ -446,10 +460,9 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
446
460
  }, label), /*#__PURE__*/React__default.createElement(ListBox.MenuIcon, {
447
461
  isOpen: isOpen,
448
462
  translateWithId: translateWithId
449
- })), normalizedSlug), /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen &&
450
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
451
- sortItems(filteredItems, sortOptions).map((item, index) => {
463
+ })), normalizedSlug), /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen && sortItems(filteredItems, sortOptions).map((item, index) => {
452
464
  const isChecked = selectedItems.filter(selected => isEqual(selected, item)).length > 0;
465
+ const isIndeterminate = selectedItems.length !== 0 && item['isSelectAll'] && !isChecked;
453
466
  const itemProps = getItemProps({
454
467
  item,
455
468
  // we don't want Downshift to set aria-selected for us
@@ -459,21 +472,23 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
459
472
  const itemText = itemToString(item);
460
473
  return /*#__PURE__*/React__default.createElement(ListBox.MenuItem, _extends({
461
474
  key: itemProps.id,
462
- isActive: isChecked,
475
+ isActive: isChecked && !item['isSelectAll'],
463
476
  "aria-label": itemText,
464
477
  isHighlighted: highlightedIndex === index,
465
478
  title: itemText,
466
479
  disabled: itemProps['aria-disabled']
467
480
  }, itemProps), /*#__PURE__*/React__default.createElement("div", {
468
481
  className: `${prefix}--checkbox-wrapper`
469
- }, /*#__PURE__*/React__default.createElement("span", {
482
+ }, /*#__PURE__*/React__default.createElement(Checkbox, {
483
+ id: `${itemProps.id}__checkbox`,
484
+ labelText: itemToElement ? /*#__PURE__*/React__default.createElement(ItemToElement, _extends({
485
+ key: itemProps.id
486
+ }, item)) : itemText,
487
+ checked: isChecked,
470
488
  title: useTitleInItem ? itemText : undefined,
471
- className: `${prefix}--checkbox-label`,
472
- "data-contained-checkbox-state": isChecked,
473
- id: `${itemProps.id}__checkbox`
474
- }, itemToElement ? /*#__PURE__*/React__default.createElement(ItemToElement, _extends({
475
- key: itemProps.id
476
- }, item)) : itemText)));
489
+ indeterminate: isIndeterminate,
490
+ disabled: disabled
491
+ })));
477
492
  })), itemsCleared && /*#__PURE__*/React__default.createElement("span", {
478
493
  "aria-live": "assertive",
479
494
  "aria-label": clearAnnouncement
@@ -35,16 +35,13 @@ const defaultSortItems = (items, _ref2) => {
35
35
  locale = 'en'
36
36
  } = _ref2;
37
37
  return items.sort((itemA, itemB) => {
38
+ // Always place "select all" option at the beginning
39
+ if (itemA.isSelectAll) return -1;
40
+ if (itemB.isSelectAll) return 1;
38
41
  const hasItemA = selectedItems.includes(itemA);
39
42
  const hasItemB = selectedItems.includes(itemB);
40
-
41
- // Prefer whichever item is in the `selectedItems` array first
42
- if (hasItemA && !hasItemB) {
43
- return -1;
44
- }
45
- if (hasItemB && !hasItemA) {
46
- return 1;
47
- }
43
+ if (hasItemA && !hasItemB) return -1;
44
+ if (hasItemB && !hasItemA) return 1;
48
45
  return compareItems(itemToString(itemA), itemToString(itemB), {
49
46
  locale
50
47
  });
@@ -251,7 +251,7 @@ class OverflowMenu extends React__default.Component {
251
251
  } = this.props;
252
252
  if (menuBody) {
253
253
  this._menuBody = menuBody;
254
- const hasFocusin = ('onfocusin' in window);
254
+ const hasFocusin = 'onfocusin' in window;
255
255
  const focusinEventName = hasFocusin ? 'focusin' : 'focus';
256
256
  this._hFocusIn = on(menuBody.ownerDocument, focusinEventName, event => {
257
257
  const target = ClickListener.getEventTarget(event);
@@ -16,6 +16,7 @@ import { usePrefix } from '../../internal/usePrefix.js';
16
16
  import { useWindowEvent } from '../../internal/useEvent.js';
17
17
  import { mapPopoverAlignProp } from '../../tools/createPropAdapter.js';
18
18
  import { useFloating, offset, flip, arrow, autoUpdate } from '@floating-ui/react';
19
+ import { hide } from '../../node_modules/@floating-ui/core/dist/floating-ui.core.mjs.js';
19
20
 
20
21
  const PopoverContext = /*#__PURE__*/React__default.createContext({
21
22
  setFloating: {
@@ -128,7 +129,7 @@ const Popover = /*#__PURE__*/React__default.forwardRef(function PopoverRenderFun
128
129
  fallbackAxisSideDirection: 'start'
129
130
  }), arrow({
130
131
  element: caretRef
131
- })],
132
+ }), hide()],
132
133
  whileElementsMounted: autoUpdate
133
134
  } : {} // When autoAlign is turned off, floating-ui will not be used
134
135
  );
@@ -148,9 +149,13 @@ const Popover = /*#__PURE__*/React__default.forwardRef(function PopoverRenderFun
148
149
  }
149
150
  useEffect(() => {
150
151
  if (autoAlign) {
151
- Object.keys(floatingStyles).forEach(style => {
152
+ const updatedFloatingStyles = {
153
+ ...floatingStyles,
154
+ visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
155
+ };
156
+ Object.keys(updatedFloatingStyles).forEach(style => {
152
157
  if (refs.floating.current) {
153
- refs.floating.current.style[style] = floatingStyles[style];
158
+ refs.floating.current.style[style] = updatedFloatingStyles[style];
154
159
  }
155
160
  });
156
161
  if (caret && middlewareData && middlewareData.arrow && caretRef?.current) {
@@ -190,7 +195,19 @@ const Popover = /*#__PURE__*/React__default.forwardRef(function PopoverRenderFun
190
195
  }, customClassName);
191
196
  const mappedChildren = React__default.Children.map(children, child => {
192
197
  const item = child;
193
- if ((item?.type === 'button' || autoAlign && item?.type?.displayName !== 'PopoverContent' || autoAlign && item?.type?.displayName === 'ToggletipButton') && /*#__PURE__*/React__default.isValidElement(item)) {
198
+ const displayName = item?.type?.displayName;
199
+
200
+ /**
201
+ * Only trigger elements (button) or trigger components (ToggletipButton) should be
202
+ * cloned because these will be decorated with a trigger-specific className and ref.
203
+ *
204
+ * There are also some specific components that should not be cloned when autoAlign
205
+ * is on, even if they are a trigger element.
206
+ */
207
+ const isTriggerElement = item?.type === 'button';
208
+ const isTriggerComponent = autoAlign && displayName && ['ToggletipButton'].includes(displayName);
209
+ const isAllowedTriggerComponent = autoAlign && displayName && !['ToggletipContent', 'PopoverContent'].includes(displayName);
210
+ if ( /*#__PURE__*/React__default.isValidElement(item) && (isTriggerElement || isTriggerComponent || isAllowedTriggerComponent)) {
194
211
  const className = item?.props?.className;
195
212
  const ref = (item?.props).ref;
196
213
  const tabTipClasses = cx(`${prefix}--popover--tab-tip__button`, className);
@@ -17,7 +17,7 @@ import { useFeatureFlag } from '../FeatureFlags/index.js';
17
17
  import { matches, match } from '../../internal/keyboard/match.js';
18
18
  import { ArrowLeft, ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
19
19
 
20
- const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
20
+ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, forwardedRef) => {
21
21
  let {
22
22
  active,
23
23
  children,
@@ -54,6 +54,14 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
54
54
  const currentNode = useRef(null);
55
55
  const currentNodeLabel = useRef(null);
56
56
  const prefix = usePrefix();
57
+ const setRefs = element => {
58
+ currentNode.current = element;
59
+ if (typeof forwardedRef === 'function') {
60
+ forwardedRef(element);
61
+ } else if (forwardedRef) {
62
+ forwardedRef.current = element;
63
+ }
64
+ };
57
65
  const nodesWithProps = React__default.Children.map(children, node => {
58
66
  if ( /*#__PURE__*/React__default.isValidElement(node)) {
59
67
  return /*#__PURE__*/React__default.cloneElement(node, {
@@ -121,13 +129,14 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
121
129
  }
122
130
  if (match(event, ArrowLeft)) {
123
131
  const findParentTreeNode = node => {
132
+ if (!node) return null;
124
133
  if (node.classList.contains(`${prefix}--tree-parent-node`)) {
125
134
  return node;
126
135
  }
127
136
  if (node.classList.contains(`${prefix}--tree`)) {
128
137
  return null;
129
138
  }
130
- return findParentTreeNode(node.parentNode);
139
+ return findParentTreeNode(node.parentElement);
131
140
  };
132
141
  if (children && expanded) {
133
142
  if (!enableTreeviewControllable) {
@@ -144,7 +153,10 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
144
153
  * When focus is on a leaf node or a closed parent node, move focus to
145
154
  * its parent node (unless its depth is level 1)
146
155
  */
147
- findParentTreeNode(currentNode.current?.parentNode)?.focus();
156
+ const parentNode = findParentTreeNode(currentNode.current?.parentElement || null);
157
+ if (parentNode instanceof HTMLElement) {
158
+ parentNode.focus();
159
+ }
148
160
  }
149
161
  }
150
162
  if (children && match(event, ArrowRight)) {
@@ -229,44 +241,40 @@ const TreeNode = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
229
241
  onClick: handleClick,
230
242
  onFocus: handleFocusEvent,
231
243
  onKeyDown: handleKeyDown,
232
- role: 'treeitem',
233
- // @ts-ignore
234
- ref: currentNode
244
+ role: 'treeitem'
235
245
  };
236
246
  if (!children) {
237
- return /*#__PURE__*/React__default.createElement("li", treeNodeProps, /*#__PURE__*/React__default.createElement("div", {
247
+ return /*#__PURE__*/React__default.createElement("li", _extends({}, treeNodeProps, {
248
+ ref: setRefs
249
+ }), /*#__PURE__*/React__default.createElement("div", {
238
250
  className: `${prefix}--tree-node__label`,
239
251
  ref: currentNodeLabel
240
252
  }, Icon && /*#__PURE__*/React__default.createElement(Icon, {
241
253
  className: `${prefix}--tree-node__icon`
242
254
  }), label));
243
255
  }
244
- return (
245
- /*#__PURE__*/
246
- // eslint-disable-next-line jsx-a11y/role-supports-aria-props
247
- React__default.createElement("li", _extends({}, treeNodeProps, {
248
- "aria-expanded": !!expanded,
249
- ref: ref
250
- }), /*#__PURE__*/React__default.createElement("div", {
251
- className: `${prefix}--tree-node__label`,
252
- ref: currentNodeLabel
253
- }, /*#__PURE__*/React__default.createElement("span", {
254
- className: `${prefix}--tree-parent-node__toggle`
255
- // @ts-ignore
256
- ,
257
- disabled: disabled,
258
- onClick: handleToggleClick
259
- }, /*#__PURE__*/React__default.createElement(CaretDown, {
260
- className: toggleClasses
261
- })), /*#__PURE__*/React__default.createElement("span", {
262
- className: `${prefix}--tree-node__label__details`
263
- }, Icon && /*#__PURE__*/React__default.createElement(Icon, {
264
- className: `${prefix}--tree-node__icon`
265
- }), label)), expanded && /*#__PURE__*/React__default.createElement("ul", {
266
- role: "group",
267
- className: `${prefix}--tree-node__children`
268
- }, nodesWithProps))
269
- );
256
+ return /*#__PURE__*/React__default.createElement("li", _extends({}, treeNodeProps, {
257
+ "aria-expanded": !!expanded,
258
+ ref: setRefs
259
+ }), /*#__PURE__*/React__default.createElement("div", {
260
+ className: `${prefix}--tree-node__label`,
261
+ ref: currentNodeLabel
262
+ }, /*#__PURE__*/React__default.createElement("span", {
263
+ className: `${prefix}--tree-parent-node__toggle`
264
+ // @ts-ignore
265
+ ,
266
+ disabled: disabled,
267
+ onClick: handleToggleClick
268
+ }, /*#__PURE__*/React__default.createElement(CaretDown, {
269
+ className: toggleClasses
270
+ })), /*#__PURE__*/React__default.createElement("span", {
271
+ className: `${prefix}--tree-node__label__details`
272
+ }, Icon && /*#__PURE__*/React__default.createElement(Icon, {
273
+ className: `${prefix}--tree-node__icon`
274
+ }), label)), expanded && /*#__PURE__*/React__default.createElement("ul", {
275
+ role: "group",
276
+ className: `${prefix}--tree-node__children`
277
+ }, nodesWithProps));
270
278
  });
271
279
  TreeNode.propTypes = {
272
280
  /**
@@ -5,7 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import TreeNode from './TreeNode';
8
+ import TreeNode, { TreeNodeProps } from './TreeNode';
9
9
  export type TreeViewProps = {
10
10
  /**
11
11
  * Mark the active node in the tree, represented by its ID
@@ -40,7 +40,9 @@ export type TreeViewProps = {
40
40
  /**
41
41
  * Callback function that is called when any node is selected
42
42
  */
43
- onSelect?: (selected: Array<string | number>, payload: any) => void;
43
+ onSelect?: (event: React.SyntheticEvent<HTMLUListElement>, payload?: Partial<TreeNodeProps> & {
44
+ activeNodeId?: string | number;
45
+ }) => void;
44
46
  /**
45
47
  * Array representing all selected node IDs in the tree
46
48
  */
@@ -49,7 +51,7 @@ export type TreeViewProps = {
49
51
  * Specify the size of the tree from a list of available sizes.
50
52
  */
51
53
  size?: 'xs' | 'sm';
52
- } & React.HTMLAttributes<HTMLUListElement>;
54
+ } & Omit<React.HTMLAttributes<HTMLUListElement>, 'onSelect'>;
53
55
  type TreeViewComponent = {
54
56
  (props: TreeViewProps): JSX.Element;
55
57
  propTypes?: any;
package/es/index.js CHANGED
@@ -167,6 +167,8 @@ export { OverflowMenuV2 as unstable_OverflowMenuV2 } from './components/Overflow
167
167
  export { Popover, PopoverContent } from './components/Popover/index.js';
168
168
  export { default as ProgressBar } from './components/ProgressBar/ProgressBar.js';
169
169
  export { AILabel, AILabelActions, AILabelContent, AILabel as unstable__Slug, AILabelActions as unstable__SlugActions, AILabelContent as unstable__SlugContent } from './components/AILabel/index.js';
170
+ export { default as unstable__ChatButton } from './components/ChatButton/ChatButton.js';
171
+ export { default as unstable__ChatButtonSkeleton } from './components/ChatButton/ChatButton.Skeleton.js';
170
172
  export { default as AISkeletonPlaceholder, default as unstable__AiSkeletonPlaceholder } from './components/AISkeleton/AISkeletonPlaceholder.js';
171
173
  export { default as AISkeletonIcon, default as unstable__AiSkeletonIcon } from './components/AISkeleton/AISkeletonIcon.js';
172
174
  export { default as AISkeletonText, default as unstable__AiSkeletonText } from './components/AISkeleton/AISkeletonText.js';
@@ -206,8 +208,6 @@ export { default as unstable__FluidTimePickerSkeleton } from './components/Fluid
206
208
  export { default as unstable__FluidTimePickerSelect } from './components/FluidTimePickerSelect/FluidTimePickerSelect.js';
207
209
  export { LayoutDirection as unstable_LayoutDirection } from './components/LayoutDirection/LayoutDirection.js';
208
210
  export { useLayoutDirection as unstable_useLayoutDirection } from './components/LayoutDirection/useLayoutDirection.js';
209
- export { default as unstable__ChatButton } from './components/ChatButton/ChatButton.js';
210
- export { default as unstable__ChatButtonSkeleton } from './components/ChatButton/ChatButton.Skeleton.js';
211
211
  export { Text as unstable_Text } from './components/Text/Text.js';
212
212
  export { TextDirection as unstable_TextDirection } from './components/Text/TextDirection.js';
213
213
  export { default as CheckboxGroup } from './components/CheckboxGroup/CheckboxGroup.js';
@@ -33,7 +33,9 @@ function useSelection(_ref2) {
33
33
  disabled,
34
34
  onChange,
35
35
  initialSelectedItems = [],
36
- selectedItems: controlledItems
36
+ selectedItems: controlledItems,
37
+ selectAll = false,
38
+ filteredItems = []
37
39
  } = _ref2;
38
40
  const isMounted = useRef(false);
39
41
  const savedOnChange = useRef(onChange);
@@ -44,25 +46,35 @@ function useSelection(_ref2) {
44
46
  if (disabled) {
45
47
  return;
46
48
  }
47
- let selectedIndex;
48
- selectedItems.forEach((selectedItem, index) => {
49
- if (isEqual(selectedItem, item)) {
50
- selectedIndex = index;
51
- }
52
- });
49
+ const allSelectableItems = filteredItems.filter(item => !item.disabled);
50
+ const disabledItemCount = filteredItems.filter(item => item.disabled).length;
53
51
  let newSelectedItems;
54
- if (selectedIndex === undefined) {
55
- newSelectedItems = selectedItems.concat(item);
56
- callOnChangeHandler({
57
- isControlled,
58
- isMounted: isMounted.current,
59
- onChangeHandlerControlled: savedOnChange.current,
60
- onChangeHandlerUncontrolled: setUncontrolledItems,
61
- selectedItems: newSelectedItems
52
+
53
+ //deselect all on click to All/indeterminate option
54
+ if (item && item.isSelectAll && selectedItems.length > 0) {
55
+ newSelectedItems = [];
56
+ }
57
+ //select all option
58
+ else if (item && item.isSelectAll && selectedItems.length == 0) {
59
+ newSelectedItems = allSelectableItems;
60
+ } else {
61
+ let selectedIndex;
62
+ selectedItems.forEach((selectedItem, index) => {
63
+ if (isEqual(selectedItem, item)) {
64
+ selectedIndex = index;
65
+ }
62
66
  });
63
- return;
67
+ if (selectedIndex === undefined) {
68
+ newSelectedItems = selectedItems.concat(item);
69
+ // checking if all items are selected then We should select mark the 'select All' option as well
70
+ if (selectAll && filteredItems.length - 1 === newSelectedItems.length + disabledItemCount) {
71
+ newSelectedItems = allSelectableItems;
72
+ }
73
+ } else {
74
+ newSelectedItems = removeAtIndex(selectedItems, selectedIndex);
75
+ newSelectedItems = newSelectedItems.filter(item => !item.isSelectAll);
76
+ }
64
77
  }
65
- newSelectedItems = removeAtIndex(selectedItems, selectedIndex);
66
78
  callOnChangeHandler({
67
79
  isControlled,
68
80
  isMounted: isMounted.current,
@@ -70,7 +82,7 @@ function useSelection(_ref2) {
70
82
  onChangeHandlerUncontrolled: setUncontrolledItems,
71
83
  selectedItems: newSelectedItems
72
84
  });
73
- }, [disabled, isControlled, selectedItems]);
85
+ }, [disabled, selectedItems, filteredItems, selectAll, isControlled]);
74
86
  const clearSelection = useCallback(() => {
75
87
  if (disabled) {
76
88
  return;
@@ -10,4 +10,4 @@ import { Ref, ForwardedRef } from 'react';
10
10
  * refs from both `React.forwardRef` and `useRef` that you would like to add to
11
11
  * the same node.
12
12
  */
13
- export declare const useMergedRefs: <T>(refs: ForwardedRef<T>[]) => Ref<T>;
13
+ export declare const useMergedRefs: <T extends unknown>(refs: ForwardedRef<T>[]) => Ref<T>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
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 PropTypes from 'prop-types';
8
+ export interface ChatButtonSkeletonProps {
9
+ /**
10
+ * Specify an optional className to add.
11
+ */
12
+ className?: string;
13
+ /**
14
+ * Specify the size of the `ChatButtonSkeleton`, from the following list of sizes:
15
+ */
16
+ size?: 'sm' | 'md' | 'lg';
17
+ }
18
+ declare const ChatButtonSkeleton: {
19
+ ({ className, size, ...rest }: ChatButtonSkeletonProps): import("react/jsx-runtime").JSX.Element;
20
+ propTypes: {
21
+ /**
22
+ * Specify an optional className to add.
23
+ */
24
+ className: PropTypes.Requireable<string>;
25
+ /**
26
+ * Specify the size of the `ChatButtonSkeleton`, from the following list of sizes:
27
+ */
28
+ size: PropTypes.Requireable<string>;
29
+ };
30
+ };
31
+ export default ChatButtonSkeleton;
@@ -45,6 +45,5 @@ ChatButtonSkeleton.propTypes = {
45
45
  */
46
46
  size: PropTypes__default["default"].oneOf(['sm', 'md', 'lg'])
47
47
  };
48
- var ChatButtonSkeleton$1 = ChatButtonSkeleton;
49
48
 
50
- exports["default"] = ChatButtonSkeleton$1;
49
+ exports["default"] = ChatButtonSkeleton;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Copyright IBM Corp. 2024
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, { type ComponentType, type FunctionComponent } from 'react';
8
+ export type ChatButtonKind = 'primary' | 'secondary' | 'danger' | 'ghost' | 'tertiary';
9
+ export type ChatButtonSize = 'sm' | 'md' | 'lg';
10
+ export interface ChatButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
11
+ /**
12
+ * Provide the contents of your Select
13
+ */
14
+ children?: React.ReactNode;
15
+ /**
16
+ * Specify an optional className to be applied to the node containing the label and the select box
17
+ */
18
+ className?: string;
19
+ /**
20
+ * Specify whether the `ChatButton` should be disabled
21
+ */
22
+ disabled?: boolean;
23
+ /**
24
+ * Specify whether the `ChatButton` should be rendered as a quick action button
25
+ */
26
+ isQuickAction?: boolean;
27
+ /**
28
+ * Specify whether the quick action `ChatButton` should be rendered as selected. This disables the input
29
+ */
30
+ isSelected?: boolean;
31
+ /**
32
+ * Specify the kind of `ChatButton` you want to create
33
+ */
34
+ kind?: ChatButtonKind;
35
+ /**
36
+ * Optional prop to specify an icon to be rendered.
37
+ * Can be a React component class
38
+ */
39
+ renderIcon?: ComponentType | FunctionComponent;
40
+ /**
41
+ * Specify the size of the `ChatButton`, from the following list of sizes:
42
+ */
43
+ size?: ChatButtonSize;
44
+ }
45
+ declare const ChatButton: React.ForwardRefExoticComponent<ChatButtonProps & React.RefAttributes<HTMLButtonElement>>;
46
+ export default ChatButton;