@carbon/react 1.71.1 → 1.72.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +799 -799
  2. package/es/components/ComboBox/ComboBox.d.ts +5 -0
  3. package/es/components/ComboBox/ComboBox.js +17 -12
  4. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +5 -0
  5. package/es/components/MultiSelect/FilterableMultiSelect.js +14 -9
  6. package/es/components/MultiSelect/MultiSelect.d.ts +5 -0
  7. package/es/components/MultiSelect/MultiSelect.js +15 -10
  8. package/es/components/OverflowMenu/OverflowMenu.d.ts +1 -1
  9. package/es/components/OverflowMenu/OverflowMenu.js +7 -17
  10. package/es/components/Pagination/Pagination.js +1 -1
  11. package/es/components/Popover/index.d.ts +5 -0
  12. package/es/components/Popover/index.js +12 -1
  13. package/es/components/Select/Select.d.ts +6 -1
  14. package/es/components/Select/Select.js +15 -10
  15. package/es/components/UIShell/Switcher.js +7 -3
  16. package/lib/components/ComboBox/ComboBox.d.ts +5 -0
  17. package/lib/components/ComboBox/ComboBox.js +17 -12
  18. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +5 -0
  19. package/lib/components/MultiSelect/FilterableMultiSelect.js +14 -9
  20. package/lib/components/MultiSelect/MultiSelect.d.ts +5 -0
  21. package/lib/components/MultiSelect/MultiSelect.js +15 -10
  22. package/lib/components/OverflowMenu/OverflowMenu.d.ts +1 -1
  23. package/lib/components/OverflowMenu/OverflowMenu.js +9 -19
  24. package/lib/components/Pagination/Pagination.js +1 -1
  25. package/lib/components/Popover/index.d.ts +5 -0
  26. package/lib/components/Popover/index.js +12 -1
  27. package/lib/components/Select/Select.d.ts +6 -1
  28. package/lib/components/Select/Select.js +15 -10
  29. package/lib/components/UIShell/Switcher.js +7 -3
  30. package/package.json +3 -3
@@ -48,6 +48,10 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
48
48
  * An optional className to add to the container node
49
49
  */
50
50
  className?: string;
51
+ /**
52
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `ComboBox` component
53
+ */
54
+ decorator?: ReactNode;
51
55
  /**
52
56
  * Specify the direction of the combobox dropdown. Can be either top or bottom.
53
57
  */
@@ -170,6 +174,7 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
170
174
  */
171
175
  size?: ListBoxSize;
172
176
  /**
177
+ * @deprecated please use decorator instead.
173
178
  * **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` component
174
179
  */
175
180
  slug?: ReactNode;
@@ -118,6 +118,7 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
118
118
  ariaLabel: deprecatedAriaLabel,
119
119
  autoAlign = false,
120
120
  className: containerClassName,
121
+ decorator,
121
122
  direction = 'bottom',
122
123
  disabled = false,
123
124
  downshiftActions,
@@ -386,7 +387,8 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
386
387
  const wrapperClasses = cx(`${prefix}--list-box__wrapper`, [containerClassName, {
387
388
  [`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
388
389
  [`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
389
- [`${prefix}--list-box__wrapper--slug`]: slug
390
+ [`${prefix}--list-box__wrapper--slug`]: slug,
391
+ [`${prefix}--list-box__wrapper--decorator`]: decorator
390
392
  }]);
391
393
  const inputClasses = cx(`${prefix}--text-input`, {
392
394
  [`${prefix}--text-input--empty`]: !inputValue,
@@ -396,10 +398,10 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
396
398
  // needs to be Capitalized for react to render it correctly
397
399
  const ItemToElement = itemToElement;
398
400
 
399
- // Slug is always size `mini`
400
- let normalizedSlug;
401
- if (slug && slug['type']?.displayName === 'AILabel') {
402
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
401
+ // AILabel always size `mini`
402
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
403
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
404
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
403
405
  size: 'mini'
404
406
  });
405
407
  }
@@ -456,12 +458,12 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
456
458
  type,
457
459
  selectedItem: newSelectedItem
458
460
  } = _ref6;
