@carbon/react 1.87.1-rc.0 → 1.88.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 (95) hide show
  1. package/.playwright/INTERNAL_AVT_REPORT_DO_NOT_USE.json +792 -792
  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/ContentSwitcher/ContentSwitcher.d.ts +1 -6
  10. package/es/components/Copy/Copy.d.ts +9 -5
  11. package/es/components/Copy/Copy.js +3 -1
  12. package/es/components/CopyButton/CopyButton.d.ts +9 -5
  13. package/es/components/CopyButton/CopyButton.js +3 -1
  14. package/es/components/Dropdown/Dropdown.d.ts +4 -1
  15. package/es/components/Dropdown/Dropdown.js +4 -1
  16. package/es/components/FileUploader/FileUploaderButton.js +6 -3
  17. package/es/components/IconButton/index.d.ts +6 -4
  18. package/es/components/IconButton/index.js +3 -4
  19. package/es/components/MultiSelect/FilterableMultiSelect.d.ts +5 -2
  20. package/es/components/MultiSelect/FilterableMultiSelect.js +101 -22
  21. package/es/components/MultiSelect/MultiSelect.d.ts +2 -1
  22. package/es/components/MultiSelect/MultiSelect.js +2 -1
  23. package/es/components/Notification/Notification.d.ts +9 -1
  24. package/es/components/Notification/Notification.js +9 -1
  25. package/es/components/NumberInput/NumberInput.d.ts +4 -0
  26. package/es/components/NumberInput/NumberInput.js +12 -7
  27. package/es/components/OverflowMenu/next/index.d.ts +6 -2
  28. package/es/components/OverflowMenu/next/index.js +4 -1
  29. package/es/components/Popover/index.d.ts +4 -1
  30. package/es/components/Popover/index.js +12 -2
  31. package/es/components/Switch/IconSwitch.d.ts +44 -2
  32. package/es/components/Switch/IconSwitch.js +34 -27
  33. package/es/components/Switch/Switch.js +1 -0
  34. package/es/components/Toggletip/index.d.ts +4 -1
  35. package/es/components/Toggletip/index.js +4 -1
  36. package/es/components/Tooltip/DefinitionTooltip.d.ts +4 -2
  37. package/es/components/Tooltip/DefinitionTooltip.js +3 -1
  38. package/es/components/Tooltip/Tooltip.d.ts +0 -3
  39. package/es/components/Tooltip/Tooltip.js +2 -10
  40. package/es/components/TreeView/TreeContext.d.ts +1 -2
  41. package/es/components/TreeView/TreeNode.d.ts +12 -8
  42. package/es/components/TreeView/TreeNode.js +3 -9
  43. package/es/components/TreeView/TreeView.d.ts +7 -5
  44. package/es/components/TreeView/TreeView.js +20 -22
  45. package/es/components/UIShell/HeaderPanel.js +1 -1
  46. package/es/internal/Selection.d.ts +1 -0
  47. package/es/internal/Selection.js +10 -0
  48. package/lib/components/AILabel/index.d.ts +4 -3
  49. package/lib/components/AILabel/index.js +3 -1
  50. package/lib/components/Button/Button.js +3 -1
  51. package/lib/components/CodeSnippet/CodeSnippet.d.ts +9 -5
  52. package/lib/components/CodeSnippet/CodeSnippet.js +3 -1
  53. package/lib/components/ComboBox/ComboBox.d.ts +2 -1
  54. package/lib/components/ComboBox/ComboBox.js +2 -1
  55. package/lib/components/ContentSwitcher/ContentSwitcher.d.ts +1 -6
  56. package/lib/components/Copy/Copy.d.ts +9 -5
  57. package/lib/components/Copy/Copy.js +3 -1
  58. package/lib/components/CopyButton/CopyButton.d.ts +9 -5
  59. package/lib/components/CopyButton/CopyButton.js +3 -1
  60. package/lib/components/Dropdown/Dropdown.d.ts +4 -1
  61. package/lib/components/Dropdown/Dropdown.js +4 -1
  62. package/lib/components/FileUploader/FileUploaderButton.js +6 -3
  63. package/lib/components/IconButton/index.d.ts +6 -4
  64. package/lib/components/IconButton/index.js +3 -4
  65. package/lib/components/MultiSelect/FilterableMultiSelect.d.ts +5 -2
  66. package/lib/components/MultiSelect/FilterableMultiSelect.js +100 -21
  67. package/lib/components/MultiSelect/MultiSelect.d.ts +2 -1
  68. package/lib/components/MultiSelect/MultiSelect.js +2 -1
  69. package/lib/components/Notification/Notification.d.ts +9 -1
  70. package/lib/components/Notification/Notification.js +9 -1
  71. package/lib/components/NumberInput/NumberInput.d.ts +4 -0
  72. package/lib/components/NumberInput/NumberInput.js +12 -7
  73. package/lib/components/OverflowMenu/next/index.d.ts +6 -2
  74. package/lib/components/OverflowMenu/next/index.js +4 -1
  75. package/lib/components/Popover/index.d.ts +4 -1
  76. package/lib/components/Popover/index.js +12 -2
  77. package/lib/components/Switch/IconSwitch.d.ts +44 -2
  78. package/lib/components/Switch/IconSwitch.js +35 -28
  79. package/lib/components/Switch/Switch.js +1 -0
  80. package/lib/components/Toggletip/index.d.ts +4 -1
  81. package/lib/components/Toggletip/index.js +4 -1
  82. package/lib/components/Tooltip/DefinitionTooltip.d.ts +4 -2
  83. package/lib/components/Tooltip/DefinitionTooltip.js +3 -1
  84. package/lib/components/Tooltip/Tooltip.d.ts +0 -3
  85. package/lib/components/Tooltip/Tooltip.js +2 -10
  86. package/lib/components/TreeView/TreeContext.d.ts +1 -2
  87. package/lib/components/TreeView/TreeNode.d.ts +12 -8
  88. package/lib/components/TreeView/TreeNode.js +3 -9
  89. package/lib/components/TreeView/TreeView.d.ts +7 -5
  90. package/lib/components/TreeView/TreeView.js +20 -22
  91. package/lib/components/UIShell/HeaderPanel.js +2 -2
  92. package/lib/internal/Selection.d.ts +1 -0
  93. package/lib/internal/Selection.js +10 -0
  94. package/package.json +7 -7
  95. package/telemetry.yml +2 -9
