@carbon/react 1.63.1 → 1.64.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 +1558 -1265
- package/es/components/{Slug → AILabel}/index.js +47 -35
- package/es/components/{AiSkeleton/AiSkeletonIcon.d.ts → AISkeleton/AISkeletonIcon.d.ts} +4 -4
- package/es/components/{AiSkeleton/AiSkeletonIcon.js → AISkeleton/AISkeletonIcon.js} +5 -5
- package/es/components/{AiSkeleton/AiSkeletonPlaceholder.d.ts → AISkeleton/AISkeletonPlaceholder.d.ts} +4 -4
- package/es/components/{AiSkeleton/AiSkeletonPlaceholder.js → AISkeleton/AISkeletonPlaceholder.js} +5 -5
- package/es/components/{AiSkeleton/AiSkeletonText.d.ts → AISkeleton/AISkeletonText.d.ts} +4 -4
- package/es/components/{AiSkeleton/AiSkeletonText.js → AISkeleton/AISkeletonText.js} +3 -3
- package/es/components/AISkeleton/index.d.ts +10 -0
- package/es/components/CheckboxGroup/CheckboxGroup.js +1 -1
- package/es/components/ComboBox/ComboBox.d.ts +21 -6
- package/es/components/ComboBox/ComboBox.js +52 -14
- package/es/components/ComposedModal/ComposedModal.js +1 -1
- package/es/components/DataTable/DataTable.js +1 -1
- package/es/components/DataTable/TableSelectRow.js +2 -1
- package/es/components/DataTable/TableToolbarSearch.js +2 -2
- package/es/components/DatePicker/DatePicker.js +65 -14
- package/es/components/DatePicker/plugins/fixEventsPlugin.js +11 -0
- package/es/components/DatePickerInput/DatePickerInput.js +1 -1
- package/es/components/Dropdown/Dropdown.d.ts +6 -4
- package/es/components/Dropdown/Dropdown.js +18 -10
- package/es/components/FluidMultiSelect/FluidMultiSelect.js +10 -6
- package/es/components/Menu/MenuItem.js +45 -63
- package/es/components/Modal/Modal.js +1 -1
- package/es/components/MultiSelect/FilterableMultiSelect.d.ts +6 -4
- package/es/components/MultiSelect/FilterableMultiSelect.js +50 -27
- package/es/components/MultiSelect/MultiSelect.d.ts +6 -4
- package/es/components/MultiSelect/MultiSelect.js +12 -8
- package/es/components/NumberInput/NumberInput.js +2 -2
- package/es/components/OverflowMenu/OverflowMenu.js +2 -1
- package/es/components/OverflowMenu/next/index.js +2 -1
- package/es/components/RadioButtonGroup/RadioButtonGroup.js +1 -1
- package/es/components/RadioTile/RadioTile.js +1 -1
- package/es/components/Select/Select.js +1 -1
- package/es/components/Tabs/Tabs.js +3 -3
- package/es/components/Tag/DismissibleTag.js +1 -1
- package/es/components/Tag/OperationalTag.js +1 -1
- package/es/components/Tag/SelectableTag.js +3 -1
- package/es/components/Tag/Tag.js +1 -1
- package/es/components/TextArea/TextArea.js +1 -1
- package/es/components/TextInput/PasswordInput.js +5 -0
- package/es/components/TextInput/TextInput.js +1 -1
- package/es/components/Tile/Tile.js +2 -2
- package/es/components/TreeView/TreeNode.d.ts +150 -0
- package/es/components/TreeView/TreeNode.js +22 -15
- package/es/components/TreeView/TreeView.d.ts +59 -0
- package/es/components/TreeView/TreeView.js +37 -23
- package/es/components/TreeView/index.d.ts +11 -0
- package/es/components/UIShell/SwitcherItem.d.ts +4 -0
- package/es/components/UIShell/SwitcherItem.js +7 -1
- package/es/index.d.ts +4 -2
- package/es/index.js +6 -6
- package/es/node_modules/@floating-ui/core/dist/floating-ui.core.mjs.js +143 -0
- package/es/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs.js +39 -0
- package/lib/components/{Slug → AILabel}/index.js +49 -37
- package/lib/components/{AiSkeleton/AiSkeletonIcon.d.ts → AISkeleton/AISkeletonIcon.d.ts} +4 -4
- package/lib/components/{AiSkeleton/AiSkeletonIcon.js → AISkeleton/AISkeletonIcon.js} +5 -5
- package/lib/components/{AiSkeleton/AiSkeletonPlaceholder.d.ts → AISkeleton/AISkeletonPlaceholder.d.ts} +4 -4
- package/lib/components/{AiSkeleton/AiSkeletonPlaceholder.js → AISkeleton/AISkeletonPlaceholder.js} +5 -5
- package/lib/components/{AiSkeleton/AiSkeletonText.d.ts → AISkeleton/AISkeletonText.d.ts} +4 -4
- package/lib/components/{AiSkeleton/AiSkeletonText.js → AISkeleton/AISkeletonText.js} +3 -3
- package/lib/components/AISkeleton/index.d.ts +10 -0
- package/lib/components/CheckboxGroup/CheckboxGroup.js +1 -1
- package/lib/components/ComboBox/ComboBox.d.ts +21 -6
- package/lib/components/ComboBox/ComboBox.js +52 -14
- package/lib/components/ComposedModal/ComposedModal.js +1 -1
- package/lib/components/DataTable/DataTable.js +2 -2
- package/lib/components/DataTable/TableSelectRow.js +2 -1
- package/lib/components/DataTable/TableToolbarSearch.js +2 -2
- package/lib/components/DatePicker/DatePicker.js +65 -14
- package/lib/components/DatePicker/plugins/fixEventsPlugin.js +11 -0
- package/lib/components/DatePickerInput/DatePickerInput.js +1 -1
- package/lib/components/Dropdown/Dropdown.d.ts +6 -4
- package/lib/components/Dropdown/Dropdown.js +18 -10
- package/lib/components/FluidMultiSelect/FluidMultiSelect.js +10 -6
- package/lib/components/Menu/MenuItem.js +44 -62
- package/lib/components/Modal/Modal.js +1 -1
- package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +6 -4
- package/lib/components/MultiSelect/FilterableMultiSelect.js +49 -26
- package/lib/components/MultiSelect/MultiSelect.d.ts +6 -4
- package/lib/components/MultiSelect/MultiSelect.js +12 -8
- package/lib/components/NumberInput/NumberInput.js +2 -2
- package/lib/components/OverflowMenu/OverflowMenu.js +2 -1
- package/lib/components/OverflowMenu/next/index.js +2 -1
- package/lib/components/RadioButtonGroup/RadioButtonGroup.js +1 -1
- package/lib/components/RadioTile/RadioTile.js +1 -1
- package/lib/components/Select/Select.js +1 -1
- package/lib/components/Tabs/Tabs.js +2 -2
- package/lib/components/Tag/DismissibleTag.js +1 -1
- package/lib/components/Tag/OperationalTag.js +1 -1
- package/lib/components/Tag/SelectableTag.js +3 -1
- package/lib/components/Tag/Tag.js +1 -1
- package/lib/components/TextArea/TextArea.js +1 -1
- package/lib/components/TextInput/PasswordInput.js +5 -0
- package/lib/components/TextInput/TextInput.js +1 -1
- package/lib/components/Tile/Tile.js +2 -2
- package/lib/components/TreeView/TreeNode.d.ts +150 -0
- package/lib/components/TreeView/TreeNode.js +24 -17
- package/lib/components/TreeView/TreeView.d.ts +59 -0
- package/lib/components/TreeView/TreeView.js +39 -25
- package/lib/components/TreeView/index.d.ts +11 -0
- package/lib/components/UIShell/SwitcherItem.d.ts +4 -0
- package/lib/components/UIShell/SwitcherItem.js +7 -1
- package/lib/index.d.ts +4 -2
- package/lib/index.js +20 -14
- package/lib/node_modules/@floating-ui/core/dist/floating-ui.core.mjs.js +148 -0
- package/lib/node_modules/@floating-ui/utils/dist/floating-ui.utils.mjs.js +47 -0
- package/package.json +4 -4
- package/scss/components/ai-label/_ai-label.scss +9 -0
- package/scss/components/ai-label/_index.scss +9 -0
- package/es/components/AiSkeleton/index.d.ts +0 -10
- package/es/components/DataTable/tools/instanceId.js +0 -20
- package/lib/components/AiSkeleton/index.d.ts +0 -10
- package/lib/components/DataTable/tools/instanceId.js +0 -24
|
@@ -173,25 +173,42 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
|
|
|
173
173
|
}
|
|
174
174
|
}, []);
|
|
175
175
|
const lastStartValue = useRef('');
|
|
176
|
+
const [calendarCloseEvent, setCalendarCloseEvent] = useState(null);
|
|
176
177
|
|
|
177
178
|
// fix datepicker deleting the selectedDate when the calendar closes
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
179
|
+
const handleCalendarClose = useCallback((selectedDates, dateStr, instance) => {
|
|
180
|
+
if (lastStartValue.current && selectedDates[0] && !startInputField.current.value) {
|
|
181
|
+
startInputField.current.value = lastStartValue.current;
|
|
182
|
+
calendarRef.current.setDate([startInputField.current.value, endInputField?.current?.value], true, calendarRef.current.config.dateFormat);
|
|
183
|
+
}
|
|
184
|
+
if (onClose) {
|
|
185
|
+
onClose(selectedDates, dateStr, instance);
|
|
186
|
+
}
|
|
187
|
+
}, [onClose]);
|
|
188
|
+
const onCalendarClose = (selectedDates, dateStr, instance, e) => {
|
|
189
|
+
if (e && e.type === 'clickOutside') {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
setCalendarCloseEvent({
|
|
193
|
+
selectedDates,
|
|
194
|
+
dateStr,
|
|
195
|
+
instance
|
|
189
196
|
});
|
|
190
197
|
};
|
|
198
|
+
useEffect(() => {
|
|
199
|
+
if (calendarCloseEvent) {
|
|
200
|
+
const {
|
|
201
|
+
selectedDates,
|
|
202
|
+
dateStr,
|
|
203
|
+
instance
|
|
204
|
+
} = calendarCloseEvent;
|
|
205
|
+
handleCalendarClose(selectedDates, dateStr, instance);
|
|
206
|
+
setCalendarCloseEvent(null);
|
|
207
|
+
}
|
|
208
|
+
}, [calendarCloseEvent, handleCalendarClose]);
|
|
191
209
|
const endInputField = useRef(null);
|
|
192
210
|
const calendarRef = useRef(null);
|
|
193
211
|
const savedOnChange = useSavedCallback(onChange);
|
|
194
|
-
const savedOnClose = useSavedCallback(datePickerType === 'range' ? onCalendarClose : onClose);
|
|
195
212
|
const savedOnOpen = useSavedCallback(onOpen);
|
|
196
213
|
const datePickerClasses = cx(`${prefix}--date-picker`, {
|
|
197
214
|
[`${prefix}--date-picker--short`]: short,
|
|
@@ -309,6 +326,7 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
|
|
|
309
326
|
} = endInputField;
|
|
310
327
|
const flatpickerconfig = {
|
|
311
328
|
inline: inline ?? false,
|
|
329
|
+
onClose: onCalendarClose,
|
|
312
330
|
disableMobile: true,
|
|
313
331
|
defaultDate: value,
|
|
314
332
|
closeOnSelect: closeOnSelect,
|
|
@@ -343,7 +361,6 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
|
|
|
343
361
|
savedOnChange(...arguments);
|
|
344
362
|
}
|
|
345
363
|
},
|
|
346
|
-
onClose: savedOnClose,
|
|
347
364
|
onReady: onHook,
|
|
348
365
|
onMonthChange: onHook,
|
|
349
366
|
onYearChange: onHook,
|
|
@@ -440,7 +457,7 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
|
|
|
440
457
|
}
|
|
441
458
|
};
|
|
442
459
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
443
|
-
}, [savedOnChange,
|
|
460
|
+
}, [savedOnChange, savedOnOpen, readOnly, closeOnSelect, hasInput]);
|
|
444
461
|
|
|
445
462
|
// this hook allows consumers to access the flatpickr calendar
|
|
446
463
|
// instance for cases where functions like open() or close()
|
|
@@ -487,6 +504,40 @@ const DatePicker = /*#__PURE__*/React__default.forwardRef(function DatePicker(_r
|
|
|
487
504
|
calendarRef.current.set('inline', inline);
|
|
488
505
|
}
|
|
489
506
|
}, [inline]);
|
|
507
|
+
useEffect(() => {
|
|
508
|
+
//when value prop is set to empty, this clears the faltpicker's calendar instance and text input
|
|
509
|
+
if (value === '') {
|
|
510
|
+
calendarRef.current?.clear();
|
|
511
|
+
if (startInputField.current) {
|
|
512
|
+
startInputField.current.value = '';
|
|
513
|
+
}
|
|
514
|
+
if (endInputField.current) {
|
|
515
|
+
endInputField.current.value = '';
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}, [value]);
|
|
519
|
+
useEffect(() => {
|
|
520
|
+
const handleMouseDown = event => {
|
|
521
|
+
if (calendarRef.current && calendarRef.current.isOpen && !calendarRef.current.calendarContainer.contains(event.target) && !startInputField.current.contains(event.target) && !endInputField.current?.contains(event.target)) {
|
|
522
|
+
// Close the calendar immediately on mousedown
|
|
523
|
+
closeCalendar();
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
const closeCalendar = event => {
|
|
527
|
+
calendarRef.current.close();
|
|
528
|
+
// Remove focus from endDate calendar input
|
|
529
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
530
|
+
document.activeElement.blur();
|
|
531
|
+
}
|
|
532
|
+
onCalendarClose(calendarRef.current.selectedDates, '', calendarRef.current, {
|
|
533
|
+
type: 'clickOutside'
|
|
534
|
+
});
|
|
535
|
+
};
|
|
536
|
+
document.addEventListener('mousedown', handleMouseDown, true);
|
|
537
|
+
return () => {
|
|
538
|
+
document.removeEventListener('mousedown', handleMouseDown, true);
|
|
539
|
+
};
|
|
540
|
+
}, [calendarRef, startInputField, endInputField, onCalendarClose]);
|
|
490
541
|
useEffect(() => {
|
|
491
542
|
if (calendarRef?.current?.set) {
|
|
492
543
|
if (value !== undefined) {
|
|
@@ -18,6 +18,15 @@ var carbonFlatpickrFixEventsPlugin = (config => fp => {
|
|
|
18
18
|
inputTo,
|
|
19
19
|
lastStartValue
|
|
20
20
|
} = config;
|
|
21
|
+
/**
|
|
22
|
+
* Handles `click` outside to close calendar
|
|
23
|
+
*/
|
|
24
|
+
const handleClickOutside = event => {
|
|
25
|
+
if (!fp.isOpen || fp.calendarContainer.contains(event.target) || event.target === inputFrom || event.target === inputTo) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
fp.close();
|
|
29
|
+
};
|
|
21
30
|
/**
|
|
22
31
|
* Handles `keydown` event.
|
|
23
32
|
*/
|
|
@@ -111,6 +120,7 @@ var carbonFlatpickrFixEventsPlugin = (config => fp => {
|
|
|
111
120
|
inputTo.removeEventListener('blur', handleBlur, true);
|
|
112
121
|
}
|
|
113
122
|
inputFrom.removeEventListener('keydown', handleKeydown, true);
|
|
123
|
+
document.removeEventListener('click', handleClickOutside, true);
|
|
114
124
|
};
|
|
115
125
|
|
|
116
126
|
/**
|
|
@@ -127,6 +137,7 @@ var carbonFlatpickrFixEventsPlugin = (config => fp => {
|
|
|
127
137
|
inputTo.addEventListener('keydown', handleKeydown, true);
|
|
128
138
|
inputTo.addEventListener('blur', handleBlur, true);
|
|
129
139
|
}
|
|
140
|
+
document.addEventListener('click', handleClickOutside, true);
|
|
130
141
|
};
|
|
131
142
|
|
|
132
143
|
/**
|
|
@@ -97,7 +97,7 @@ const DatePickerInput = /*#__PURE__*/React__default.forwardRef(function DatePick
|
|
|
97
97
|
|
|
98
98
|
// Slug is always size `mini`
|
|
99
99
|
let normalizedSlug;
|
|
100
|
-
if (slug && slug['type']?.displayName === '
|
|
100
|
+
if (slug && slug['type']?.displayName === 'AILabel') {
|
|
101
101
|
normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
|
|
102
102
|
size: 'mini'
|
|
103
103
|
});
|
|
@@ -36,10 +36,12 @@ export interface DropdownProps<ItemType> extends Omit<ReactAttr<HTMLDivElement>,
|
|
|
36
36
|
*/
|
|
37
37
|
disabled?: boolean;
|
|
38
38
|
/**
|
|
39
|
-
* Additional props passed to Downshift.
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* Additional props passed to Downshift.
|
|
40
|
+
*
|
|
41
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
42
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
43
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
44
|
+
* from potentially breaking changes.
|
|
43
45
|
*/
|
|
44
46
|
downshiftProps?: Partial<UseSelectProps<ItemType>>;
|
|
45
47
|
/**
|
|
@@ -19,6 +19,7 @@ import '../FluidForm/FluidForm.js';
|
|
|
19
19
|
import { FormContext } from '../FluidForm/FormContext.js';
|
|
20
20
|
import { useId } from '../../internal/useId.js';
|
|
21
21
|
import { useFloating, size, flip, autoUpdate } from '@floating-ui/react';
|
|
22
|
+
import { hide } from '../../node_modules/@floating-ui/core/dist/floating-ui.core.mjs.js';
|
|
22
23
|
import { ListBoxSize, ListBoxType } from '../ListBox/ListBoxPropTypes.js';
|
|
23
24
|
|
|
24
25
|
const {
|
|
@@ -72,7 +73,8 @@ const Dropdown = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
|
|
|
72
73
|
} = _ref;
|
|
73
74
|
const {
|
|
74
75
|
refs,
|
|
75
|
-
floatingStyles
|
|
76
|
+
floatingStyles,
|
|
77
|
+
middlewareData
|
|
76
78
|
} = useFloating(autoAlign ? {
|
|
77
79
|
placement: direction,
|
|
78
80
|
// The floating element is positioned relative to its nearest
|
|
@@ -91,15 +93,19 @@ const Dropdown = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
|
|
|
91
93
|
width: `${rects.reference.width}px`
|
|
92
94
|
});
|
|
93
95
|
}
|
|
94
|
-
}), flip()],
|
|
96
|
+
}), flip(), hide()],
|
|
95
97
|
whileElementsMounted: autoUpdate
|
|
96
98
|
} : {} // When autoAlign is turned off, floating-ui will not be used
|
|
97
99
|
);
|
|
98
100
|
useEffect(() => {
|
|
99
101
|
if (autoAlign) {
|
|
100
|
-
|
|
102
|
+
const updatedFloatingStyles = {
|
|
103
|
+
...floatingStyles,
|
|
104
|
+
visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
|
|
105
|
+
};
|
|
106
|
+
Object.keys(updatedFloatingStyles).forEach(style => {
|
|
101
107
|
if (refs.floating.current) {
|
|
102
|
-
refs.floating.current.style[style] =
|
|
108
|
+
refs.floating.current.style[style] = updatedFloatingStyles[style];
|
|
103
109
|
}
|
|
104
110
|
});
|
|
105
111
|
}
|
|
@@ -260,11 +266,11 @@ const Dropdown = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
|
|
|
260
266
|
};
|
|
261
267
|
const menuProps = useMemo(() => getMenuProps({
|
|
262
268
|
ref: autoAlign ? refs.setFloating : null
|
|
263
|
-
}), [autoAlign]);
|
|
269
|
+
}), [autoAlign, getMenuProps, refs.setFloating]);
|
|
264
270
|
|
|
265
271
|
// Slug is always size `mini`
|
|
266
272
|
let normalizedSlug;
|
|
267
|
-
if (slug && slug['type']?.displayName === '
|
|
273
|
+
if (slug && slug['type']?.displayName === 'AILabel') {
|
|
268
274
|
normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
|
|
269
275
|
size: 'mini'
|
|
270
276
|
});
|
|
@@ -360,10 +366,12 @@ Dropdown.propTypes = {
|
|
|
360
366
|
*/
|
|
361
367
|
disabled: PropTypes.bool,
|
|
362
368
|
/**
|
|
363
|
-
* Additional props passed to Downshift.
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
369
|
+
* Additional props passed to Downshift.
|
|
370
|
+
*
|
|
371
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
372
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
373
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
374
|
+
* from potentially breaking changes.
|
|
367
375
|
*/
|
|
368
376
|
downshiftProps: PropTypes.object,
|
|
369
377
|
/**
|
|
@@ -53,7 +53,8 @@ FluidMultiSelect.propTypes = {
|
|
|
53
53
|
clearSelectionText: PropTypes.string,
|
|
54
54
|
/**
|
|
55
55
|
* Provide a compare function that is used to determine the ordering of
|
|
56
|
-
* options. See 'sortItems' for more control.
|
|
56
|
+
* options. See 'sortItems' for more control. Consider declaring function
|
|
57
|
+
* with `useCallback` to prevent unnecessary re-renders.
|
|
57
58
|
*/
|
|
58
59
|
compareItems: PropTypes.func,
|
|
59
60
|
/**
|
|
@@ -65,10 +66,12 @@ FluidMultiSelect.propTypes = {
|
|
|
65
66
|
*/
|
|
66
67
|
disabled: PropTypes.bool,
|
|
67
68
|
/**
|
|
68
|
-
* Additional props passed to Downshift.
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
69
|
+
* Additional props passed to Downshift.
|
|
70
|
+
*
|
|
71
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
72
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
73
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
74
|
+
* from potentially breaking changes.
|
|
72
75
|
*/
|
|
73
76
|
downshiftProps: PropTypes.object,
|
|
74
77
|
/**
|
|
@@ -104,7 +107,8 @@ FluidMultiSelect.propTypes = {
|
|
|
104
107
|
/**
|
|
105
108
|
* Helper function passed to downshift that allows the library to render a
|
|
106
109
|
* given item to a string label. By default, it extracts the `label` field
|
|
107
|
-
* from a given item to serve as the item label in the list.
|
|
110
|
+
* from a given item to serve as the item label in the list. Consider
|
|
111
|
+
* declaring function with `useCallback` to prevent unnecessary re-renders.
|
|
108
112
|
*/
|
|
109
113
|
itemToString: PropTypes.func,
|
|
110
114
|
/**
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
9
9
|
import cx from 'classnames';
|
|
10
10
|
import PropTypes from 'prop-types';
|
|
11
|
-
import React__default, { forwardRef, useContext, useRef,
|
|
11
|
+
import React__default, { forwardRef, useState, useContext, useRef, useEffect } from 'react';
|
|
12
|
+
import { useFloating, autoUpdate, offset, useInteractions, useHover, safePolygon, FloatingFocusManager } from '@floating-ui/react';
|
|
12
13
|
import { CaretLeft, CaretRight, Checkmark } from '@carbon/icons-react';
|
|
13
14
|
import { useControllableState } from '../../internal/useControllableState.js';
|
|
14
15
|
import { useMergedRefs } from '../../internal/useMergedRefs.js';
|
|
@@ -23,9 +24,6 @@ import { match } from '../../internal/keyboard/match.js';
|
|
|
23
24
|
import { ArrowRight, Enter, Space } from '../../internal/keyboard/keys.js';
|
|
24
25
|
|
|
25
26
|
var _CaretLeft, _CaretRight;
|
|
26
|
-
const hoverIntentDelay = 150; // in ms
|
|
27
|
-
const leaveIntentDelay = 300; // in ms
|
|
28
|
-
|
|
29
27
|
const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
30
28
|
let {
|
|
31
29
|
children,
|
|
@@ -38,19 +36,37 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
38
36
|
shortcut,
|
|
39
37
|
...rest
|
|
40
38
|
} = _ref;
|
|
39
|
+
const [submenuOpen, setSubmenuOpen] = useState(false);
|
|
40
|
+
const [rtl, setRtl] = useState(false);
|
|
41
|
+
const {
|
|
42
|
+
refs,
|
|
43
|
+
floatingStyles,
|
|
44
|
+
context: floatingContext
|
|
45
|
+
} = useFloating({
|
|
46
|
+
open: submenuOpen,
|
|
47
|
+
onOpenChange: setSubmenuOpen,
|
|
48
|
+
placement: rtl ? 'left-start' : 'right-start',
|
|
49
|
+
whileElementsMounted: autoUpdate,
|
|
50
|
+
middleware: [offset({
|
|
51
|
+
mainAxis: -6,
|
|
52
|
+
crossAxis: -6
|
|
53
|
+
})]
|
|
54
|
+
});
|
|
55
|
+
const {
|
|
56
|
+
getReferenceProps,
|
|
57
|
+
getFloatingProps
|
|
58
|
+
} = useInteractions([useHover(floatingContext, {
|
|
59
|
+
delay: 100,
|
|
60
|
+
enabled: true,
|
|
61
|
+
handleClose: safePolygon({
|
|
62
|
+
requireIntent: false
|
|
63
|
+
})
|
|
64
|
+
})]);
|
|
41
65
|
const prefix = usePrefix();
|
|
42
66
|
const context = useContext(MenuContext);
|
|
43
67
|
const menuItem = useRef(null);
|
|
44
|
-
const ref = useMergedRefs([forwardRef, menuItem]);
|
|
45
|
-
const [boundaries, setBoundaries] = useState({
|
|
46
|
-
x: -1,
|
|
47
|
-
y: -1
|
|
48
|
-
});
|
|
49
|
-
const [rtl, setRtl] = useState(false);
|
|
68
|
+
const ref = useMergedRefs([forwardRef, menuItem, refs.setReference]);
|
|
50
69
|
const hasChildren = Boolean(children);
|
|
51
|
-
const [submenuOpen, setSubmenuOpen] = useState(false);
|
|
52
|
-
const hoverIntentTimeout = useRef(null);
|
|
53
|
-
const leaveIntentTimeout = useRef(null);
|
|
54
70
|
const isDisabled = disabled && !hasChildren;
|
|
55
71
|
const isDanger = kind === 'danger' && !hasChildren;
|
|
56
72
|
function registerItem() {
|
|
@@ -66,31 +82,10 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
66
82
|
if (!menuItem.current) {
|
|
67
83
|
return;
|
|
68
84
|
}
|
|
69
|
-
const {
|
|
70
|
-
x,
|
|
71
|
-
y,
|
|
72
|
-
width,
|
|
73
|
-
height
|
|
74
|
-
} = menuItem.current.getBoundingClientRect();
|
|
75
|
-
if (rtl) {
|
|
76
|
-
setBoundaries({
|
|
77
|
-
x: [-x, x - width],
|
|
78
|
-
y: [y, y + height]
|
|
79
|
-
});
|
|
80
|
-
} else {
|
|
81
|
-
setBoundaries({
|
|
82
|
-
x: [x, x + width],
|
|
83
|
-
y: [y, y + height]
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
85
|
setSubmenuOpen(true);
|
|
87
86
|
}
|
|
88
87
|
function closeSubmenu() {
|
|
89
88
|
setSubmenuOpen(false);
|
|
90
|
-
setBoundaries({
|
|
91
|
-
x: -1,
|
|
92
|
-
y: -1
|
|
93
|
-
});
|
|
94
89
|
}
|
|
95
90
|
function handleClick(e) {
|
|
96
91
|
if (!isDisabled) {
|
|
@@ -104,27 +99,6 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
104
99
|
}
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
|
-
function handleMouseEnter() {
|
|
108
|
-
if (leaveIntentTimeout.current) {
|
|
109
|
-
// When mouse reenters before closing keep sub menu open
|
|
110
|
-
clearTimeout(leaveIntentTimeout.current);
|
|
111
|
-
leaveIntentTimeout.current = null;
|
|
112
|
-
}
|
|
113
|
-
hoverIntentTimeout.current = setTimeout(() => {
|
|
114
|
-
openSubmenu();
|
|
115
|
-
}, hoverIntentDelay);
|
|
116
|
-
}
|
|
117
|
-
function handleMouseLeave() {
|
|
118
|
-
if (hoverIntentTimeout.current) {
|
|
119
|
-
clearTimeout(hoverIntentTimeout.current);
|
|
120
|
-
// Avoid closing the sub menu as soon as mouse leaves
|
|
121
|
-
// prevents accidental closure due to scroll bar
|
|
122
|
-
leaveIntentTimeout.current = setTimeout(() => {
|
|
123
|
-
closeSubmenu();
|
|
124
|
-
menuItem.current?.focus();
|
|
125
|
-
}, leaveIntentDelay);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
102
|
function handleKeyDown(e) {
|
|
129
103
|
if (hasChildren && match(e, ArrowRight)) {
|
|
130
104
|
openSubmenu();
|
|
@@ -169,7 +143,18 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
169
143
|
});
|
|
170
144
|
}
|
|
171
145
|
}, [iconsAllowed, IconElement, context.state.hasIcons, context]);
|
|
172
|
-
|
|
146
|
+
useEffect(() => {
|
|
147
|
+
Object.keys(floatingStyles).forEach(style => {
|
|
148
|
+
if (refs.floating.current && style !== 'position') {
|
|
149
|
+
refs.floating.current.style[style] = floatingStyles[style];
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}, [floatingStyles, refs.floating]);
|
|
153
|
+
return /*#__PURE__*/React__default.createElement(FloatingFocusManager, {
|
|
154
|
+
context: floatingContext,
|
|
155
|
+
order: ['reference', 'floating'],
|
|
156
|
+
modal: false
|
|
157
|
+
}, /*#__PURE__*/React__default.createElement("li", _extends({
|
|
173
158
|
role: "menuitem"
|
|
174
159
|
}, rest, {
|
|
175
160
|
ref: ref,
|
|
@@ -179,10 +164,8 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
179
164
|
"aria-haspopup": hasChildren ?? undefined,
|
|
180
165
|
"aria-expanded": hasChildren ? submenuOpen : undefined,
|
|
181
166
|
onClick: handleClick,
|
|
182
|
-
onMouseEnter: hasChildren ? handleMouseEnter : undefined,
|
|
183
|
-
onMouseLeave: hasChildren ? handleMouseLeave : undefined,
|
|
184
167
|
onKeyDown: handleKeyDown
|
|
185
|
-
}), /*#__PURE__*/React__default.createElement("div", {
|
|
168
|
+
}, getReferenceProps()), /*#__PURE__*/React__default.createElement("div", {
|
|
186
169
|
className: `${prefix}--menu-item__icon`
|
|
187
170
|
}, iconsAllowed && IconElement && /*#__PURE__*/React__default.createElement(IconElement, null)), /*#__PURE__*/React__default.createElement(Text, {
|
|
188
171
|
as: "div",
|
|
@@ -192,16 +175,15 @@ const MenuItem = /*#__PURE__*/forwardRef(function MenuItem(_ref, forwardRef) {
|
|
|
192
175
|
className: `${prefix}--menu-item__shortcut`
|
|
193
176
|
}, shortcut), hasChildren && /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", {
|
|
194
177
|
className: `${prefix}--menu-item__shortcut`
|
|
195
|
-
}, rtl ? _CaretLeft || (_CaretLeft = /*#__PURE__*/React__default.createElement(CaretLeft, null)) : _CaretRight || (_CaretRight = /*#__PURE__*/React__default.createElement(CaretRight, null))), /*#__PURE__*/React__default.createElement(Menu, {
|
|
178
|
+
}, rtl ? _CaretLeft || (_CaretLeft = /*#__PURE__*/React__default.createElement(CaretLeft, null)) : _CaretRight || (_CaretRight = /*#__PURE__*/React__default.createElement(CaretRight, null))), /*#__PURE__*/React__default.createElement(Menu, _extends({
|
|
196
179
|
label: label,
|
|
197
180
|
open: submenuOpen,
|
|
198
181
|
onClose: () => {
|
|
199
182
|
closeSubmenu();
|
|
200
183
|
menuItem.current?.focus();
|
|
201
184
|
},
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}, children)));
|
|
185
|
+
ref: refs.setFloating
|
|
186
|
+
}, getFloatingProps()), children))));
|
|
205
187
|
});
|
|
206
188
|
MenuItem.propTypes = {
|
|
207
189
|
/**
|
|
@@ -229,7 +229,7 @@ const Modal = /*#__PURE__*/React__default.forwardRef(function Modal(_ref, ref) {
|
|
|
229
229
|
|
|
230
230
|
// Slug is always size `sm`
|
|
231
231
|
let normalizedSlug;
|
|
232
|
-
if (slug && slug['type']?.displayName === '
|
|
232
|
+
if (slug && slug['type']?.displayName === 'AILabel') {
|
|
233
233
|
normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
|
|
234
234
|
size: 'sm'
|
|
235
235
|
});
|
|
@@ -48,10 +48,12 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
|
|
|
48
48
|
*/
|
|
49
49
|
disabled?: boolean;
|
|
50
50
|
/**
|
|
51
|
-
* Additional props passed to Downshift.
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
51
|
+
* Additional props passed to Downshift.
|
|
52
|
+
*
|
|
53
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
54
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
55
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
56
|
+
* from potentially breaking changes.
|
|
55
57
|
*/
|
|
56
58
|
downshiftProps?: UseMultipleSelectionProps<ItemType>;
|
|
57
59
|
/**
|
|
@@ -11,7 +11,7 @@ import cx from 'classnames';
|
|
|
11
11
|
import Downshift, { useCombobox, useMultipleSelection } from 'downshift';
|
|
12
12
|
import isEqual from 'react-fast-compare';
|
|
13
13
|
import PropTypes from 'prop-types';
|
|
14
|
-
import React__default, { useContext, useState, useLayoutEffect, useRef,
|
|
14
|
+
import React__default, { useContext, useState, useLayoutEffect, useRef, useMemo, useEffect } from 'react';
|
|
15
15
|
import { defaultFilterItems } from '../ComboBox/tools/filter.js';
|
|
16
16
|
import { sortingPropTypes } from './MultiSelectPropTypes.js';
|
|
17
17
|
import ListBox from '../ListBox/index.js';
|
|
@@ -164,20 +164,23 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
|
|
|
164
164
|
setPrevOpen(open);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
//
|
|
168
|
-
const sortedItems =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
167
|
+
// memoize sorted items to reduce unnecessary expensive sort on rerender
|
|
168
|
+
const sortedItems = useMemo(() => {
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
170
|
+
return sortItems(filterItems(items, {
|
|
171
|
+
itemToString,
|
|
172
|
+
inputValue
|
|
173
|
+
}), {
|
|
174
|
+
selectedItems: {
|
|
175
|
+
top: controlledSelectedItems,
|
|
176
|
+
fixed: [],
|
|
177
|
+
'top-after-reopen': topItems
|
|
178
|
+
}[selectionFeedback],
|
|
179
|
+
itemToString,
|
|
180
|
+
compareItems,
|
|
181
|
+
locale
|
|
182
|
+
});
|
|
183
|
+
}, [items, inputValue, controlledSelectedItems, topItems, selectionFeedback, itemToString, compareItems, locale]);
|
|
181
184
|
const inline = type === 'inline';
|
|
182
185
|
const showWarning = !invalid && warn;
|
|
183
186
|
const wrapperClasses = cx(`${prefix}--multi-select__wrapper`, `${prefix}--multi-select--filterable__wrapper`, `${prefix}--list-box__wrapper`, containerClassName, {
|
|
@@ -217,9 +220,15 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
|
|
|
217
220
|
setTopItems(controlledSelectedItems);
|
|
218
221
|
}
|
|
219
222
|
}, [controlledSelectedItems, isOpen, setTopItems]);
|
|
223
|
+
const validateHighlightFocus = () => {
|
|
224
|
+
if (controlledSelectedItems.length > 0) {
|
|
225
|
+
setHighlightedIndex(0);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
220
228
|
function handleMenuChange(forceIsOpen) {
|
|
221
229
|
const nextIsOpen = forceIsOpen ?? !isOpen;
|
|
222
230
|
setIsOpen(nextIsOpen);
|
|
231
|
+
validateHighlightFocus();
|
|
223
232
|
if (onMenuChange) {
|
|
224
233
|
onMenuChange(nextIsOpen);
|
|
225
234
|
}
|
|
@@ -237,9 +246,8 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
|
|
|
237
246
|
} = useCombobox({
|
|
238
247
|
isOpen,
|
|
239
248
|
items: sortedItems,
|
|
249
|
+
// defaultHighlightedIndex: 0, // after selection, highlight the first item.
|
|
240
250
|
itemToString,
|
|
241
|
-
defaultHighlightedIndex: 0,
|
|
242
|
-
// after selection, highlight the first item.
|
|
243
251
|
id,
|
|
244
252
|
labelId,
|
|
245
253
|
menuId,
|
|
@@ -284,24 +292,37 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
|
|
|
284
292
|
return changes;
|
|
285
293
|
case FunctionToggleMenu:
|
|
286
294
|
case ToggleButtonClick:
|
|
295
|
+
validateHighlightFocus();
|
|
287
296
|
if (changes.isOpen && !changes.selectedItem) {
|
|
288
297
|
return {
|
|
289
|
-
...changes
|
|
290
|
-
highlightedIndex: 0
|
|
298
|
+
...changes
|
|
291
299
|
};
|
|
292
300
|
}
|
|
293
|
-
return
|
|
301
|
+
return {
|
|
302
|
+
...changes,
|
|
303
|
+
highlightedIndex: null
|
|
304
|
+
};
|
|
294
305
|
case InputChange:
|
|
295
306
|
if (onInputValueChange) {
|
|
296
307
|
onInputValueChange(changes.inputValue);
|
|
297
308
|
}
|
|
298
309
|
setInputValue(changes.inputValue ?? '');
|
|
299
310
|
setIsOpen(true);
|
|
300
|
-
return
|
|
311
|
+
return {
|
|
312
|
+
...changes,
|
|
313
|
+
highlightedIndex: 0
|
|
314
|
+
};
|
|
301
315
|
case InputClick:
|
|
316
|
+
validateHighlightFocus();
|
|
317
|
+
if (changes.isOpen && !changes.selectedItem) {
|
|
318
|
+
return {
|
|
319
|
+
...changes
|
|
320
|
+
};
|
|
321
|
+
}
|
|
302
322
|
return {
|
|
303
323
|
...changes,
|
|
304
|
-
isOpen: false
|
|
324
|
+
isOpen: false,
|
|
325
|
+
highlightedIndex: null
|
|
305
326
|
};
|
|
306
327
|
case MenuMouseLeave:
|
|
307
328
|
return {
|
|
@@ -385,7 +406,7 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
|
|
|
385
406
|
|
|
386
407
|
// Slug is always size `mini`
|
|
387
408
|
let normalizedSlug;
|
|
388
|
-
if (slug && slug['type']?.displayName === '
|
|
409
|
+
if (slug && slug['type']?.displayName === 'AILabel') {
|
|
389
410
|
normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
|
|
390
411
|
size: 'mini'
|
|
391
412
|
});
|
|
@@ -622,10 +643,12 @@ FilterableMultiSelect.propTypes = {
|
|
|
622
643
|
*/
|
|
623
644
|
disabled: PropTypes.bool,
|
|
624
645
|
/**
|
|
625
|
-
* Additional props passed to Downshift.
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
646
|
+
* Additional props passed to Downshift.
|
|
647
|
+
*
|
|
648
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
649
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
650
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
651
|
+
* from potentially breaking changes.
|
|
629
652
|
*/
|
|
630
653
|
// @ts-ignore
|
|
631
654
|
downshiftProps: PropTypes.shape(Downshift.propTypes),
|
|
@@ -42,10 +42,12 @@ export interface MultiSelectProps<ItemType> extends MultiSelectSortingProps<Item
|
|
|
42
42
|
*/
|
|
43
43
|
disabled?: ListBoxProps['disabled'];
|
|
44
44
|
/**
|
|
45
|
-
* Additional props passed to Downshift.
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
45
|
+
* Additional props passed to Downshift.
|
|
46
|
+
*
|
|
47
|
+
* **Use with caution:** anything you define here overrides the components'
|
|
48
|
+
* internal handling of that prop. Downshift APIs and internals are subject to
|
|
49
|
+
* change, and in some cases they can not be shimmed by Carbon to shield you
|
|
50
|
+
* from potentially breaking changes.
|
|
49
51
|
*/
|
|
50
52
|
downshiftProps?: Partial<UseSelectProps<ItemType>>;
|
|
51
53
|
/**
|