@carbon/react 1.87.1 → 1.89.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 (97) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +804 -804
  2. package/es/components/AILabel/index.d.ts +4 -3
  3. package/es/components/AILabel/index.js +3 -1
  4. package/es/components/Button/Button.js +3 -1
  5. package/es/components/CodeSnippet/CodeSnippet.d.ts +9 -5
  6. package/es/components/CodeSnippet/CodeSnippet.js +3 -1
  7. package/es/components/ComboBox/ComboBox.d.ts +2 -1
  8. package/es/components/ComboBox/ComboBox.js +2 -1
  9. package/es/components/ContainedList/ContainedList.d.ts +2 -2
  10. package/es/components/ContentSwitcher/ContentSwitcher.d.ts +1 -6
  11. package/es/components/Copy/Copy.d.ts +9 -5
  12. package/es/components/Copy/Copy.js +3 -1
  13. package/es/components/CopyButton/CopyButton.d.ts +9 -5
  14. package/es/components/CopyButton/CopyButton.js +3 -1
  15. package/es/components/Dropdown/Dropdown.d.ts +4 -1
  16. package/es/components/Dropdown/Dropdown.js +4 -1
  17. package/es/components/FileUploader/FileUploaderButton.js +6 -3
  18. package/es/components/IconButton/index.d.ts +6 -4
  19. package/es/components/IconButton/index.js +3 -4
  20. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +5 -2
  21. package/es/components/MultiSelect/FilterableMultiSelect.js +101 -22
  22. package/es/components/MultiSelect/MultiSelect.d.ts +2 -1
  23. package/es/components/MultiSelect/MultiSelect.js +2 -1
  24. package/es/components/Notification/Notification.d.ts +9 -1
  25. package/es/components/Notification/Notification.js +9 -1
  26. package/es/components/NumberInput/NumberInput.d.ts +4 -0
  27. package/es/components/NumberInput/NumberInput.js +12 -7
  28. package/es/components/OverflowMenu/next/index.d.ts +6 -2
  29. package/es/components/OverflowMenu/next/index.js +4 -1
  30. package/es/components/Popover/index.d.ts +4 -1
  31. package/es/components/Popover/index.js +15 -22
  32. package/es/components/Switch/IconSwitch.d.ts +44 -2
  33. package/es/components/Switch/IconSwitch.js +34 -27
  34. package/es/components/Switch/Switch.js +1 -0
  35. package/es/components/TextArea/TextArea.js +21 -4
  36. package/es/components/Toggletip/index.d.ts +4 -1
  37. package/es/components/Toggletip/index.js +4 -1
  38. package/es/components/Tooltip/DefinitionTooltip.d.ts +4 -2
  39. package/es/components/Tooltip/DefinitionTooltip.js +3 -1
  40. package/es/components/Tooltip/Tooltip.d.ts +0 -3
  41. package/es/components/Tooltip/Tooltip.js +2 -10
  42. package/es/components/TreeView/TreeNode.d.ts +4 -2
  43. package/es/components/TreeView/TreeNode.js +2 -1
  44. package/es/components/UIShell/Header.d.ts +3 -3
  45. package/es/components/UIShell/Header.js +7 -4
  46. package/es/components/UIShell/HeaderPanel.js +1 -1
  47. package/es/internal/Selection.d.ts +1 -0
  48. package/es/internal/Selection.js +10 -0
  49. package/lib/components/AILabel/index.d.ts +4 -3
  50. package/lib/components/AILabel/index.js +3 -1
  51. package/lib/components/Button/Button.js +3 -1
  52. package/lib/components/CodeSnippet/CodeSnippet.d.ts +9 -5
  53. package/lib/components/CodeSnippet/CodeSnippet.js +3 -1
  54. package/lib/components/ComboBox/ComboBox.d.ts +2 -1
  55. package/lib/components/ComboBox/ComboBox.js +2 -1
  56. package/lib/components/ContainedList/ContainedList.d.ts +2 -2
  57. package/lib/components/ContentSwitcher/ContentSwitcher.d.ts +1 -6
  58. package/lib/components/Copy/Copy.d.ts +9 -5
  59. package/lib/components/Copy/Copy.js +3 -1
  60. package/lib/components/CopyButton/CopyButton.d.ts +9 -5
  61. package/lib/components/CopyButton/CopyButton.js +3 -1
  62. package/lib/components/Dropdown/Dropdown.d.ts +4 -1
  63. package/lib/components/Dropdown/Dropdown.js +4 -1
  64. package/lib/components/FileUploader/FileUploaderButton.js +6 -3
  65. package/lib/components/IconButton/index.d.ts +6 -4
  66. package/lib/components/IconButton/index.js +3 -4
  67. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +5 -2
  68. package/lib/components/MultiSelect/FilterableMultiSelect.js +100 -21
  69. package/lib/components/MultiSelect/MultiSelect.d.ts +2 -1
  70. package/lib/components/MultiSelect/MultiSelect.js +2 -1
  71. package/lib/components/Notification/Notification.d.ts +9 -1
  72. package/lib/components/Notification/Notification.js +9 -1
  73. package/lib/components/NumberInput/NumberInput.d.ts +4 -0
  74. package/lib/components/NumberInput/NumberInput.js +12 -7
  75. package/lib/components/OverflowMenu/next/index.d.ts +6 -2
  76. package/lib/components/OverflowMenu/next/index.js +4 -1
  77. package/lib/components/Popover/index.d.ts +4 -1
  78. package/lib/components/Popover/index.js +14 -21
  79. package/lib/components/Switch/IconSwitch.d.ts +44 -2
  80. package/lib/components/Switch/IconSwitch.js +35 -28
  81. package/lib/components/Switch/Switch.js +1 -0
  82. package/lib/components/TextArea/TextArea.js +21 -4
  83. package/lib/components/Toggletip/index.d.ts +4 -1
  84. package/lib/components/Toggletip/index.js +4 -1
  85. package/lib/components/Tooltip/DefinitionTooltip.d.ts +4 -2
  86. package/lib/components/Tooltip/DefinitionTooltip.js +3 -1
  87. package/lib/components/Tooltip/Tooltip.d.ts +0 -3
  88. package/lib/components/Tooltip/Tooltip.js +2 -10
  89. package/lib/components/TreeView/TreeNode.d.ts +4 -2
  90. package/lib/components/TreeView/TreeNode.js +2 -1
  91. package/lib/components/UIShell/Header.d.ts +3 -3
  92. package/lib/components/UIShell/Header.js +7 -4
  93. package/lib/components/UIShell/HeaderPanel.js +2 -2
  94. package/lib/internal/Selection.d.ts +1 -0
  95. package/lib/internal/Selection.js +10 -0
  96. package/package.json +8 -8
  97. package/telemetry.yml +2 -9
