@carbon/react 1.63.1 → 1.63.2

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 (28) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +1022 -1092
  2. package/es/components/ComboBox/ComboBox.d.ts +21 -6
  3. package/es/components/ComboBox/ComboBox.js +48 -10
  4. package/es/components/DataTable/TableSelectRow.js +2 -1
  5. package/es/components/DataTable/TableToolbarSearch.js +2 -2
  6. package/es/components/DatePicker/DatePicker.js +65 -14
  7. package/es/components/DatePicker/plugins/fixEventsPlugin.js +11 -0
  8. package/es/components/Dropdown/Dropdown.d.ts +6 -4
  9. package/es/components/Dropdown/Dropdown.js +6 -4
  10. package/es/components/FluidMultiSelect/FluidMultiSelect.js +6 -4
  11. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +6 -4
  12. package/es/components/MultiSelect/FilterableMultiSelect.js +6 -4
  13. package/es/components/MultiSelect/MultiSelect.d.ts +6 -4
  14. package/es/components/MultiSelect/MultiSelect.js +6 -4
  15. package/lib/components/ComboBox/ComboBox.d.ts +21 -6
  16. package/lib/components/ComboBox/ComboBox.js +48 -10
  17. package/lib/components/DataTable/TableSelectRow.js +2 -1
  18. package/lib/components/DataTable/TableToolbarSearch.js +2 -2
  19. package/lib/components/DatePicker/DatePicker.js +65 -14
  20. package/lib/components/DatePicker/plugins/fixEventsPlugin.js +11 -0
  21. package/lib/components/Dropdown/Dropdown.d.ts +6 -4
  22. package/lib/components/Dropdown/Dropdown.js +6 -4
  23. package/lib/components/FluidMultiSelect/FluidMultiSelect.js +6 -4
  24. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +6 -4
  25. package/lib/components/MultiSelect/FilterableMultiSelect.js +6 -4
  26. package/lib/components/MultiSelect/MultiSelect.d.ts +6 -4
  27. package/lib/components/MultiSelect/MultiSelect.js +6 -4
  28. package/package.json +2 -2
@@ -4,8 +4,8 @@
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import { UseComboboxProps } from 'downshift';
8
- import { type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithRef, type InputHTMLAttributes, type MouseEvent } from 'react';
7
+ import { UseComboboxProps, UseComboboxActions } from 'downshift';
8
+ import React, { type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithRef, type InputHTMLAttributes, type MouseEvent } from 'react';
9
9
  import { ListBoxSize } from '../ListBox';
10
10
  import { TranslateWithId } from '../../types/common';
11
11
  type ExcludedAttributes = 'id' | 'onChange' | 'onClick' | 'type' | 'size';
@@ -57,12 +57,27 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
57
57
  */
58
58
  disabled?: boolean;
59
59
  /**
60
- * Additional props passed to Downshift. Use with caution: anything you define
61
- * here overrides the components' internal handling of that prop. Downshift
62
- * internals are subject to change, and in some cases they can not be shimmed
63
- * to shield you from potentially breaking changes.
60
+ * Additional props passed to Downshift.
61
+ *
62
+ * **Use with caution:** anything you define here overrides the components'
63
+ * internal handling of that prop. Downshift APIs and internals are subject to
64
+ * change, and in some cases they can not be shimmed by Carbon to shield you
65
+ * from potentially breaking changes.
66
+ *
64
67
  */
65
68
  downshiftProps?: Partial<UseComboboxProps<ItemType>>;