@@ -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;
@@ -186,7 +186,9 @@ AILabel.propTypes = {
186
186
  */
187
187
  'aria-label': PropTypes.string,
188
188
  /**
189
- * Will auto-align the popover. This prop is currently experimental and is subject to future changes.
189
+ * Will auto-align the popover. This prop is currently experimental and is
190
+ * subject to future changes. Requires React v17+
191
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
190
192
  */
191
193
  autoAlign: PropTypes.bool,
192
194
  /**
@@ -109,7 +109,9 @@ Button.propTypes = {
109
109
  */
110
110
  as: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.elementType]),
111
111
  /**
112
- * **Experimental**: Will attempt to automatically align the tooltip
112
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
113
+ * React v17+
114
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
113
115
  */
114
116
  autoAlign: PropTypes.bool,
115
117
  /**
@@ -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
  /**
@@ -268,7 +268,9 @@ CodeSnippet.propTypes = {
268
268
  */
269
269
  ariaLabel: deprecate(PropTypes.string, 'This prop syntax has been deprecated. Please use the new `aria-label`.'),
270
270
  /**
271
- * **Experimental**: Will attempt to automatically align the tooltip
271
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
272
+ * React v17+
273
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
272
274
  */
273
275
  autoAlign: PropTypes.bool,
274
276
  /**
@@ -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
  /**
@@ -776,7 +776,8 @@ ComboBox.propTypes = {
776
776
  /**
777
777
  * **Experimental**: Will attempt to automatically align the floating
778
778
  * element to avoid collisions with the viewport and being clipped by
779
- * ancestor elements.
779
+ * ancestor elements. Requires React v17+
780
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
780
781
  */
781
782
  autoAlign: PropTypes.bool,
782
783
  /**
@@ -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
  /**
@@ -90,7 +90,9 @@ Copy.propTypes = {
90
90
  // new values to match floating-ui
91
91
  '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),
92
92
  /**
93
- * **Experimental**: Will attempt to automatically align the tooltip
93
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
94
+ * React v17+
95
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
94
96
  */
95
97
  autoAlign: PropTypes.bool,
96
98
  /**
@@ -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
  /**
@@ -72,7 +72,9 @@ CopyButton.propTypes = {
72
72
  // new values to match floating-ui
73
73
  '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),
74
74
  /**
75
- * **Experimental**: Will attempt to automatically align the tooltip
75
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
76
+ * React v17+
77
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
76
78
  */