@@ -18,6 +18,7 @@ interface UseSelectionProps<ItemType> {
18
18
  export declare const useSelection: <ItemType>({ disabled, onChange, initialSelectedItems, selectedItems: controlledItems, selectAll, filteredItems, }: UseSelectionProps<ItemType>) => {
19
19
  clearSelection: () => void;
20
20
  onItemChange: (item: ItemType) => void;
21
+ toggleAll: (items: ItemType[]) => void;
21
22
  selectedItems: ItemType[];
22
23
  };
23
24
  interface SelectionRenderProps<ItemType> {
@@ -90,6 +90,15 @@ const useSelection = ({
90
90
  selectedItems: []
91
91
  });
92
92
  }, [disabled, isControlled]);
93
+ const toggleAll = useCallback(items => {
94
+ callOnChangeHandler({
95
+ isControlled,
96
+ isMounted: isMounted.current,
97
+ onChangeHandlerControlled: savedOnChange.current,
98
+ onChangeHandlerUncontrolled: setUncontrolledItems,
99
+ selectedItems: items
100
+ });
101
+ }, [isControlled]);
93
102
  useEffect(() => {
94
103
  savedOnChange.current = onChange;
95
104
  }, [onChange]);
@@ -109,6 +118,7 @@ const useSelection = ({
109
118
  return {
110
119
  clearSelection,
111
120
  onItemChange,
121
+ toggleAll,
112
122
  selectedItems
113
123
  };
114
124
  };
@@ -5,6 +5,7 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
+ import type { DeprecatedPopoverAlignment, NewPopoverAlignment, PopoverAlignment } from '../Popover';
8
9
  export type AILabelContentProps = React.HTMLAttributes<HTMLSpanElement>;
9
10
  export declare const AILabelContent: React.ForwardRefExoticComponent<AILabelContentProps & React.RefAttributes<unknown>>;
10
11
  export type AILabelActionsProps = React.HTMLAttributes<HTMLSpanElement>;
@@ -13,9 +14,9 @@ export declare const AILabelActions: React.ForwardRefExoticComponent<AILabelActi
13
14
  * Deprecated popover alignment values.
14
15
  * @deprecated Use NewPopoverAlignment instead.
15
16
  */
16
- export type DeprecatedAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-bottom' | 'left-top' | 'right-bottom' | 'right-top';
17
- export type NewAlignment = 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
18
- export type Alignment = DeprecatedAlignment | NewAlignment;
17
+ export type DeprecatedAlignment = DeprecatedPopoverAlignment;
18
+ export type NewAlignment = NewPopoverAlignment;
19
+ export type Alignment = PopoverAlignment;
19
20
  export interface AILabelProps {
20
21
  AILabelContent?: React.ReactNode;
21
22
  aiText?: string;
@@ -188,7 +188,9 @@ AILabel.propTypes = {
188
188
  */
189
189
  'aria-label': PropTypes.string,
190
190
  /**
191
- * Will auto-align the popover. This prop is currently experimental and is subject to future changes.
191
+ * Will auto-align the popover. This prop is currently experimental and is
192
+ * subject to future changes. Requires React v17+
193
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
192
194
  */
193
195
  autoAlign: PropTypes.bool,
194
196
  /**
@@ -113,7 +113,9 @@ Button.propTypes = {
113
113
  */
114
114
  as: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.elementType]),
115
115
  /**
116
- * **Experimental**: Will attempt to automatically align the tooltip
116
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
117
+ * React v17+
118
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
117
119
  */
118
120
  autoAlign: PropTypes.bool,
119
121
  /**
@@ -6,16 +6,18 @@
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
8
  import { PropsWithChildren } from 'react';
9
- export type DeprecatedCodeSnippetAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-bottom' | 'left-top' | 'right-bottom' | 'right-top';
10
- export type NewCodeSnippetAlignment = 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
11
- export type CodeSnippetAlignment = DeprecatedCodeSnippetAlignment | NewCodeSnippetAlignment;
9
+ import type { DeprecatedPopoverAlignment, NewPopoverAlignment, PopoverAlignment } from '../Popover';
10
+ export type DeprecatedCodeSnippetAlignment = DeprecatedPopoverAlignment;
11
+ export type NewCodeSnippetAlignment = NewPopoverAlignment;
12
+ export type CodeSnippetAlignment = PopoverAlignment;
12
13
  export interface CodeSnippetProps {
13
14
  /**
14
15
  * Specify how the trigger should align with the tooltip
15
16
  */
16
17
  align?: CodeSnippetAlignment;
17
18
  /**
18
- * **Experimental**: Will attempt to automatically align the tooltip
19
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires React v17+
20
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
19
21
  */
20
22
  autoAlign?: boolean;
21
23
  /**
@@ -122,7 +124,9 @@ declare namespace CodeSnippet {
122
124
  */
123
125
  ariaLabel: (props: Record<string, any>, propName: string, componentName: string, ...rest: any[]) => any;
124
126
  /**
125
- * **Experimental**: Will attempt to automatically align the tooltip
127
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
128
+ * React v17+
129
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
126
130
  */
127
131
  autoAlign: PropTypes.Requireable<boolean>;
128
132
  /**
@@ -272,7 +272,9 @@ CodeSnippet.propTypes = {
272
272
  */
273
273
  ariaLabel: deprecate.deprecate(PropTypes.string, 'This prop syntax has been deprecated. Please use the new `aria-label`.'),
274
274
  /**
275
- * **Experimental**: Will attempt to automatically align the tooltip
275
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
276
+ * React v17+
277
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
276
278
  */
277
279
  autoAlign: PropTypes.bool,
278
280
  /**
@@ -41,7 +41,8 @@ export interface ComboBoxProps<ItemType> extends Omit<InputHTMLAttributes<HTMLIn
41
41
  /**
42
42
  * **Experimental**: Will attempt to automatically align the floating
43
43
  * element to avoid collisions with the viewport and being clipped by
44
- * ancestor elements.
44
+ * ancestor elements. Requires React v17+
45
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
45
46
  */
46
47
  autoAlign?: boolean;
47
48
  /**
@@ -780,7 +780,8 @@ ComboBox.propTypes = {
780
780
  /**
781
781
  * **Experimental**: Will attempt to automatically align the floating
782
782
  * element to avoid collisions with the viewport and being clipped by
783
- * ancestor elements.
783
+ * ancestor elements. Requires React v17+
784
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
784
785
  */
785
786
  autoAlign: PropTypes.bool,
786
787
  /**
@@ -7,9 +7,9 @@
7
7
  import React, { ReactNode } from 'react';
8
8
  import ContainedListItem from './ContainedListItem';
9
9
  declare const variants: readonly ["on-page", "disclosed"];
10
- export interface ContainedListType extends React.FC<ContainedListProps> {
10
+ export type ContainedListType = React.FC<ContainedListProps> & {
11
11
  ContainedListItem: typeof ContainedListItem;
12
- }
12
+ };
13
13
  export type Variants = (typeof variants)[number];
14
14
  export interface ContainedListProps {
15
15
  /**
@@ -6,12 +6,7 @@
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
8
  import { type HTMLAttributes, type ReactElement } from 'react';
9
- export interface SwitchEventHandlersParams {
10
- index?: number;
11
- name?: string | number;
12
- text?: string;
13
- key?: string | number;
14
- }
9
+ import type { SwitchEventHandlersParams } from '../Switch/Switch';
15
10
  export interface ContentSwitcherProps extends Omit<HTMLAttributes<HTMLElement>, 'onChange'> {
16
11
  /**
17
12
  * Pass in Switch components to be rendered in the ContentSwitcher
@@ -6,16 +6,18 @@
6
6
  */
7
7
  import PropTypes from 'prop-types';
8
8
  import React, { AnimationEventHandler, MouseEventHandler, PropsWithChildren } from 'react';
9
- export type DeprecatedCopyAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-bottom' | 'left-top' | 'right-bottom' | 'right-top';
10
- export type NewCopyAlignment = 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
11
- export type CopyAlignment = DeprecatedCopyAlignment | NewCopyAlignment;
9
+ import type { DeprecatedPopoverAlignment, NewPopoverAlignment, PopoverAlignment } from '../Popover';
10
+ export type DeprecatedCopyAlignment = DeprecatedPopoverAlignment;
11
+ export type NewCopyAlignment = NewPopoverAlignment;
12
+ export type CopyAlignment = PopoverAlignment;
12
13
  export interface CopyProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
14
  /**
14
15
  * Specify how the trigger should align with the tooltip
15
16
  */
16
17
  align?: CopyAlignment;
17
18
  /**
18
- * **Experimental**: Will attempt to automatically align the tooltip
19
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires React v17+
20
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
19
21
  */
20
22
  autoAlign?: boolean;
21
23
  /**
@@ -50,7 +52,9 @@ declare namespace Copy {
50
52
  */
51
53
  align: (props: any, propName: any, componentName: any, ...rest: any[]) => any;
52
54
  /**
53
- * **Experimental**: Will attempt to automatically align the tooltip
55
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
56
+ * React v17+
57
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
54
58
  */
55
59
  autoAlign: PropTypes.Requireable<boolean>;
56
60
  /**
@@ -94,7 +94,9 @@ Copy.propTypes = {
94
94
  // new values to match floating-ui
95
95
  'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']), ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'], mapPopoverAlign.mapPopoverAlign),
96
96
  /**
97
- * **Experimental**: Will attempt to automatically align the tooltip
97
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
98
+ * React v17+
99
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
98
100
  */
99
101
  autoAlign: PropTypes.bool,
100
102
  /**
@@ -7,16 +7,18 @@
7
7
  import PropTypes from 'prop-types';
8
8
  import { MouseEventHandler } from 'react';
9
9
  import { ButtonProps } from '../Button';
10
- export type DeprecatedCopyButtonAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-bottom' | 'left-top' | 'right-bottom' | 'right-top';
11
- export type NewCopyButtonAlignment = 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
12
- export type CopyButtonAlignment = DeprecatedCopyButtonAlignment | NewCopyButtonAlignment;
10
+ import type { DeprecatedPopoverAlignment, NewPopoverAlignment, PopoverAlignment } from '../Popover';
11
+ export type DeprecatedCopyButtonAlignment = DeprecatedPopoverAlignment;
12
+ export type NewCopyButtonAlignment = NewPopoverAlignment;
13
+ export type CopyButtonAlignment = PopoverAlignment;
13
14
  export interface CopyButtonProps extends ButtonProps<'button'> {
14
15
  /**
15
16
  * Specify how the trigger should align with the tooltip
16
17
  */
17
18
  align?: CopyButtonAlignment;
18
19
  /**
19
- * **Experimental**: Will attempt to automatically align the tooltip
20
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires React v17+
21
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
20
22
  */
21
23
  autoAlign?: boolean;
22
24
  /**
@@ -51,7 +53,9 @@ declare namespace CopyButton {
51
53
  */
52
54
  align: (props: any, propName: any, componentName: any, ...rest: any[]) => any;
53
55
  /**
54
- * **Experimental**: Will attempt to automatically align the tooltip
56
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
57
+ * React v17+
58
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
55
59
  */
56
60
  autoAlign: PropTypes.Requireable<boolean>;
57
61
  /**
@@ -76,7 +76,9 @@ CopyButton.propTypes = {
76
76
  // new values to match floating-ui
77
77
  'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']), ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'], mapPopoverAlign.mapPopoverAlign),
78
78
  /**
79
- * **Experimental**: Will attempt to automatically align the tooltip
79
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
80
+ * React v17+
81
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
80
82
  */
81
83
  autoAlign: PropTypes.bool,
82
84
  /**
@@ -24,7 +24,10 @@ export interface DropdownProps<ItemType> extends Omit<HTMLAttributes<HTMLDivElem
24
24
  */
25
25
  ariaLabel?: string;
26
26
  /**
27
- * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
27
+ * **Experimental**: Will attempt to automatically align the floating element
28
+ * to avoid collisions with the viewport and being clipped by ancestor
29
+ * elements. Requires React v17+
30
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
28
31
  */
29
32
  autoAlign?: boolean;
30
33
  /**
@@ -400,7 +400,10 @@ Dropdown.propTypes = {
400
400
  */
401
401
  ariaLabel: deprecate.deprecate(PropTypes.string, 'This prop syntax has been deprecated. Please use the new `aria-label`.'),
402
402
  /**
403
- * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
403
+ * **Experimental**: Will attempt to automatically align the floating element
404
+ * to avoid collisions with the viewport and being clipped by ancestor
405
+ * elements. Requires React v17+
406
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
404
407
  */
405
408
  autoAlign: PropTypes.bool,
406
409
  /**
@@ -67,9 +67,12 @@ function FileUploaderButton({
67
67
  }
68
68
  }
69
69
  function onKeyDown(event) {
70
- if (match.matches(event, [keys.Enter, keys.Space]) && inputNode.current) {
71
- inputNode.current.value = '';
72
- inputNode.current.click();
70
+ if (match.matches(event, [keys.Enter, keys.Space])) {
71
+ event.preventDefault();
72
+ if (inputNode.current) {
73
+ inputNode.current.value = '';
74
+ inputNode.current.click();
75
+ }
73
76
  }
74
77
  }
75
78
  function handleOnChange(event) {
@@ -6,18 +6,20 @@
6
6
  */
7
7
  import React, { ReactNode } from 'react';
8
8
  import { ButtonSize } from '../Button';
9
+ import type { DeprecatedPopoverAlignment, NewPopoverAlignment, PopoverAlignment } from '../Popover';
9
10
  export declare const IconButtonKinds: readonly ["primary", "secondary", "ghost", "tertiary"];
10
11
  export type IconButtonKind = (typeof IconButtonKinds)[number];
11
- export type DeprecatedIconButtonAlignment = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left-bottom' | 'left-top' | 'right-bottom' | 'right-top';
12
- export type NewIconButtonAlignment = 'top' | 'bottom' | 'left' | 'right' | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-end' | 'left-start' | 'right-end' | 'right-start';
13
- export type IconButtonAlignment = DeprecatedIconButtonAlignment | NewIconButtonAlignment;
12
+ export type DeprecatedIconButtonAlignment = DeprecatedPopoverAlignment;
13
+ export type NewIconButtonAlignment = NewPopoverAlignment;
14
+ export type IconButtonAlignment = PopoverAlignment;
14
15
  export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
15
16
  /**
16
17
  * Specify how the trigger should align with the tooltip
17
18
  */
18
19
  align?: IconButtonAlignment;
19
20
  /**
20
- * **Experimental**: Will attempt to automatically align the tooltip
21
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires React v17+
22
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
21
23
  */
22
24
  autoAlign?: boolean;
23
25
  /**
@@ -101,7 +101,9 @@ IconButton.propTypes = {
101
101
  // new values to match floating-ui
102
102
  'top-start', 'top-end', 'bottom-start', 'bottom-end', 'left-end', 'left-start', 'right-end', 'right-start']), ['top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end'], mapPopoverAlign.mapPopoverAlign),
103
103
  /**
104
- * **Experimental**: Will attempt to automatically align the tooltip
104
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
105
+ * React v17+
106
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
105
107
  */
106
108
  autoAlign: PropTypes.bool,
107
109
  /**
@@ -156,9 +158,6 @@ IconButton.propTypes = {
156
158
  /**
157
159
  * Provide the label to be rendered inside of the Tooltip. The label will use
158
160
  * `aria-labelledby` and will fully describe the child node that is provided.
159
- * If the child node already has an `aria-label`, the tooltip will not apply
160
- * `aria-labelledby`. If the child node has `aria-labelledby`, that value will
161
- * be used instead. Otherwise, the tooltip will use its own ID as the label.
162
161
  * This means that if you have text in the child node it will not be
163
162
  * announced to the screen reader.
164
163
  * If using `badgeCount={0}`, make sure the label explains that there is a
@@ -28,7 +28,8 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
28
28
  /**
29
29
  * **Experimental**: Will attempt to automatically align the floating
30
30
  * element to avoid collisions with the viewport and being clipped by
31
- * ancestor elements.
31
+ * ancestor elements. Requires React v17+
32
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
32
33
  */
33
34
  autoAlign?: boolean;
34
35
  className?: string;
@@ -62,7 +63,9 @@ export interface FilterableMultiSelectProps<ItemType> extends MultiSelectSorting
62
63
  */
63
64
  downshiftProps?: UseMultipleSelectionProps<ItemType>;
64
65
  /**
65
- * Default sorter is assigned if not provided.
66
+ * Provide a method that filters the dropdown options based on the current input. Overriding this
67
+ * prop means that you have to handle the filtering logic when the user types in the text input.
68
+ * Otherwise, a default built-in filtering function will be used.
66
69
  */
67
70
  filterItems?(items: readonly ItemType[], extra: {
68
71
  inputValue: string | null;
@@ -17,6 +17,8 @@ var React = require('react');
17
17
  var filter = require('./filter.js');
18
18
  var MultiSelectPropTypes = require('./MultiSelectPropTypes.js');
19
19
  var index$1 = require('../ListBox/index.js');
20
+ var Checkbox = require('../Checkbox/Checkbox.js');
21
+ require('../Checkbox/Checkbox.Skeleton.js');
20
22
  var ListBoxSelection = require('../ListBox/next/ListBoxSelection.js');
21
23
  var ListBoxTrigger = require('../ListBox/next/ListBoxTrigger.js');
22
24
  var keys = require('../../internal/keyboard/keys.js');
@@ -117,16 +119,56 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
117
119
  const [inputValue, setInputValue] = React.useState('');
118
120
  const [topItems, setTopItems] = React.useState(initialSelectedItems ?? []);
119
121
  const [inputFocused, setInputFocused] = React.useState(false);
122
+ const filteredItems = React.useMemo(() => filterItems(items, {
123
+ itemToString: itemToString$1,
124
+ inputValue
125
+ }), [items, inputValue, itemToString$1, filterItems]);
126
+ const nonSelectAllItems = React.useMemo(() => filteredItems.filter(item => !item.isSelectAll), [filteredItems]);
127
+ let selectAll = filteredItems.some(item => item.isSelectAll);
128
+ if ((selected ?? []).length > 0 && selectAll) {
129
+ console.warn('Warning: `selectAll` should not be used when `selectedItems` is provided. Please pass either `selectAll` or `selectedItems`, not both.');
130
+ selectAll = false;
131
+ }
120
132
  const {
121
133
  selectedItems: controlledSelectedItems,
122
134
  onItemChange,
123
- clearSelection
135
+ clearSelection,
136
+ toggleAll
124
137
  } = Selection.useSelection({
125
138
  disabled,
126
139
  initialSelectedItems,
127
140
  onChange,
128
- selectedItems: selected
141
+ selectedItems: selected,
142
+ selectAll,
143
+ filteredItems
129
144
  });
145
+ const selectAllStatus = React.useMemo(() => {
146
+ const selectable = nonSelectAllItems.filter(item => !item.disabled);
147
+ const nonSelectedCount = selectable.filter(item => !controlledSelectedItems.some(sel => isEqual(sel, item))).length;
148
+ const totalCount = selectable.length;
149
+ return {
150
+ checked: totalCount > 0 && nonSelectedCount === 0,
151
+ indeterminate: nonSelectedCount > 0 && nonSelectedCount < totalCount
152
+ };
153
+ }, [controlledSelectedItems, nonSelectAllItems]);
154
+ const handleSelectAllClick = React.useCallback(() => {
155
+ const selectable = nonSelectAllItems.filter(i => !i.disabled);
156
+ const {
157
+ checked,
158
+ indeterminate
159
+ } = selectAllStatus;
160
+
161
+ // clear all options if select-all state is checked or indeterminate
162
+ if (checked || indeterminate) {
163
+ const remainingSelectedItems = controlledSelectedItems.filter(sel => !filteredItems.some(e => isEqual(e, sel)));
164
+ toggleAll(remainingSelectedItems);
165
+
166
+ // select all options if select-all state is empty
167
+ } else {
168
+ const toSelect = selectable.filter(e => !controlledSelectedItems.some(sel => isEqual(sel, e)));
169
+ toggleAll([...controlledSelectedItems, ...toSelect]);
170
+ }
171
+ }, [nonSelectAllItems, selectAllStatus, controlledSelectedItems, toggleAll]);
130
172
  const {
131
173
  refs,
132
174
  floatingStyles,
@@ -177,10 +219,11 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
177
219
  // memoize sorted items to reduce unnecessary expensive sort on rerender
178
220
  const sortedItems = React.useMemo(() => {
179
221
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
180
- return sortItems(filterItems(items, {
181
- itemToString: itemToString$1,
182
- inputValue
183
- }), {
222
+ const selectAllItem = items.find(item => item.isSelectAll);
223
+ const selectableRealItems = nonSelectAllItems.filter(item => !item.disabled);
224
+
225
+ // Sort only non-select-all items, select-all item must stay at the top
226
+ const sortedReal = sortItems(nonSelectAllItems, {
184
227
  selectedItems: {
185
228
  top: controlledSelectedItems,
186
229
  fixed: [],
@@ -190,7 +233,13 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
190
233
  compareItems,
191
234
  locale
192
235
  });
193
- }, [items, inputValue, controlledSelectedItems, topItems, selectionFeedback, itemToString$1, compareItems, locale]);
236
+
237
+ // Only show select-all-item if there exist non-disabled filtered items to select
238
+ if (selectAllItem && selectableRealItems.length > 0) {
239
+ return [selectAllItem, ...sortedReal];
240
+ }
241
+ return sortedReal;
242
+ }, [items, inputValue, controlledSelectedItems, topItems, selectionFeedback, itemToString$1, compareItems, locale, sortItems, nonSelectAllItems]);
194
243
  const inline = type === 'inline';
195
244
  const showWarning = !invalid && warn;
196
245
  const wrapperClasses = cx(`${prefix}--multi-select__wrapper`, `${prefix}--multi-select--filterable__wrapper`, `${prefix}--list-box__wrapper`, containerClassName, {
@@ -313,8 +362,15 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
313
362
  }
314
363
  switch (type) {
315
364
  case InputKeyDownEnter:
365
+ if (sortedItems.length === 0) {
366
+ return changes;
367
+ }
316
368
  if (changes.selectedItem && changes.selectedItem.disabled !== true) {
317
- onItemChange(changes.selectedItem);
369
+ if (changes.selectedItem.isSelectAll) {
370
+ handleSelectAllClick();
371
+ } else {
372
+ onItemChange(changes.selectedItem);
373
+ }
318
374
  }
319
375
  setHighlightedIndex(changes.selectedItem);
320
376
  return {
@@ -322,7 +378,9 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
322
378
  highlightedIndex: state.highlightedIndex
323
379
  };
324
380
  case ItemClick:
325
- if (changes.selectedItem) {
381
+ if (changes.selectedItem.isSelectAll) {
382
+ handleSelectAllClick();
383
+ } else {
326
384
  onItemChange(changes.selectedItem);
327
385
  }
328
386
  setHighlightedIndex(changes.selectedItem);
@@ -455,6 +513,9 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
455
513
  const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/React.cloneElement(candidate, {
456
514
  size: 'mini'
457
515
  }) : null;
516
+
517
+ // exclude the select-all item from the count
518
+ const selectedItemsLength = controlledSelectedItems.filter(item => !item.isSelectAll).length;
458
519
  const className = cx(`${prefix}--multi-select`, `${prefix}--combo-box`, `${prefix}--multi-select--filterable`, {
459
520
  [`${prefix}--multi-select--invalid`]: invalid,
460
521
  [`${prefix}--multi-select--invalid--focused`]: invalid && inputFocused,
@@ -462,7 +523,8 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
462
523
  [`${prefix}--multi-select--inline`]: inline,
463
524
  [`${prefix}--multi-select--selected`]: controlledSelectedItems?.length > 0,
464
525
  [`${prefix}--multi-select--filterable--input-focused`]: inputFocused,
465
- [`${prefix}--multi-select--readonly`]: readOnly
526
+ [`${prefix}--multi-select--readonly`]: readOnly,
527
+ [`${prefix}--multi-select--selectall`]: selectAll
466
528
  });
467
529
  const labelProps = getLabelProps();
468
530
  const buttonProps = getToggleButtonProps({
@@ -600,7 +662,7 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
600
662
  textInput.current.focus();
601
663
  }
602
664
  },
603
- selectionCount: controlledSelectedItems.length,
665
+ selectionCount: selectedItemsLength,
604
666
  translateWithId: translateWithId,
605
667
  disabled: disabled
606
668
  }), /*#__PURE__*/React.createElement("input", _rollupPluginBabelHelpers.extends({
@@ -632,7 +694,14 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
632
694
  }))), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
633
695
  className: `${prefix}--list-box__inner-wrapper--decorator`
634
696
  }, normalizedDecorator) : '', /*#__PURE__*/React.createElement(index$1.default.Menu, menuProps, isOpen ? sortedItems.map((item, index) => {
635
- const isChecked = controlledSelectedItems.filter(selected => isEqual(selected, item)).length > 0;
697
+ let isChecked;
698
+ let isIndeterminate = false;
699
+ if (item.isSelectAll) {
700
+ isChecked = selectAllStatus.checked;
701
+ isIndeterminate = selectAllStatus.indeterminate;
702
+ } else {
703
+ isChecked = controlledSelectedItems.filter(selected => isEqual(selected, item)).length > 0;
704
+ }
636
705
  const itemProps = getItemProps({
637
706
  item,
638
707
  ['aria-selected']: isChecked
@@ -652,20 +721,23 @@ const FilterableMultiSelect = /*#__PURE__*/React.forwardRef(function FilterableM
652
721
  return /*#__PURE__*/React.createElement(index$1.default.MenuItem, _rollupPluginBabelHelpers.extends({
653
722
  key: itemProps.id,
654
723
  "aria-label": itemText,
655
- isActive: isChecked,
724
+ isActive: isChecked && !item['isSelectAll'],
656
725
  isHighlighted: highlightedIndex === index,
657
726
  title: itemText,
658
727
  disabled: disabled
659
728
  }, modifiedItemProps), /*#__PURE__*/React.createElement("div", {
660
729
  className: `${prefix}--checkbox-wrapper`
661
- }, /*#__PURE__*/React.createElement("span", {
730
+ }, /*#__PURE__*/React.createElement(Checkbox.default, {
731
+ id: `${itemProps.id}-item`,
732
+ labelText: ItemToElement ? /*#__PURE__*/React.createElement(ItemToElement, _rollupPluginBabelHelpers.extends({
733
+ key: itemProps.id
734
+ }, item)) : itemText,
735
+ checked: isChecked,
662
736
  title: useTitleInItem ? itemText : undefined,
663
- className: `${prefix}--checkbox-label`,
664
- "data-contained-checkbox-state": isChecked,
665
- id: `${itemProps.id}-item`
666
- }, ItemToElement ? /*#__PURE__*/React.createElement(ItemToElement, _rollupPluginBabelHelpers.extends({
667
- key: itemProps.id
668
- }, item)) : itemText)));
737
+ indeterminate: isIndeterminate,
738
+ disabled: disabled,
739
+ tabIndex: -1
740
+ })));
669
741
  }) : null)), !inline && !invalid && !warn ? helper : null);
670
742
  });