69
+ /**
70
+ * Provide a ref that will be mutated to contain an object of downshift
71
+ * action functions. These can be called to change the internal state of the
72
+ * downshift useCombobox hook.
73
+ *
74
+ * **Use with caution:** calling these actions modifies the internal state of
75
+ * downshift. It may conflict with or override the state management used within
76
+ * Combobox. Downshift APIs and internals are subject to change, and in some
77
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
78
+ * changes.
79
+ */
80
+ downshiftActions?: React.MutableRefObject<UseComboboxActions<ItemType> | undefined>;
66
81
  /**
67
82
  * Provide helper text that is used alongside the control label for
68
83
  * additional help
@@ -99,6 +99,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
99
99
  className: containerClassName,
100
100
  direction = 'bottom',
101
101
  disabled = false,
102
+ downshiftActions,
102
103
  downshiftProps,
103
104
  helperText,
104
105
  id,
@@ -317,17 +318,24 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
317
318
  });
318
319
  }
319
320
  const {
321
+ // Prop getters
320
322
  getInputProps,
321
323
  getItemProps,
322
324
  getLabelProps,
323
325
  getMenuProps,
324
326
  getToggleButtonProps,
327
+ // State
325
328
  isOpen,
326
329
  highlightedIndex,
327
- selectItem,
328
330
  selectedItem,
329
- toggleMenu,
330
- setHighlightedIndex
331
+ // Actions
332
+ closeMenu,
333
+ openMenu,
334
+ reset,
335
+ selectItem,
336
+ setHighlightedIndex,
337
+ setInputValue: downshiftSetInputValue,
338
+ toggleMenu
331
339
  } = useCombobox({
332
340
  items: filterItems(items, itemToString, inputValue),
333
341
  inputValue: inputValue,
@@ -372,6 +380,22 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
372
380
  },
373
381
  ...downshiftProps
374
382
  });
383
+ useEffect(() => {
384
+ // Used to expose the downshift actions to consumers for use with downshiftProps
385
+ // An odd pattern, here we mutate the value stored in the ref provided from the consumer.
386
+ // A riff of https://gist.github.com/gaearon/1a018a023347fe1c2476073330cc5509
387
+ if (downshiftActions) {
388
+ downshiftActions.current = {
389
+ closeMenu,
390
+ openMenu,
391
+ reset,
392
+ selectItem,
393
+ setHighlightedIndex,
394
+ setInputValue: downshiftSetInputValue,
395
+ toggleMenu
396
+ };
397
+ }
398
+ }, [closeMenu, openMenu, reset, selectItem, setHighlightedIndex, downshiftSetInputValue, toggleMenu]);
375
399
  const buttonProps = getToggleButtonProps({
376
400
  disabled: disabled || readOnly,
377
401
  onClick: handleToggleClick(isOpen),
@@ -444,9 +468,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
444
468
  }, getInputProps({
445
469
  'aria-controls': isOpen ? undefined : menuProps.id,
446
470
  placeholder,
447
- ref: {
448
- ...mergeRefs(textInput, ref)
449
- },
471
+ ref: mergeRefs(textInput, ref),
450
472
  onKeyDown: event => {
451
473
  if (match(event, Space)) {
452
474
  event.stopPropagation();
@@ -586,12 +608,28 @@ ComboBox.propTypes = {
586
608
  */
587
609
  disabled: PropTypes.bool,
588
610
  /**
589
- * Additional props passed to Downshift. Use with caution: anything you define
590
- * here overrides the components' internal handling of that prop. Downshift
591
- * internals are subject to change, and in some cases they can not be shimmed
592
- * to shield you from potentially breaking changes.
611
+ * Additional props passed to Downshift.
612
+ *
613
+ * **Use with caution:** anything you define here overrides the components'
614
+ * internal handling of that prop. Downshift APIs and internals are subject to
615
+ * change, and in some cases they can not be shimmed by Carbon to shield you
616
+ * from potentially breaking changes.
593
617
  */
594
618
  downshiftProps: PropTypes.object,
619
+ /**
620
+ * Provide a ref that will be mutated to contain an object of downshift
621
+ * action functions. These can be called to change the internal state of the
622
+ * downshift useCombobox hook.
623
+ *
624
+ * **Use with caution:** calling these actions modifies the internal state of
625
+ * downshift. It may conflict with or override the state management used within
626
+ * Combobox. Downshift APIs and internals are subject to change, and in some
627
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
628
+ * changes.
629
+ */
630
+ downshiftActions: PropTypes.exact({
631
+ current: PropTypes.any
632
+ }),
595
633
  /**
596
634
  * Provide helper text that is used alongside the control label for
597
635
  * additional help
@@ -7,10 +7,11 @@
7
7
 
8
8
  import { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
9
  import PropTypes from 'prop-types';
10
- import React__default, { useId } from 'react';
10
+ import React__default from 'react';
11
11
  import cx from 'classnames';
12
12
  import InlineCheckbox from '../InlineCheckbox/InlineCheckbox.js';
13
13
  import RadioButton from '../RadioButton/RadioButton.js';
14
+ import { useId } from '../../internal/useId.js';
14
15
  import { usePrefix } from '../../internal/usePrefix.js';
15
16
  import deprecate from '../../prop-types/deprecate.js';
16
17
 
@@ -54,7 +54,7 @@ const TableToolbarSearch = _ref => {
54
54
  const [expandedState, setExpandedState] = useState(Boolean(defaultExpanded || defaultValue));
55
55
  const expanded = controlled ? expandedProp : expandedState;
56
56
  const [value, setValue] = useState(defaultValue || '');
57
- const uniqueId = useId();
57
+ const uniqueId = useId('table-toolbar-search');
58
58
  const [focusTarget, setFocusTarget] = useState(null);
59
59
  const prefix = usePrefix();
60
60
  useEffect(() => {
@@ -101,7 +101,7 @@ const TableToolbarSearch = _ref => {
101
101
  disabled: disabled,
102
102
  className: searchClasses,
103
103
  value: value,
104
- id: typeof id !== 'undefined' ? id : `table-toolbar-search-${uniqueId.toString()}`,
104
+ id: typeof id !== 'undefined' ? id : uniqueId,
105
105
  labelText: labelText || t('carbon.table.toolbar.search.label'),
106
106
  placeholder: placeholder || t('carbon.table.toolbar.search.placeholder'),
107
107
  onChange: onChange,
@@ -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 onCalendarClose = (selectedDates, dateStr) => {
179
- endInputField?.current?.focus();
180
- calendarRef?.current?.calendarContainer?.classList.remove('open');
181
- setTimeout(() => {
182
- if (lastStartValue.current && selectedDates[0] && !startInputField.current.value) {
183
- startInputField.current.value = lastStartValue.current;
184
- calendarRef.current.setDate([startInputField.current.value, endInputField?.current?.value], true, calendarRef.current.config.dateFormat);
185
- }
186
- if (onClose) {
187
- onClose(calendarRef.current.selectedDates, dateStr, calendarRef.current);
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, savedOnClose, savedOnOpen, readOnly, closeOnSelect, hasInput]);
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
  /**
@@ -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. Use with caution: anything you define
40
- * here overrides the components' internal handling of that prop. Downshift
41
- * internals are subject to change, and in some cases they can not be shimmed
42
- * to shield you from potentially breaking changes.
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
  /**
@@ -360,10 +360,12 @@ Dropdown.propTypes = {
360
360
  */