77
79
  autoAlign: PropTypes.bool,
78
80
  /**
@@ -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
  /**
@@ -396,7 +396,10 @@ Dropdown.propTypes = {
396
396
  */
397
397
  ariaLabel: deprecate(PropTypes.string, 'This prop syntax has been deprecated. Please use the new `aria-label`.'),
398
398
  /**
399
- * **Experimental**: Will attempt to automatically align the floating element to avoid collisions with the viewport and being clipped by ancestor elements.
399
+ * **Experimental**: Will attempt to automatically align the floating element
400
+ * to avoid collisions with the viewport and being clipped by ancestor
401
+ * elements. Requires React v17+
402
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
400
403
  */
401
404
  autoAlign: PropTypes.bool,
402
405
  /**
@@ -63,9 +63,12 @@ function FileUploaderButton({
63
63
  }
64
64
  }
65
65
  function onKeyDown(event) {
66
- if (matches(event, [Enter, Space]) && inputNode.current) {
67
- inputNode.current.value = '';
68
- inputNode.current.click();
66
+ if (matches(event, [Enter, Space])) {
67
+ event.preventDefault();
68
+ if (inputNode.current) {
69
+ inputNode.current.value = '';
70
+ inputNode.current.click();
71
+ }
69
72
  }
70
73
  }
71
74
  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
  /**
@@ -99,7 +99,9 @@ IconButton.propTypes = {
99
99
  // new values to match floating-ui
100
100
  '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),
101
101
  /**
102
- * **Experimental**: Will attempt to automatically align the tooltip
102
+ * **Experimental**: Will attempt to automatically align the tooltip. Requires
103
+ * React v17+
104
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
103
105
  */
104
106
  autoAlign: PropTypes.bool,