459
- if (type === '__item_click__' && !isEqual(selectedItemProp, newSelectedItem)) {
461
+ if (type === useCombobox.stateChangeTypes.ItemClick && !isEqual(selectedItemProp, newSelectedItem)) {
460
462
  onChange({
461
463
  selectedItem: newSelectedItem
462
464
  });
463
465
  }
464
- if (type === '__function_select_item__' || type === '__input_keydown_enter__') {
466
+ if (type === useCombobox.stateChangeTypes.FunctionSelectItem || type === useCombobox.stateChangeTypes.InputKeyDownEnter) {
465
467
  onChange({
466
468
  selectedItem: newSelectedItem
467
469
  });
@@ -661,7 +663,9 @@ const ComboBox = /*#__PURE__*/forwardRef((props, ref) => {
661
663
  }), /*#__PURE__*/React__default.createElement(ListBoxTrigger, _extends({}, buttonProps, {
662
664
  isOpen: isOpen,
663
665
  translateWithId: translateWithId
664
- }))), normalizedSlug, /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen ? filterItems(items, itemToString, inputValue).map((item, index) => {
666
+ }))), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
667
+ className: `${prefix}--list-box__inner-wrapper--decorator`
668
+ }, normalizedDecorator) : '', /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen ? filterItems(items, itemToString, inputValue).map((item, index) => {
665
669
  const isObject = item !== null && typeof item === 'object';
666
670
  const title = isObject && 'text' in item && itemToElement ? item.text?.toString() : itemToString(item);
667
671
  const itemProps = getItemProps({
@@ -724,6 +728,10 @@ ComboBox.propTypes = {
724
728
  * An optional className to add to the container node
725
729
  */
726
730
  className: PropTypes.string,
731
+ /**
732
+ * **Experimental**: Provide a decorator component to be rendered inside the `ComboBox` component
733
+ */
734
+ decorator: PropTypes.node,
727
735
  /**
728
736
  * Specify the direction of the combobox dropdown. Can be either top or bottom.
729
737
  */
@@ -841,10 +849,7 @@ ComboBox.propTypes = {
841
849
  * Specify the size of the ListBox. Currently supports either `sm`, `md` or `lg` as an option.
842
850
  */
843
851
  size: ListBoxSize,
844
- /**
845
- * **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` component
846
- */
847
- slug: PropTypes.node,
852
+ slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
848
853
  /**
849
854
  * Provide text to be used in a `<label>` element that is tied to the
850
855
  * combobox via ARIA attributes.
@@ -39,6 +39,10 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
39
39
  * Specify the text that should be read for screen readers to clear selection.
40
40
  */
41
41
  clearSelectionText?: string;
42
+ /**
43
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `FilterableMultiSelect` component
44
+ */
45
+ decorator?: ReactNode;
42
46
  /**
43
47
  * Specify the direction of the multiselect dropdown.
44
48
  */
@@ -164,6 +168,7 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
164
168
  */
165
169
  size?: 'sm' | 'md' | 'lg';
166
170
  /**
171
+ * @deprecated please use decorator instead.
167
172
  * **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component
168
173
  */
169
174
  slug?: ReactNode;
@@ -69,6 +69,7 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
69
69
  clearSelectionDescription = 'Total items selected: ',
70
70
  clearSelectionText = 'To clear selection, press Delete or Backspace',
71
71
  compareItems = defaultCompareItems,
72
+ decorator,
72
73
  direction = 'bottom',
73
74
  disabled = false,
74
75
  downshiftProps,
@@ -198,6 +199,7 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
198
199
  [`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
199
200
  [`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
200
201
  [`${prefix}--list-box__wrapper--slug`]: slug,
202
+ [`${prefix}--list-box__wrapper--decorator`]: decorator,
201
203
  [`${prefix}--autoalign`]: autoAlign
202
204
  });
203
205
  const helperId = !helperText ? undefined : `filterablemultiselect-helper-text-${filterableMultiSelectInstanceId}`;
@@ -412,10 +414,10 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
412
414
  }
413
415
  }
414
416
 
415
- // Slug is always size `mini`
416
- let normalizedSlug;
417
- if (slug && slug['type']?.displayName === 'AILabel') {
418
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
417
+ // AILabel always size `mini`
418
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
419
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
420
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
419
421
  size: 'mini'
420
422
  });
421
423
  }
@@ -596,7 +598,9 @@ const FilterableMultiSelect = /*#__PURE__*/React__default.forwardRef(function Fi
596
598
  }), /*#__PURE__*/React__default.createElement(ListBoxTrigger, _extends({}, buttonProps, {
597
599
  isOpen: isOpen,
598
600
  translateWithId: translateWithId
599
- }))), normalizedSlug, /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen ? sortedItems.map((item, index) => {
601
+ }))), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
602
+ className: `${prefix}--list-box__inner-wrapper--decorator`
603
+ }, normalizedDecorator) : '', /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen ? sortedItems.map((item, index) => {
600
604
  const isChecked = controlledSelectedItems.filter(selected => isEqual(selected, item)).length > 0;
601
605
  const itemProps = getItemProps({
602
606
  item,
@@ -658,6 +662,10 @@ FilterableMultiSelect.propTypes = {
658
662
  * Specify the text that should be read for screen readers to clear selection.
659
663
  */
660
664
  clearSelectionText: PropTypes.string,
665
+ /**
666
+ * **Experimental**: Provide a decorator component to be rendered inside the `FilterableMultiSelect` component
667
+ */
668
+ decorator: PropTypes.node,
661
669
  /**
662
670
  * Specify the direction of the multiselect dropdown. Can be either top or bottom.
663
671
  */
@@ -757,10 +765,7 @@ FilterableMultiSelect.propTypes = {
757
765
  * Specify the size of the ListBox. Currently supports either `sm`, `md` or `lg` as an option.
758
766
  */
759
767
  size: ListBoxSize,
760
- /**
761
- * **Experimental**: Provide a `Slug` component to be rendered inside the `FilterableMultiSelect` component
762
- */
763
- slug: PropTypes.node,
768
+ slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
764
769
  ...sortingPropTypes,
765
770
  /**
766
771
  * Provide text to be used in a `<label>` element that is tied to the
@@ -33,6 +33,10 @@ export interface MultiSelectProps<ItemType> extends MultiSelectSortingProps<Item
33
33
  * Specify the text that should be read for screen readers to clear selection.
34
34
  */
35
35
  clearSelectionText?: string;
36
+ /**
37
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `MultiSelect` component
38
+ */
39
+ decorator?: ReactNode;
36
40
  /**
37
41
  * Specify the direction of the multiselect dropdown. Can be either top or bottom.
38
42
  */
@@ -143,6 +147,7 @@ export interface MultiSelectProps<ItemType> extends MultiSelectSortingProps<Item
143
147
  */
144
148
  size?: ListBoxSize;
145
149
  /**
150
+ * @deprecated please use decorator instead.
146
151
  * **Experimental**: Provide a `Slug` component to be rendered inside the `MultiSelect` component
147
152
  */
148
153
  slug?: ReactNode;
@@ -63,6 +63,7 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
63
63
  let {
64
64
  autoAlign = false,
65
65
  className: containerClassName,
66
+ decorator,
66
67
  id,
67
68
  items,
68
69
  itemToElement,
@@ -262,7 +263,8 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
262
263
  [`${prefix}--list-box__wrapper--inline--invalid`]: inline && invalid,
263
264
  [`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
264
265
  [`${prefix}--list-box__wrapper--fluid--focus`]: !isOpen && isFluid && isFocused,
265
- [`${prefix}--list-box__wrapper--slug`]: slug
266
+ [`${prefix}--list-box__wrapper--slug`]: slug,
267
+ [`${prefix}--list-box__wrapper--decorator`]: decorator
266
268
  });
267
269
  const titleClasses = cx(`${prefix}--label`, {
268
270
  [`${prefix}--label--disabled`]: disabled,
@@ -400,10 +402,10 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
400
402
  }
401
403
  } : {};
402
404
 
403
- // Slug is always size `mini`
404
- let normalizedSlug;
405
- if (slug && slug['type']?.displayName === 'AILabel') {
406
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
405
+ // AILabel always size `mini`
406
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
407
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
408
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
407
409
  size: 'mini'
408
410
  });
409
411
  }
@@ -463,7 +465,9 @@ const MultiSelect = /*#__PURE__*/React__default.forwardRef((_ref, ref) => {
463
465
  }, label), /*#__PURE__*/React__default.createElement(ListBox.MenuIcon, {
464
466
  isOpen: isOpen,
465
467
  translateWithId: translateWithId
466
- })), normalizedSlug), /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen && sortItems(filteredItems, sortOptions).map((item, index) => {
468
+ })), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
469
+ className: `${prefix}--list-box__inner-wrapper--decorator`
470
+ }, normalizedDecorator) : ''), /*#__PURE__*/React__default.createElement(ListBox.Menu, menuProps, isOpen && sortItems(filteredItems, sortOptions).map((item, index) => {
467
471
  const isChecked = selectedItems.filter(selected => isEqual(selected, item)).length > 0;
468
472
  const isIndeterminate = selectedItems.length !== 0 && item['isSelectAll'] && !isChecked;
469
473
  const itemProps = getItemProps({
@@ -528,6 +532,10 @@ MultiSelect.propTypes = {
528
532
  * declaring function with `useCallback` to prevent unnecessary re-renders.
529
533
  */
530
534
  compareItems: PropTypes.func,
535
+ /**
536
+ * **Experimental**: Provide a decorator component to be rendered inside the `MultiSelect` component
537
+ */
538
+ decorator: PropTypes.node,
531
539
  /**
532
540
  * Specify the direction of the multiselect dropdown. Can be either top or bottom.
533
541
  */
@@ -635,10 +643,7 @@ MultiSelect.propTypes = {
635
643
  * Specify the size of the ListBox. Currently supports either `sm`, `md` or `lg` as an option.
636
644
  */
637
645
  size: ListBoxSize,
638
- /**
639
- * **Experimental**: Provide a `Slug` component to be rendered inside the `MultiSelect` component
640
- */
641
- slug: PropTypes.node,
646
+ slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
642
647
  /**
643
648
  * Provide a method that sorts all options in the control. Overriding this
644
649
  * prop means that you also have to handle the sort logic for selected versus
@@ -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 PropTypes from 'prop-types';
8
7
  import React, { ComponentType } from 'react';
8
+ import PropTypes from 'prop-types';
9
9
  /**
10
10
  * @param {Element} menuBody The menu body with the menu arrow.
11
11
  * @param {string} direction The floating menu direction.
@@ -6,19 +6,19 @@
6
6
  */
7
7
 
8
8
  import { defineProperty as _defineProperty, extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js';
9
- import invariant from 'invariant';
10
- import PropTypes from 'prop-types';
9
+ import FloatingMenu, { DIRECTION_TOP, DIRECTION_BOTTOM } from '../../internal/FloatingMenu.js';
11
10
  import React__default from 'react';
12
- import cx from 'classnames';
13
11
  import ClickListener from '../../internal/ClickListener.js';
14
- import FloatingMenu, { DIRECTION_TOP, DIRECTION_BOTTOM } from '../../internal/FloatingMenu.js';
12
+ import { IconButton } from '../IconButton/index.js';
15
13
  import { OverflowMenuVertical } from '@carbon/icons-react';
16
- import mergeRefs from '../../tools/mergeRefs.js';
17
14
  import { PrefixContext } from '../../internal/usePrefix.js';
15
+ import PropTypes from 'prop-types';
16
+ import cx from 'classnames';
18
17
  import deprecate from '../../prop-types/deprecate.js';
19
- import { IconButton } from '../IconButton/index.js';
20
- import setupGetInstanceId from '../../tools/setupGetInstanceId.js';
18
+ import invariant from 'invariant';
19
+ import mergeRefs from '../../tools/mergeRefs.js';
21
20
  import { noopFn } from '../../internal/noopFn.js';
21
+ import setupGetInstanceId from '../../tools/setupGetInstanceId.js';
22
22
  import { matches } from '../../internal/keyboard/match.js';
23
23
  import { ArrowUp, ArrowRight, ArrowDown, ArrowLeft, Escape } from '../../internal/keyboard/keys.js';
24
24
 
@@ -81,16 +81,6 @@ const getMenuOffset = (menuBody, direction, trigger, flip) => {
81
81
  top: 0
82
82
  };
83
83
  }
84
- case 'left':
85
- case 'right':
86
- {
87
- // TODO: Ensure `trigger` is there for `<OverflowMenu open>`
88
- const triggerHeight = !trigger ? 0 : trigger.offsetHeight;
89
- return {
90
- left: 0,
91
- top: (!flip ? 1 : -1) * (menuHeight / 2 - triggerHeight / 2)
92
- };
93
- }
94
84
  }
95
85
  };
96
86
  class OverflowMenu extends React__default.Component {
@@ -225,7 +225,7 @@ const Pagination = /*#__PURE__*/React__default.forwardRef(function Pagination(_r
225
225
  }, pageText(page)) : /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement(Select, {
226
226
  id: `${prefix}-pagination-select-${inputId}-right`,
227
227
  className: `${prefix}--select__page-number`,
228
- labelText: `Page number, of ${totalPages} pages`,
228
+ labelText: `Page of ${totalPages} pages`,
229
229
  inline: true,
230
230
  hideLabel: true,
231
231
  onChange: handlePageInputChange,
@@ -6,6 +6,7 @@
6
6
  */
7
7
  import React, { type ForwardedRef, type WeakValidationMap, type ElementType } from 'react';
8
8
  import { type PolymorphicProps } from '../../types/common';
9
+ import { type Boundary } from '@floating-ui/react';
9
10
  /**
10
11
  * Deprecated popover alignment values.
11
12
  * @deprecated Use NewPopoverAlignment instead.
@@ -22,6 +23,10 @@ interface PopoverBaseProps {
22
23
  * Will auto-align the popover on first render if it is not visible. This prop is currently experimental and is subject to future changes.
23
24
  */
24
25
  autoAlign?: boolean;
26
+ /**
27
+ * Specify a bounding element to be used for autoAlign calculations. The viewport is used by default. This prop is currently experimental and is subject to future changes.
28
+ */
29
+ autoAlignBoundary?: Boundary;
25
30
  /**
26
31
  * Specify whether a caret should be rendered
27
32
  */
@@ -53,6 +53,7 @@ const Popover = /*#__PURE__*/React__default.forwardRef(function PopoverRenderFun
53
53
  align: initialAlign = isTabTip ? 'bottom-start' : 'bottom',
54
54
  as: BaseComponent = 'span',
55
55
  autoAlign = false,
56
+ autoAlignBoundary,
56
57
  caret = isTabTip ? false : true,
57
58
  className: customClassName,
58
59
  children,
@@ -130,7 +131,8 @@ const Popover = /*#__PURE__*/React__default.forwardRef(function PopoverRenderFun
130
131
  middleware: [offset(!isTabTip ? popoverDimensions?.current?.offset : 0), autoAlign && flip({
131
132
  fallbackPlacements: align.includes('bottom') ? ['bottom', 'bottom-start', 'bottom-end', 'right', 'right-start', 'right-end', 'left', 'left-start', 'left-end', 'top', 'top-start', 'top-end'] : ['top', 'top-start', 'top-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end', 'bottom', 'bottom-start', 'bottom-end'],
132
133
  fallbackStrategy: 'initialPlacement',
133
- fallbackAxisSideDirection: 'start'
134
+ fallbackAxisSideDirection: 'start',
135
+ boundary: autoAlignBoundary
134
136
  }), arrow({
135
137
  element: caretRef
136
138
  }), autoAlign && hide()],
@@ -301,6 +303,15 @@ Popover.propTypes = {
301
303
  * Will auto-align the popover on first render if it is not visible. This prop is currently experimental and is subject to future changes.
302
304
  */
303
305
  autoAlign: PropTypes.bool,
306
+ /**
307
+ * Specify a bounding element to be used for autoAlign calculations. The viewport is used by default. This prop is currently experimental and is subject to future changes.
308
+ */
309
+ autoAlignBoundary: PropTypes.oneOfType([PropTypes.oneOf(['clippingAncestors']), PropTypes.elementType, PropTypes.arrayOf(PropTypes.elementType), PropTypes.exact({
310
+ x: PropTypes.number.isRequired,
311
+ y: PropTypes.number.isRequired,
312
+ width: PropTypes.number.isRequired,
313
+ height: PropTypes.number.isRequired
314
+ })]),
304
315
  /**
305
316
  * Specify whether a caret should be rendered
306
317
  */
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import React, { ChangeEventHandler, ComponentPropsWithRef, ReactNode } from 'react';
8
8
  type ExcludedAttributes = 'size';
9
- interface SelectProps extends Omit<ComponentPropsWithRef<'select'>, ExcludedAttributes> {
9
+ export interface SelectProps extends Omit<ComponentPropsWithRef<'select'>, ExcludedAttributes> {
10
10
  /**
11
11
  * Provide the contents of your Select
12
12
  */
@@ -15,6 +15,10 @@ interface SelectProps extends Omit<ComponentPropsWithRef<'select'>, ExcludedAttr
15
15
  * Specify an optional className to be applied to the node containing the label and the select box
16
16
  */
17
17
  className?: string;
18
+ /**
19
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `Select` component
20
+ */
21
+ decorator?: ReactNode;
18
22
  /**
19
23
  * Optionally provide the default value of the `<select>`
20
24
  */
@@ -77,6 +81,7 @@ interface SelectProps extends Omit<ComponentPropsWithRef<'select'>, ExcludedAttr
77
81
  */
78
82
  size?: 'sm' | 'md' | 'lg';
79
83
  /**
84
+ * @deprecated please use decorator instead.
80
85
  * **Experimental**: Provide a `Slug` component to be rendered inside the `Dropdown` component
81
86
  */
82
87
  slug?: ReactNode;
@@ -22,6 +22,7 @@ import { Text } from '../Text/Text.js';
22
22
  const Select = /*#__PURE__*/React__default.forwardRef(function Select(_ref, ref) {
23
23
  let {
24
24
  className,
25
+ decorator,
25
26
  id,
26
27
  inline = false,
27
28
  labelText = 'Select',
@@ -60,7 +61,8 @@ const Select = /*#__PURE__*/React__default.forwardRef(function Select(_ref, ref)
60
61
  [`${prefix}--select--warning`]: warn,
61
62
  [`${prefix}--select--fluid--invalid`]: isFluid && invalid,
62
63
  [`${prefix}--select--fluid--focus`]: isFluid && isFocused,
63
- [`${prefix}--select--slug`]: slug
64
+ [`${prefix}--select--slug`]: slug,
65
+ [`${prefix}--select--decorator`]: decorator
64
66
  });
65
67
  const labelClasses = cx(`${prefix}--label`, {
66
68
  [`${prefix}--visually-hidden`]: hideLabel,
@@ -123,10 +125,10 @@ const Select = /*#__PURE__*/React__default.forwardRef(function Select(_ref, ref)
123
125
  }
124
126
  };
125
127
 
126
- // Slug is always size `mini`
127
- let normalizedSlug;
128
- if (slug && slug['type']?.displayName === 'AILabel') {
129
- normalizedSlug = /*#__PURE__*/React__default.cloneElement(slug, {
128
+ // AILabel always size `mini`
129
+ let normalizedDecorator = /*#__PURE__*/React__default.isValidElement(slug ?? decorator) ? slug ?? decorator : null;
130
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
131
+ normalizedDecorator = /*#__PURE__*/React__default.cloneElement(normalizedDecorator, {
130
132
  size: 'mini'
131
133
  });
132
134
  }
@@ -167,7 +169,9 @@ const Select = /*#__PURE__*/React__default.forwardRef(function Select(_ref, ref)
167
169
  "data-invalid": invalid || null,
168
170
  onFocus: handleFocus,
169
171
  onBlur: handleFocus
170
- }, input, normalizedSlug, isFluid && /*#__PURE__*/React__default.createElement("hr", {
172
+ }, input, slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default.createElement("div", {
173
+ className: `${prefix}--select__inner-wrapper--decorator`
174
+ }, normalizedDecorator) : '', isFluid && /*#__PURE__*/React__default.createElement("hr", {
171
175
  className: `${prefix}--select__divider`
172
176
  }), isFluid && error ? error : null), !inline && !isFluid && error ? error : helper));
173
177
  });
@@ -181,6 +185,10 @@ Select.propTypes = {
181
185
  * Specify an optional className to be applied to the node containing the label and the select box
182
186
  */
183
187
  className: PropTypes.string,
188
+ /**
189
+ * **Experimental**: Provide a decorator component to be rendered inside the `Select` component
190
+ */
191
+ decorator: PropTypes.node,
184
192
  /**
185
193
  * Optionally provide the default value of the `<select>`
186
194
  */
@@ -241,10 +249,7 @@ Select.propTypes = {
241
249
  * Specify the size of the Select Input.
242
250
  */
243
251
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
244
- /**
245
- * **Experimental**: Provide a `Slug` component to be rendered inside the `Select` component
246
- */
247
- slug: PropTypes.node,
252
+ slug: deprecate(PropTypes.node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
248
253
  /**
249
254
  * Specify whether the control is currently in warning state
250
255
  */
@@ -38,7 +38,7 @@ const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
38
38
  direction
39
39
  } = _ref;
40
40
  const enabledIndices = React__default.Children.toArray(children).reduce((acc, curr, i) => {
41
- if (Object.keys(curr.props).length !== 0) {
41
+ if (/*#__PURE__*/React__default.isValidElement(curr) && Object.keys(curr.props).length !== 0 && getDisplayName(curr.type) === 'SwitcherItem') {
42
42
  acc.push(i);
43
43
  }
44
44
  return acc;
@@ -50,7 +50,11 @@ const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
50
50
  if (direction === -1) {
51
51
  return enabledIndices[enabledIndices.length - 1];
52
52
  }
53
- return 0;
53
+ return enabledIndices[0];
54
+ case 0:
55
+ if (direction === 1) {
56
+ return enabledIndices[1];
57
+ }
54
58
  default:
55
59
  return enabledIndices[nextIndex];
56
60
  }
@@ -62,7 +66,7 @@ const Switcher = /*#__PURE__*/forwardRef(function Switcher(props, forwardRef) {
62
66
  };
63
67
  const childrenWithProps = React__default.Children.toArray(children).map((child, index) => {
64
68
  // only setup click handlers if onChange event is passed
65
- if (/*#__PURE__*/React__default.isValidElement(child) && child.type && getDisplayName(child.type) === 'Switcher') {
69
+ if (/*#__PURE__*/React__default.isValidElement(child) && child.type && getDisplayName(child.type) === 'SwitcherItem') {
66
70
  return /*#__PURE__*/React__default.cloneElement(child, {
67
71
  handleSwitcherItemFocus,
68
72
  index,
@@ -48,6 +48,10 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
48
48
  * An optional className to add to the container node
49
49
  */
50
50
  className?: string;
51
+ /**
52
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `ComboBox` component
53
+ */
54
+ decorator?: ReactNode;
51
55
  /**
52
56
  * Specify the direction of the combobox dropdown. Can be either top or bottom.
53
57
  */
@@ -170,6 +174,7 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
170
174
  */
171
175
  size?: ListBoxSize;
172
176
  /**
177
+ * @deprecated please use decorator instead.
173
178
  * **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` component
174
179
  */
175
180
  slug?: ReactNode;
@@ -129,6 +129,7 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
129
129
  ariaLabel: deprecatedAriaLabel,
130
130
  autoAlign = false,
131
131
  className: containerClassName,
132
+ decorator,
132
133
  direction = 'bottom',
133
134
  disabled = false,
134
135
  downshiftActions,
@@ -397,7 +398,8 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
397
398
  const wrapperClasses = cx__default["default"](`${prefix}--list-box__wrapper`, [containerClassName, {
398
399
  [`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
399
400
  [`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
400
- [`${prefix}--list-box__wrapper--slug`]: slug
401
+ [`${prefix}--list-box__wrapper--slug`]: slug,
402
+ [`${prefix}--list-box__wrapper--decorator`]: decorator
401
403
  }]);
402
404
  const inputClasses = cx__default["default"](`${prefix}--text-input`, {
403
405
  [`${prefix}--text-input--empty`]: !inputValue,
@@ -407,10 +409,10 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
407
409
  // needs to be Capitalized for react to render it correctly
408
410
  const ItemToElement = itemToElement;
409
411
 
410
- // Slug is always size `mini`
411
- let normalizedSlug;
412
- if (slug && slug['type']?.displayName === 'AILabel') {
413
- normalizedSlug = /*#__PURE__*/React__default["default"].cloneElement(slug, {
412
+ // AILabel always size `mini`
413
+ let normalizedDecorator = /*#__PURE__*/React__default["default"].isValidElement(slug ?? decorator) ? slug ?? decorator : null;
414
+ if (normalizedDecorator && normalizedDecorator['type']?.displayName === 'AILabel') {
415
+ normalizedDecorator = /*#__PURE__*/React__default["default"].cloneElement(normalizedDecorator, {
414
416
  size: 'mini'
415
417
  });
416
418
  }
@@ -467,12 +469,12 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
467
469
  type,
468
470
  selectedItem: newSelectedItem
469
471
  } = _ref6;
470
- if (type === '__item_click__' && !isEqual__default["default"](selectedItemProp, newSelectedItem)) {
472
+ if (type === Downshift.useCombobox.stateChangeTypes.ItemClick && !isEqual__default["default"](selectedItemProp, newSelectedItem)) {
471
473
  onChange({
472
474
  selectedItem: newSelectedItem
473
475
  });
474
476
  }
475
- if (type === '__function_select_item__' || type === '__input_keydown_enter__') {
477
+ if (type === Downshift.useCombobox.stateChangeTypes.FunctionSelectItem || type === Downshift.useCombobox.stateChangeTypes.InputKeyDownEnter) {
476
478
  onChange({
477
479
  selectedItem: newSelectedItem
478
480
  });
@@ -672,7 +674,9 @@ const ComboBox = /*#__PURE__*/React.forwardRef((props, ref) => {
672
674
  }), /*#__PURE__*/React__default["default"].createElement(ListBoxTrigger["default"], _rollupPluginBabelHelpers["extends"]({}, buttonProps, {
673
675
  isOpen: isOpen,
674
676
  translateWithId: translateWithId
675
- }))), normalizedSlug, /*#__PURE__*/React__default["default"].createElement(index$1["default"].Menu, menuProps, isOpen ? filterItems(items, itemToString, inputValue).map((item, index) => {
677
+ }))), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React__default["default"].createElement("div", {
678
+ className: `${prefix}--list-box__inner-wrapper--decorator`
679
+ }, normalizedDecorator) : '', /*#__PURE__*/React__default["default"].createElement(index$1["default"].Menu, menuProps, isOpen ? filterItems(items, itemToString, inputValue).map((item, index) => {
676
680
  const isObject = item !== null && typeof item === 'object';
677
681
  const title = isObject && 'text' in item && itemToElement ? item.text?.toString() : itemToString(item);
678
682
  const itemProps = getItemProps({
@@ -735,6 +739,10 @@ ComboBox.propTypes = {
735
739
  * An optional className to add to the container node
736
740
  */
737
741
  className: PropTypes__default["default"].string,
742
+ /**
743
+ * **Experimental**: Provide a decorator component to be rendered inside the `ComboBox` component
744
+ */
745
+ decorator: PropTypes__default["default"].node,
738
746
  /**
739
747
  * Specify the direction of the combobox dropdown. Can be either top or bottom.
740
748
  */
@@ -852,10 +860,7 @@ ComboBox.propTypes = {
852
860
  * Specify the size of the ListBox. Currently supports either `sm`, `md` or `lg` as an option.
853
861
  */
854
862
  size: ListBoxPropTypes.ListBoxSize,
855
- /**
856
- * **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` component
857
- */
858
- slug: PropTypes__default["default"].node,
863
+ slug: deprecate["default"](PropTypes__default["default"].node, 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'),
859
864
  /**
860
865
  * Provide text to be used in a `<label>` element that is tied to the
861
866
  * combobox via ARIA attributes.
@@ -39,6 +39,10 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
39
39
  * Specify the text that should be read for screen readers to clear selection.
40
40
  */
41
41
  clearSelectionText?: string;
42
+ /**
43
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `FilterableMultiSelect` component
44
+ */
45
+ decorator?: ReactNode;
42
46
  /**
43
47
  * Specify the direction of the multiselect dropdown.
44
48
  */
@@ -164,6 +168,7 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
164
168
  */
165
169
  size?: 'sm' | 'md' | 'lg';
166
170
  /**
171
+ * @deprecated please use decorator instead.
167
172
  * **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component
168
173
  */
169
174
  slug?: ReactNode;