361
361
  disabled: PropTypes.bool,
362
362
  /**
363
- * Additional props passed to Downshift. Use with caution: anything you define
364
- * here overrides the components' internal handling of that prop. Downshift
365
- * internals are subject to change, and in some cases they can not be shimmed
366
- * to shield you from potentially breaking changes.
363
+ * Additional props passed to Downshift.
364
+ *
365
+ * **Use with caution:** anything you define here overrides the components'
366
+ * internal handling of that prop. Downshift APIs and internals are subject to
367
+ * change, and in some cases they can not be shimmed by Carbon to shield you
368
+ * from potentially breaking changes.
367
369
  */
368
370
  downshiftProps: PropTypes.object,
369
371
  /**
@@ -65,10 +65,12 @@ FluidMultiSelect.propTypes = {
65
65
  */
66
66
  disabled: PropTypes.bool,
67
67
  /**
68
- * Additional props passed to Downshift. Use with caution: anything you define
69
- * here overrides the components' internal handling of that prop. Downshift
70
- * internals are subject to change, and in some cases they can not be shimmed
71
- * to shield you from potentially breaking changes.
68
+ * Additional props passed to Downshift.
69
+ *
70
+ * **Use with caution:** anything you define here overrides the components'
71
+ * internal handling of that prop. Downshift APIs and internals are subject to
72
+ * change, and in some cases they can not be shimmed by Carbon to shield you
73
+ * from potentially breaking changes.
72
74
  */
73
75
  downshiftProps: PropTypes.object,
74
76
  /**
@@ -48,10 +48,12 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
48
48
  */
49
49
  disabled?: boolean;
50
50
  /**
51
- * Additional props passed to Downshift. Use with caution: anything you define
52
- * here overrides the components' internal handling of that prop. Downshift
53
- * internals are subject to change, and in some cases they can not be shimmed
54
- * to shield you from potentially breaking changes.
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
  /**
@@ -622,10 +622,12 @@ FilterableMultiSelect.propTypes = {
622
622
  */
623
623
  disabled: PropTypes.bool,
624
624
  /**
625
- * Additional props passed to Downshift. Use with caution: anything you define
626
- * here overrides the components' internal handling of that prop. Downshift
627
- * internals are subject to change, and in some cases they can not be shimmed
628
- * to shield you from potentially breaking changes.
625
+ * Additional props passed to Downshift.
626
+ *
627
+ * **Use with caution:** anything you define here overrides the components'
628
+ * internal handling of that prop. Downshift APIs and internals are subject to
629
+ * change, and in some cases they can not be shimmed by Carbon to shield you
630
+ * from potentially breaking changes.
629
631
  */
630
632
  // @ts-ignore
631
633
  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. Use with caution: anything you define
46
- * here overrides the components' internal handling of that prop. Downshift
47
- * internals are subject to change, and in some cases they can not be shimmed
48
- * to shield you from potentially breaking changes.
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
  /**
@@ -518,10 +518,12 @@ MultiSelect.propTypes = {
518
518
  */