105
107
  /**
@@ -154,9 +156,6 @@ IconButton.propTypes = {
154
156
  /**
155
157
  * Provide the label to be rendered inside of the Tooltip. The label will use
156
158
  * `aria-labelledby` and will fully describe the child node that is provided.
157
- * If the child node already has an `aria-label`, the tooltip will not apply
158
- * `aria-labelledby`. If the child node has `aria-labelledby`, that value will
159
- * be used instead. Otherwise, the tooltip will use its own ID as the label.
160
159
  * This means that if you have text in the child node it will not be
161
160
  * announced to the screen reader.
162
161
  * 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;
@@ -11,10 +11,12 @@ import cx from 'classnames';
11
11
  import Downshift, { useCombobox, useMultipleSelection } from 'downshift';
12
12
  import isEqual from 'react-fast-compare';
13
13
  import PropTypes from 'prop-types';
14
- import React, { forwardRef, useContext, useRef, useState, useLayoutEffect, useMemo, useEffect, cloneElement } from 'react';
14
+ import React, { forwardRef, useContext, useRef, useState, useMemo, useCallback, useLayoutEffect, useEffect, cloneElement } from 'react';
15
15
  import { defaultFilterItems } from './filter.js';
16
16
  import { sortingPropTypes } from './MultiSelectPropTypes.js';
17
17
  import ListBox from '../ListBox/index.js';
18
+ import Checkbox from '../Checkbox/Checkbox.js';
19
+ import '../Checkbox/Checkbox.Skeleton.js';
18
20
  import ListBoxSelection from '../ListBox/next/ListBoxSelection.js';
19
21
  import ListBoxTrigger from '../ListBox/next/ListBoxTrigger.js';
20
22
  import { Space, Enter, Delete, Escape, Tab, Home, End } from '../../internal/keyboard/keys.js';
@@ -115,16 +117,56 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
115
117
  const [inputValue, setInputValue] = useState('');
116
118
  const [topItems, setTopItems] = useState(initialSelectedItems ?? []);
117
119
  const [inputFocused, setInputFocused] = useState(false);
120
+ const filteredItems = useMemo(() => filterItems(items, {
121
+ itemToString,
122
+ inputValue
123
+ }), [items, inputValue, itemToString, filterItems]);
124
+ const nonSelectAllItems = useMemo(() => filteredItems.filter(item => !item.isSelectAll), [filteredItems]);
125
+ let selectAll = filteredItems.some(item => item.isSelectAll);
126
+ if ((selected ?? []).length > 0 && selectAll) {
127
+ console.warn('Warning: `selectAll` should not be used when `selectedItems` is provided. Please pass either `selectAll` or `selectedItems`, not both.');
128
+ selectAll = false;
129
+ }
118
130
  const {
119
131
  selectedItems: controlledSelectedItems,
120
132
  onItemChange,
121
- clearSelection
133
+ clearSelection,
134
+ toggleAll
122
135
  } = useSelection({
123
136
  disabled,
124
137
  initialSelectedItems,
125
138
  onChange,
126
- selectedItems: selected
139
+ selectedItems: selected,
140
+ selectAll,
141
+ filteredItems
127
142
  });
143
+ const selectAllStatus = useMemo(() => {
144
+ const selectable = nonSelectAllItems.filter(item => !item.disabled);
145
+ const nonSelectedCount = selectable.filter(item => !controlledSelectedItems.some(sel => isEqual(sel, item))).length;
146
+ const totalCount = selectable.length;
147
+ return {
148
+ checked: totalCount > 0 && nonSelectedCount === 0,
149
+ indeterminate: nonSelectedCount > 0 && nonSelectedCount < totalCount
150
+ };
151
+ }, [controlledSelectedItems, nonSelectAllItems]);
152
+ const handleSelectAllClick = useCallback(() => {
153
+ const selectable = nonSelectAllItems.filter(i => !i.disabled);
154
+ const {
155
+ checked,
156
+ indeterminate
157
+ } = selectAllStatus;
158
+
159
+ // clear all options if select-all state is checked or indeterminate
160
+ if (checked || indeterminate) {
161
+ const remainingSelectedItems = controlledSelectedItems.filter(sel => !filteredItems.some(e => isEqual(e, sel)));
162
+ toggleAll(remainingSelectedItems);
163
+
164
+ // select all options if select-all state is empty
165
+ } else {
166
+ const toSelect = selectable.filter(e => !controlledSelectedItems.some(sel => isEqual(sel, e)));
167
+ toggleAll([...controlledSelectedItems, ...toSelect]);
168
+ }
169
+ }, [nonSelectAllItems, selectAllStatus, controlledSelectedItems, toggleAll]);
128
170
  const {
129
171
  refs,
130
172
  floatingStyles,
@@ -175,10 +217,11 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
175
217
  // memoize sorted items to reduce unnecessary expensive sort on rerender
176
218
  const sortedItems = useMemo(() => {
177
219
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
178
- return sortItems(filterItems(items, {
179
- itemToString,
180
- inputValue
181
- }), {
220
+ const selectAllItem = items.find(item => item.isSelectAll);
221
+ const selectableRealItems = nonSelectAllItems.filter(item => !item.disabled);
222
+
223
+ // Sort only non-select-all items, select-all item must stay at the top
224
+ const sortedReal = sortItems(nonSelectAllItems, {
182
225
  selectedItems: {
183
226
  top: controlledSelectedItems,
184
227
  fixed: [],
@@ -188,7 +231,13 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
188
231
  compareItems,
189
232
  locale
190
233
  });
191
- }, [items, inputValue, controlledSelectedItems, topItems, selectionFeedback, itemToString, compareItems, locale]);
234
+
235
+ // Only show select-all-item if there exist non-disabled filtered items to select
236
+ if (selectAllItem && selectableRealItems.length > 0) {
237
+ return [selectAllItem, ...sortedReal];
238
+ }
239
+ return sortedReal;
240
+ }, [items, inputValue, controlledSelectedItems, topItems, selectionFeedback, itemToString, compareItems, locale, sortItems, nonSelectAllItems]);
192
241
  const inline = type === 'inline';
193
242
  const showWarning = !invalid && warn;
194
243
  const wrapperClasses = cx(`${prefix}--multi-select__wrapper`, `${prefix}--multi-select--filterable__wrapper`, `${prefix}--list-box__wrapper`, containerClassName, {
@@ -311,8 +360,15 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
311
360
  }
312
361
  switch (type) {
313
362
  case InputKeyDownEnter:
363
+ if (sortedItems.length === 0) {
364
+ return changes;
365
+ }
314
366
  if (changes.selectedItem && changes.selectedItem.disabled !== true) {
315
- onItemChange(changes.selectedItem);
367
+ if (changes.selectedItem.isSelectAll) {
368
+ handleSelectAllClick();
369
+ } else {
370
+ onItemChange(changes.selectedItem);
371
+ }
316
372
  }
317
373
  setHighlightedIndex(changes.selectedItem);
318
374
  return {
@@ -320,7 +376,9 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
320
376
  highlightedIndex: state.highlightedIndex
321
377
  };
322
378
  case ItemClick:
323
- if (changes.selectedItem) {
379
+ if (changes.selectedItem.isSelectAll) {
380
+ handleSelectAllClick();
381
+ } else {
324
382
  onItemChange(changes.selectedItem);
325
383
  }
326
384
  setHighlightedIndex(changes.selectedItem);
@@ -453,6 +511,9 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
453
511
  const normalizedDecorator = candidateIsAILabel ? /*#__PURE__*/cloneElement(candidate, {
454
512
  size: 'mini'
455
513
  }) : null;