671
743
  FilterableMultiSelect.displayName = 'FilterableMultiSelect';
@@ -683,7 +755,8 @@ FilterableMultiSelect.propTypes = {
683
755
  /**
684
756
  * **Experimental**: Will attempt to automatically align the floating
685
757
  * element to avoid collisions with the viewport and being clipped by
686
- * ancestor elements.
758
+ * ancestor elements. Requires React v17+
759
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
687
760
  */
688
761
  autoAlign: PropTypes.bool,
689
762
  /**
@@ -698,6 +771,12 @@ FilterableMultiSelect.propTypes = {
698
771
  * **Experimental**: Provide a decorator component to be rendered inside the `FilterableMultiSelect` component
699
772
  */
700
773
  decorator: PropTypes.node,
774
+ /**
775
+ * Provide a method that filters the dropdown options based on the current input. Overriding this
776
+ * prop means that you have to handle the filtering logic when the user types in the text input.
777
+ * Otherwise, a default built-in filtering function will be used.
778
+ */
779
+ filterItems: PropTypes.func,
701
780
  /**
702
781
  * Specify the direction of the multiselect dropdown. Can be either top or bottom.
703
782
  */
@@ -17,7 +17,8 @@ export interface MultiSelectProps<ItemType> extends MultiSelectSortingProps<Item
17
17
  /**
18
18
  * **Experimental**: Will attempt to automatically align the floating
19
19
  * element to avoid collisions with the viewport and being clipped by
20
- * ancestor elements.
20
+ * ancestor elements. Requires React v17+
21
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
21
22
  */
22
23
  autoAlign?: boolean;
23
24
  className?: string;
@@ -538,7 +538,8 @@ MultiSelect.propTypes = {
538
538
  /**
539
539
  * **Experimental**: Will attempt to automatically align the floating
540
540
  * element to avoid collisions with the viewport and being clipped by
541
- * ancestor elements.
541
+ * ancestor elements. Requires React v17+
542
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
542
543
  */
543
544
  autoAlign: PropTypes.bool,
544
545
  /**