519
519
  disabled: PropTypes.bool,
520
520
  /**
521
- * Additional props passed to Downshift. Use with caution: anything you define
522
- * here overrides the components' internal handling of that prop. Downshift
523
- * internals are subject to change, and in some cases they can not be shimmed
524
- * to shield you from potentially breaking changes.
521
+ * Additional props passed to Downshift.
522
+ *
523
+ * **Use with caution:** anything you define here overrides the components'
524
+ * internal handling of that prop. Downshift APIs and internals are subject to
525
+ * change, and in some cases they can not be shimmed by Carbon to shield you
526
+ * from potentially breaking changes.
525
527
  */
526
528
  downshiftProps: PropTypes.object,
527
529
  /**
@@ -4,8 +4,8 @@
4
4
  * This source code is licensed under the Apache-2.0 license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import { UseComboboxProps } from 'downshift';
8
- import { type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithRef, type InputHTMLAttributes, type MouseEvent } from 'react';
7
+ import { UseComboboxProps, UseComboboxActions } from 'downshift';
8
+ import React, { type ReactNode, type ComponentType, type ReactElement, type RefAttributes, type PropsWithChildren, type PropsWithRef, type InputHTMLAttributes, type MouseEvent } from 'react';
9
9
  import { ListBoxSize } from '../ListBox';
10
10
  import { TranslateWithId } from '../../types/common';
11
11
  type ExcludedAttributes = 'id' | 'onChange' | 'onClick' | 'type' | 'size';
@@ -57,12 +57,27 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
57
57
  */
58
58
  disabled?: boolean;
59
59
  /**
60
- * Additional props passed to Downshift. Use with caution: anything you define
61
- * here overrides the components' internal handling of that prop. Downshift
62
- * internals are subject to change, and in some cases they can not be shimmed
63
- * to shield you from potentially breaking changes.
60
+ * Additional props passed to Downshift.
61
+ *
62
+ * **Use with caution:** anything you define here overrides the components'
63
+ * internal handling of that prop. Downshift APIs and internals are subject to
64
+ * change, and in some cases they can not be shimmed by Carbon to shield you
65
+ * from potentially breaking changes.
66
+ *
64
67
  */
65
68
  downshiftProps?: Partial<UseComboboxProps<ItemType>>;
69
+ /**
70
+ * Provide a ref that will be mutated to contain an object of downshift
71
+ * action functions. These can be called to change the internal state of the
72
+ * downshift useCombobox hook.
73
+ *
74
+ * **Use with caution:** calling these actions modifies the internal state of
75
+ * downshift. It may conflict with or override the state management used within
76
+ * Combobox. Downshift APIs and internals are subject to change, and in some
77
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
78
+ * changes.
79
+ */
80
+ downshiftActions?: React.MutableRefObject<UseComboboxActions<ItemType> | undefined>;
66
81
  /**
67
82
  * Provide helper text that is used alongside the control label for
68
83
  * additional help
@@ -109,6 +109,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
109
109
  className: containerClassName,
110
110
  direction = 'bottom',
111
111
  disabled = false,
112
+ downshiftActions,
112
113
  downshiftProps,
113
114
  helperText,
114
115
  id,
@@ -327,17 +328,24 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
327
328
  });
328
329
  }
329
330
  const {
331
+ // Prop getters
330
332
  getInputProps,
331
333
  getItemProps,
332
334
  getLabelProps,
333
335
  getMenuProps,
334
336
  getToggleButtonProps,
337
+ // State
335
338
  isOpen,
336
339
  highlightedIndex,
337
- selectItem,
338
340
  selectedItem,
339
- toggleMenu,
340
- setHighlightedIndex
341
+ // Actions
342
+ closeMenu,
343
+ openMenu,
344
+ reset,
345
+ selectItem,
346
+ setHighlightedIndex,
347
+ setInputValue: downshiftSetInputValue,
348
+ toggleMenu
341
349
  } = Downshift.useCombobox({
342
350
  items: filterItems(items, itemToString, inputValue),
343
351
  inputValue: inputValue,
@@ -382,6 +390,22 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
382
390
  },
383
391
  ...downshiftProps
384
392
  });
393
+ React.useEffect(() => {
394
+ // Used to expose the downshift actions to consumers for use with downshiftProps
395
+ // An odd pattern, here we mutate the value stored in the ref provided from the consumer.
396
+ // A riff of https://gist.github.com/gaearon/1a018a023347fe1c2476073330cc5509
397
+ if (downshiftActions) {
398
+ downshiftActions.current = {
399
+ closeMenu,
400
+ openMenu,
401
+ reset,
402
+ selectItem,
403
+ setHighlightedIndex,
404
+ setInputValue: downshiftSetInputValue,
405
+ toggleMenu
406
+ };
407
+ }
408
+ }, [closeMenu, openMenu, reset, selectItem, setHighlightedIndex, downshiftSetInputValue, toggleMenu]);
385
409
  const buttonProps = getToggleButtonProps({
386
410
  disabled: disabled || readOnly,
387
411
  onClick: handleToggleClick(isOpen),
@@ -454,9 +478,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
454
478
  }, getInputProps({
455
479
  'aria-controls': isOpen ? undefined : menuProps.id,
456
480
  placeholder,
457
- ref: {
458
- ...mergeRefs["default"](textInput, ref)
459
- },
481
+ ref: mergeRefs["default"](textInput, ref),
460
482
  onKeyDown: event => {
461
483
  if (match.match(event, keys.Space)) {
462
484
  event.stopPropagation();
@@ -596,12 +618,28 @@ ComboBox.propTypes = {
596
618
  */