514
+
515
+ // exclude the select-all item from the count
516
+ const selectedItemsLength = controlledSelectedItems.filter(item => !item.isSelectAll).length;
456
517
  const className = cx(`${prefix}--multi-select`, `${prefix}--combo-box`, `${prefix}--multi-select--filterable`, {
457
518
  [`${prefix}--multi-select--invalid`]: invalid,
458
519
  [`${prefix}--multi-select--invalid--focused`]: invalid && inputFocused,
@@ -460,7 +521,8 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
460
521
  [`${prefix}--multi-select--inline`]: inline,
461
522
  [`${prefix}--multi-select--selected`]: controlledSelectedItems?.length > 0,
462
523
  [`${prefix}--multi-select--filterable--input-focused`]: inputFocused,
463
- [`${prefix}--multi-select--readonly`]: readOnly
524
+ [`${prefix}--multi-select--readonly`]: readOnly,
525
+ [`${prefix}--multi-select--selectall`]: selectAll
464
526
  });
465
527
  const labelProps = getLabelProps();
466
528
  const buttonProps = getToggleButtonProps({
@@ -598,7 +660,7 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
598
660
  textInput.current.focus();
599
661
  }
600
662
  },
601
- selectionCount: controlledSelectedItems.length,
663
+ selectionCount: selectedItemsLength,
602
664
  translateWithId: translateWithId,
603
665
  disabled: disabled
604
666
  }), /*#__PURE__*/React.createElement("input", _extends({
@@ -630,7 +692,14 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
630
692
  }))), slug ? normalizedDecorator : decorator ? /*#__PURE__*/React.createElement("div", {
631
693
  className: `${prefix}--list-box__inner-wrapper--decorator`
632
694
  }, normalizedDecorator) : '', /*#__PURE__*/React.createElement(ListBox.Menu, menuProps, isOpen ? sortedItems.map((item, index) => {
633
- const isChecked = controlledSelectedItems.filter(selected => isEqual(selected, item)).length > 0;
695
+ let isChecked;
696
+ let isIndeterminate = false;
697
+ if (item.isSelectAll) {
698
+ isChecked = selectAllStatus.checked;
699
+ isIndeterminate = selectAllStatus.indeterminate;
700
+ } else {
701
+ isChecked = controlledSelectedItems.filter(selected => isEqual(selected, item)).length > 0;
702
+ }
634
703
  const itemProps = getItemProps({
635
704
  item,
636
705
  ['aria-selected']: isChecked
@@ -650,20 +719,23 @@ const FilterableMultiSelect = /*#__PURE__*/forwardRef(function FilterableMultiSe
650
719
  return /*#__PURE__*/React.createElement(ListBox.MenuItem, _extends({
651
720
  key: itemProps.id,
652
721
  "aria-label": itemText,
653
- isActive: isChecked,
722
+ isActive: isChecked && !item['isSelectAll'],
654
723
  isHighlighted: highlightedIndex === index,
655
724
  title: itemText,
656
725
  disabled: disabled
657
726
  }, modifiedItemProps), /*#__PURE__*/React.createElement("div", {
658
727
  className: `${prefix}--checkbox-wrapper`
659
- }, /*#__PURE__*/React.createElement("span", {
728
+ }, /*#__PURE__*/React.createElement(Checkbox, {
729
+ id: `${itemProps.id}-item`,
730
+ labelText: ItemToElement ? /*#__PURE__*/React.createElement(ItemToElement, _extends({
731
+ key: itemProps.id
732
+ }, item)) : itemText,
733
+ checked: isChecked,
660
734
  title: useTitleInItem ? itemText : undefined,
661
- className: `${prefix}--checkbox-label`,
662
- "data-contained-checkbox-state": isChecked,
663
- id: `${itemProps.id}-item`
664
- }, ItemToElement ? /*#__PURE__*/React.createElement(ItemToElement, _extends({
665
- key: itemProps.id
666
- }, item)) : itemText)));
735
+ indeterminate: isIndeterminate,
736
+ disabled: disabled,
737
+ tabIndex: -1
738
+ })));
667
739
  }) : null)), !inline && !invalid && !warn ? helper : null);
