@carbon/react 1.65.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.
- package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +964 -888
- package/es/components/ChatButton/ChatButton.Skeleton.d.ts +31 -0
- package/es/components/ChatButton/ChatButton.Skeleton.js +1 -2
- package/es/components/ChatButton/ChatButton.d.ts +46 -0
- package/es/components/ChatButton/ChatButton.js +3 -3
- package/es/components/ChatButton/index.d.ts +12 -0
- package/es/components/Checkbox/index.js +10 -0
- package/es/components/ComboBox/ComboBox.js +12 -7
- package/es/components/ComboButton/index.js +8 -3
- package/es/components/ComposedModal/index.d.ts +2 -0
- package/es/components/DataTable/TableSlugRow.d.ts +1 -0
- package/es/components/DataTable/TableSlugRow.js +1 -0
- package/es/components/Grid/Column.js +3 -3
- package/es/components/ListBox/ListBoxMenuItem.d.ts +10 -1
- package/es/components/ListBox/next/ListBoxSelection.d.ts +106 -0
- package/es/components/ListBox/next/ListBoxSelection.js +12 -16
- package/es/components/ListBox/next/ListBoxTrigger.d.ts +31 -0
- package/es/components/ListBox/next/ListBoxTrigger.js +2 -4
- package/es/components/ListBox/next/index.d.ts +8 -0
- package/es/components/MultiSelect/FilterableMultiSelect.js +12 -14
- package/es/components/MultiSelect/MultiSelect.js +64 -49
- package/es/components/MultiSelect/tools/sorting.js +5 -8
- package/es/components/OverflowMenu/OverflowMenu.js +1 -1
- package/es/components/Popover/index.js +21 -4
- package/es/components/TreeView/TreeNode.js +41 -33
- package/es/components/TreeView/TreeView.d.ts +5 -3
- package/es/index.js +2 -2
- package/es/internal/Selection.js +30 -18
- package/es/internal/useMergedRefs.d.ts +1 -1
- package/lib/components/ChatButton/ChatButton.Skeleton.d.ts +31 -0
- package/lib/components/ChatButton/ChatButton.Skeleton.js +1 -2
- package/lib/components/ChatButton/ChatButton.d.ts +46 -0
- package/lib/components/ChatButton/ChatButton.js +4 -4
- package/lib/components/ChatButton/index.d.ts +12 -0
- package/lib/components/Checkbox/index.js +19 -0
- package/lib/components/ComboBox/ComboBox.js +12 -7
- package/lib/components/ComboButton/index.js +8 -3
- package/lib/components/ComposedModal/index.d.ts +2 -0
- package/lib/components/DataTable/TableSlugRow.d.ts +1 -0
- package/lib/components/DataTable/TableSlugRow.js +1 -0
- package/lib/components/Grid/Column.js +3 -3
- package/lib/components/ListBox/ListBoxMenuItem.d.ts +10 -1
- package/lib/components/ListBox/next/ListBoxSelection.d.ts +106 -0
- package/lib/components/ListBox/next/ListBoxSelection.js +11 -16
- package/lib/components/ListBox/next/ListBoxTrigger.d.ts +31 -0
- package/lib/components/ListBox/next/ListBoxTrigger.js +2 -4
- package/lib/components/ListBox/next/index.d.ts +8 -0
- package/lib/components/MultiSelect/FilterableMultiSelect.js +12 -14
- package/lib/components/MultiSelect/MultiSelect.js +63 -48
- package/lib/components/MultiSelect/tools/sorting.js +5 -8
- package/lib/components/OverflowMenu/OverflowMenu.js +1 -1
- package/lib/components/Popover/index.js +21 -4
- package/lib/components/TreeView/TreeNode.js +41 -33
- package/lib/components/TreeView/TreeView.d.ts +5 -3
- package/lib/index.js +4 -4
- package/lib/internal/Selection.js +30 -18
- package/lib/internal/useMergedRefs.d.ts +1 -1
- package/package.json +23 -20
|
@@ -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
|
|
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
|
-
|
|
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] =
|
|
163
|
+
refs.floating.current.style[style] = updatedFloatingStyles[style];
|
|
150
164
|
}
|
|
151
165
|
});
|
|
152
166
|
}
|
|
153
167
|
}, [autoAlign, floatingStyles, refs.floating, middlewareData, open]);
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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:
|
|
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:
|
|
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(
|
|
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
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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] =
|
|
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
|
-
|
|
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,
|
|
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.
|
|
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?.
|
|
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",
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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?: (
|
|
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';
|
package/es/internal/Selection.js
CHANGED
|
@@ -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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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
|
-
|
|
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,
|
|
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;
|
|
@@ -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;
|