597
619
  disabled: PropTypes__default["default"].bool,
598
620
  /**
599
- * Additional props passed to Downshift. Use with caution: anything you define
600
- * here overrides the components' internal handling of that prop. Downshift
601
- * internals are subject to change, and in some cases they can not be shimmed
602
- * to shield you from potentially breaking changes.
621
+ * Additional props passed to Downshift.
622
+ *
623
+ * **Use with caution:** anything you define here overrides the components'
624
+ * internal handling of that prop. Downshift APIs and internals are subject to
625
+ * change, and in some cases they can not be shimmed by Carbon to shield you
626
+ * from potentially breaking changes.
603
627
  */
604
628
  downshiftProps: PropTypes__default["default"].object,
629
+ /**
630
+ * Provide a ref that will be mutated to contain an object of downshift
631
+ * action functions. These can be called to change the internal state of the
632
+ * downshift useCombobox hook.
633
+ *
634
+ * **Use with caution:** calling these actions modifies the internal state of
635
+ * downshift. It may conflict with or override the state management used within
636
+ * Combobox. Downshift APIs and internals are subject to change, and in some
637
+ * cases they can not be shimmed by Carbon to shield you from potentially breaking
638
+ * changes.
639
+ */
640
+ downshiftActions: PropTypes__default["default"].exact({
641
+ current: PropTypes__default["default"].any
642
+ }),
605
643
  /**
606
644
  * Provide helper text that is used alongside the control label for
607
645
  * additional help
@@ -15,6 +15,7 @@ var React = require('react');
15
15
  var cx = require('classnames');
16
16
  var InlineCheckbox = require('../InlineCheckbox/InlineCheckbox.js');
17
17
  var RadioButton = require('../RadioButton/RadioButton.js');
18
+ var useId = require('../../internal/useId.js');
18
19
  var usePrefix = require('../../internal/usePrefix.js');
19
20
  var deprecate = require('../../prop-types/deprecate.js');
20
21
 
@@ -38,7 +39,7 @@ const TableSelectRow = _ref => {
38
39
  className
39
40
  } = _ref;
40
41
  const prefix = usePrefix.usePrefix();
41
- const uniqueNameId = React.useId();
42
+ const uniqueNameId = useId.useId();
42
43
  const selectionInputProps = {
43
44
  id,
44
45
  name: name ? name : uniqueNameId,
@@ -64,7 +64,7 @@ const TableToolbarSearch = _ref => {
64
64
  const [expandedState, setExpandedState] = React.useState(Boolean(defaultExpanded || defaultValue));
65
65
  const expanded = controlled ? expandedProp : expandedState;
66
66
  const [value, setValue] = React.useState(defaultValue || '');
67
- const uniqueId = useId.useId();
67
+ const uniqueId = useId.useId('table-toolbar-search');
68
68
  const [focusTarget, setFocusTarget] = React.useState(null);
69
69
  const prefix = usePrefix.usePrefix();
70
70
  React.useEffect(() => {
@@ -111,7 +111,7 @@ const TableToolbarSearch = _ref => {
111
111
  disabled: disabled,
112
112
  className: searchClasses,
113
113
  value: value,
114
- id: typeof id !== 'undefined' ? id : `table-toolbar-search-${uniqueId.toString()}`,
114
+ id: typeof id !== 'undefined' ? id : uniqueId,
115
115
  labelText: labelText || t('carbon.table.toolbar.search.label'),
116
116
  placeholder: placeholder || t('carbon.table.toolbar.search.placeholder'),
117
117
  onChange: onChange,