668
740
  });
669
741
  FilterableMultiSelect.displayName = 'FilterableMultiSelect';
@@ -681,7 +753,8 @@ FilterableMultiSelect.propTypes = {
681
753
  /**
682
754
  * **Experimental**: Will attempt to automatically align the floating
683
755
  * element to avoid collisions with the viewport and being clipped by
684
- * ancestor elements.
756
+ * ancestor elements. Requires React v17+
757
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
685
758
  */
686
759
  autoAlign: PropTypes.bool,
687
760
  /**
@@ -696,6 +769,12 @@ FilterableMultiSelect.propTypes = {
696
769
  * **Experimental**: Provide a decorator component to be rendered inside the `FilterableMultiSelect` component
697
770
  */
698
771
  decorator: PropTypes.node,
772
+ /**
773
+ * Provide a method that filters the dropdown options based on the current input. Overriding this
774
+ * prop means that you have to handle the filtering logic when the user types in the text input.
775
+ * Otherwise, a default built-in filtering function will be used.
776
+ */
777
+ filterItems: PropTypes.func,
699
778
  /**
700
779
  * Specify the direction of the multiselect dropdown. Can be either top or bottom.
701
780
  */
@@ -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;
@@ -536,7 +536,8 @@ MultiSelect.propTypes = {
536
536
  /**
537
537
  * **Experimental**: Will attempt to automatically align the floating
538
538
  * element to avoid collisions with the viewport and being clipped by
539
- * ancestor elements.
539
+ * ancestor elements. Requires React v17+
540
+ * @see https://github.com/carbon-design-system/carbon/issues/18714
540
541
  */
541
542
  autoAlign: PropTypes.bool,
542
543
  /**
@@ -367,6 +367,10 @@ export interface ActionableNotificationProps extends HTMLAttributes<HTMLDivEleme
367
367
  * Provide a description for "close" icon button that can be read by screen readers
368
368
  */
369
369
  'aria-label'?: string;
370
+ /**
371
+ * Specify the caption
372
+ */
373
+ caption?: string;
370
374
  /**
371
375
  * Specify the content
372
376
  */
@@ -430,7 +434,7 @@ export interface ActionableNotificationProps extends HTMLAttributes<HTMLDivEleme
430
434
  */
431
435
  title?: string;
432
436
  }
433
- export declare function ActionableNotification({ actionButtonLabel, ['aria-label']: ariaLabel, ariaLabel: deprecatedAriaLabel, children, role, onActionButtonClick, onClose, onCloseButtonClick, statusIconDescription, className, inline, kind, lowContrast, hideCloseButton, hasFocus, closeOnEscape, title, subtitle, ...rest }: ActionableNotificationProps): import("react/jsx-runtime").JSX.Element | null;
437
+ export declare function ActionableNotification({ actionButtonLabel, ['aria-label']: ariaLabel, ariaLabel: deprecatedAriaLabel, caption, children, role, onActionButtonClick, onClose, onCloseButtonClick, statusIconDescription, className, inline, kind, lowContrast, hideCloseButton, hasFocus, closeOnEscape, title, subtitle, ...rest }: ActionableNotificationProps): import("react/jsx-runtime").JSX.Element | null;
434
438
  export declare namespace ActionableNotification {
435
439
  var propTypes: {
436
440
  /**
@@ -446,6 +450,10 @@ export declare namespace ActionableNotification {
446
450
  * Provide a description for "close" icon button that can be read by screen readers
447
451
  */
448
452
  ariaLabel: (props: Record<string, any>, propName: string, componentName: string, ...rest: any[]) => any;
453
+ /**
454
+ * Specify the caption
455
+ */
456
+ caption: PropTypes.Requireable<string>;
449
457
  /**
450
458
  * Specify the content
451
459
  */