` element that is tied to the
diff --git a/packages/react/src/components/FluidComboBox/FluidComboBox.stories.js b/packages/react/src/components/FluidComboBox/FluidComboBox.stories.js
index de6e62746430..aefd4f0794aa 100644
--- a/packages/react/src/components/FluidComboBox/FluidComboBox.stories.js
+++ b/packages/react/src/components/FluidComboBox/FluidComboBox.stories.js
@@ -13,7 +13,10 @@ import {
ToggletipButton,
ToggletipContent,
} from '../Toggletip';
-import { Information } from '@carbon/icons-react';
+import { AILabel, AILabelContent, AILabelActions } from '../AILabel';
+import { IconButton } from '../IconButton';
+import { Button } from '../Button';
+import { Information, View, FolderOpen, Folders } from '@carbon/icons-react';
export default {
title: 'Experimental/Fluid Components/unstable__FluidComboBox',
@@ -92,6 +95,51 @@ export const Condensed = () => (
);
+const aiLabel = (
+
+
+
+
AI Explained
+
84%
+
Confidence score
+
+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
+
+
+
Model type
+
Foundation model
+
+
+
+
+
+
+
+
+
+
+
+ View details
+
+
+
+);
+
+export const withAILabel = () => (
+
+ {}}
+ id="default"
+ titleText="Label"
+ label="Choose an option"
+ items={items}
+ itemToString={(item) => (item ? item.text : '')}
+ decorator={aiLabel}
+ />
+
+);
+
export const Playground = (args) => (
(
);
+const aiLabel = (
+
+
+
+
AI Explained
+
84%
+
Confidence score
+
+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
+
+
+
Model type
+
Foundation model
+
+
+
+
+
+
+
+
+
+
+
+ View details
+
+
+
+);
+
+export const withAILabel = () => (
+
+ (item ? item.text : '')}
+ decorator={aiLabel}
+ />
+
+);
+
export const Playground = (args) => (
(
);
+const aiLabel = (
+
+
+
+
AI Explained
+
84%
+
Confidence score
+
+ Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
+
+
+
Model type
+
Foundation model
+
+
+
+
+
+
+
+
+
+
+
+ View details
+
+
+
+);
+
+export const withAILabel = () => (
+
+ {}}
+ initialSelectedItem={items[2]}
+ id="default"
+ titleText="Label"
+ label="Choose an option"
+ items={items}
+ itemToString={(item) => (item ? item.text : '')}
+ decorator={aiLabel}
+ />
+
+);
+
export const Playground = (args) => (
{
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
{
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
{
itemToString={(item) => (item ? item.text : '')}
titleText="ComboBox title"
helperText="Combobox helper text"
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
{
label="Choose an option"
items={items}
itemToString={(item) => (item ? item.text : '')}
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
@@ -456,7 +456,7 @@ export const withAILabel = (args) => {
label="Choose an option"
items={items}
itemToString={(item) => (item ? item.text : '')}
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
@@ -471,7 +471,7 @@ export const withAILabel = (args) => {
label="Choose an option"
items={items}
itemToString={(item) => (item ? item.text : '')}
- slug={aiLabel}
+ decorator={aiLabel}
{...rest}
/>
diff --git a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
index a61fa77b9518..e1a5893ab4be 100644
--- a/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
+++ b/packages/react/src/components/MultiSelect/FilterableMultiSelect.tsx
@@ -131,6 +131,11 @@ export interface FilterableMultiSelectProps
*/
clearSelectionText?: string;
+ /**
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `FilterableMultiSelect` component
+ */
+ decorator?: ReactNode;
+
/**
* Specify the direction of the multiselect dropdown.
*/
@@ -281,6 +286,7 @@ export interface FilterableMultiSelectProps
size?: 'sm' | 'md' | 'lg';
/**
+ * @deprecated please use decorator instead.
* **Experimental**: Provide a `Slug` component to be rendered inside the `Checkbox` component
*/
slug?: ReactNode;
@@ -318,6 +324,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
clearSelectionDescription = 'Total items selected: ',
clearSelectionText = 'To clear selection, press Delete or Backspace',
compareItems = defaultCompareItems,
+ decorator,
direction = 'bottom',
disabled = false,
downshiftProps,
@@ -467,6 +474,7 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
[`${prefix}--list-box__wrapper--fluid--invalid`]: isFluid && invalid,
[`${prefix}--list-box__wrapper--fluid--focus`]: isFluid && isFocused,
[`${prefix}--list-box__wrapper--slug`]: slug,
+ [`${prefix}--list-box__wrapper--decorator`]: decorator,
[`${prefix}--autoalign`]: autoAlign,
}
);
@@ -674,12 +682,20 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
}
}
- // Slug is always size `mini`
- let normalizedSlug;
- if (slug && slug['type']?.displayName === 'AILabel') {
- normalizedSlug = React.cloneElement(slug as React.ReactElement, {
- size: 'mini',
- });
+ // AILabel always size `mini`
+ let normalizedDecorator = React.isValidElement(slug ?? decorator)
+ ? (slug ?? decorator)
+ : null;
+ if (
+ normalizedDecorator &&
+ normalizedDecorator['type']?.displayName === 'AILabel'
+ ) {
+ normalizedDecorator = React.cloneElement(
+ normalizedDecorator as React.ReactElement,
+ {
+ size: 'mini',
+ }
+ );
}
const className = cx(
@@ -916,7 +932,15 @@ const FilterableMultiSelect = React.forwardRef(function FilterableMultiSelect<
translateWithId={translateWithId}
/>
- {normalizedSlug}
+ {slug ? (
+ normalizedDecorator
+ ) : decorator ? (
+
+ {normalizedDecorator}
+
+ ) : (
+ ''
+ )}
{isOpen
@@ -1016,6 +1040,11 @@ FilterableMultiSelect.propTypes = {
*/
clearSelectionText: PropTypes.string,
+ /**
+ * **Experimental**: Provide a decorator component to be rendered inside the `FilterableMultiSelect` component
+ */
+ decorator: PropTypes.node,
+
/**
* Specify the direction of the multiselect dropdown. Can be either top or bottom.
*/
@@ -1139,10 +1168,10 @@ FilterableMultiSelect.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,
- /**
- * **Experimental**: Provide a `Slug` component to be rendered inside the `FilterableMultiSelect` component
- */
- slug: PropTypes.node,
+ slug: deprecate(
+ PropTypes.node,
+ 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'
+ ),
...sortingPropTypes,
diff --git a/packages/react/src/components/MultiSelect/MultiSelect.stories.js b/packages/react/src/components/MultiSelect/MultiSelect.stories.js
index b6ffbae7c858..819d32671c8c 100644
--- a/packages/react/src/components/MultiSelect/MultiSelect.stories.js
+++ b/packages/react/src/components/MultiSelect/MultiSelect.stories.js
@@ -18,7 +18,6 @@ import ButtonSet from '../ButtonSet';
import { AILabel, AILabelContent, AILabelActions } from '../AILabel';
import { IconButton } from '../IconButton';
import { View, FolderOpen, Folders } from '@carbon/icons-react';
-import { Tabs, Tab, TabList, TabPanels, TabPanel } from '@carbon/react';
export default {
title: 'Components/MultiSelect',
@@ -483,7 +482,7 @@ export const withAILabel = () => (
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
- slug={aiLabel}
+ decorator={aiLabel}
/>
);
@@ -498,7 +497,7 @@ export const FilterableWithAILabel = () => (
items={items}
itemToString={(item) => (item ? item.text : '')}
selectionFeedback="top-after-reopen"
- slug={aiLabel}
+ decorator={aiLabel}
/>
);
diff --git a/packages/react/src/components/MultiSelect/MultiSelect.tsx b/packages/react/src/components/MultiSelect/MultiSelect.tsx
index d9d18bddc023..f9917dd75d92 100644
--- a/packages/react/src/components/MultiSelect/MultiSelect.tsx
+++ b/packages/react/src/components/MultiSelect/MultiSelect.tsx
@@ -128,6 +128,11 @@ export interface MultiSelectProps
*/
clearSelectionText?: string;
+ /**
+ * **Experimental**: Provide a `decorator` component to be rendered inside the `MultiSelect` component
+ */
+ decorator?: ReactNode;
+
/**
* Specify the direction of the multiselect dropdown. Can be either top or bottom.
*/
@@ -260,6 +265,7 @@ export interface MultiSelectProps
size?: ListBoxSize;
/**
+ * @deprecated please use decorator instead.
* **Experimental**: Provide a `Slug` component to be rendered inside the `MultiSelect` component
*/
slug?: ReactNode;
@@ -296,6 +302,7 @@ const MultiSelect = React.forwardRef(
{
autoAlign = false,
className: containerClassName,
+ decorator,
id,
items,
itemToElement,
@@ -538,6 +545,7 @@ const MultiSelect = React.forwardRef(
[`${prefix}--list-box__wrapper--fluid--focus`]:
!isOpen && isFluid && isFocused,
[`${prefix}--list-box__wrapper--slug`]: slug,
+ [`${prefix}--list-box__wrapper--decorator`]: decorator,
}
);
const titleClasses = cx(`${prefix}--label`, {
@@ -679,12 +687,20 @@ const MultiSelect = React.forwardRef(
}
: {};
- // Slug is always size `mini`
- let normalizedSlug;
- if (slug && slug['type']?.displayName === 'AILabel') {
- normalizedSlug = React.cloneElement(slug as React.ReactElement, {
- size: 'mini',
- });
+ // AILabel always size `mini`
+ let normalizedDecorator = React.isValidElement(slug ?? decorator)
+ ? (slug ?? decorator)
+ : null;
+ if (
+ normalizedDecorator &&
+ normalizedDecorator['type']?.displayName === 'AILabel'
+ ) {
+ normalizedDecorator = React.cloneElement(
+ normalizedDecorator as React.ReactElement,
+ {
+ size: 'mini',
+ }
+ );
}
const itemsSelectedText =
@@ -773,7 +789,15 @@ const MultiSelect = React.forwardRef(
translateWithId={translateWithId}
/>
- {normalizedSlug}
+ {slug ? (
+ normalizedDecorator
+ ) : decorator ? (
+
+ {normalizedDecorator}
+
+ ) : (
+ ''
+ )}
{isOpen &&
@@ -886,6 +910,11 @@ MultiSelect.propTypes = {
*/
compareItems: PropTypes.func,
+ /**
+ * **Experimental**: Provide a decorator component to be rendered inside the `MultiSelect` component
+ */
+ decorator: PropTypes.node,
+
/**
* Specify the direction of the multiselect dropdown. Can be either top or bottom.
*/
@@ -1019,10 +1048,10 @@ MultiSelect.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,
- /**
- * **Experimental**: Provide a `Slug` component to be rendered inside the `MultiSelect` component
- */
- slug: PropTypes.node,
+ slug: deprecate(
+ PropTypes.node,
+ 'The `slug` prop has been deprecated and will be removed in the next major version. Use the decorator prop instead.'
+ ),
/**
* Provide a method that sorts all options in the control. Overriding this
diff --git a/packages/react/src/components/MultiSelect/__tests__/FilterableMultiSelect-test.js b/packages/react/src/components/MultiSelect/__tests__/FilterableMultiSelect-test.js
index d992d5b61927..b7287b9d6dbb 100644
--- a/packages/react/src/components/MultiSelect/__tests__/FilterableMultiSelect-test.js
+++ b/packages/react/src/components/MultiSelect/__tests__/FilterableMultiSelect-test.js
@@ -250,6 +250,7 @@ describe('FilterableMultiSelect', () => {
});
it('should respect slug prop', async () => {
+ const spy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const { container } = render(
} />
);
@@ -258,6 +259,18 @@ describe('FilterableMultiSelect', () => {
expect(container.firstChild).toHaveClass(
`${prefix}--list-box__wrapper--slug`
);
+ spy.mockRestore();
+ });
+
+ it('should respect decorator prop', async () => {
+ const { container } = render(
+ } />
+ );
+ await waitForPosition();
+
+ expect(container.firstChild).toHaveClass(
+ `${prefix}--list-box__wrapper--decorator`
+ );
});
it('should place the given id on the listbox wrapper', async () => {
diff --git a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js
index fd977410fd70..8e16e2c4dc20 100644
--- a/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js
+++ b/packages/react/src/components/MultiSelect/__tests__/MultiSelect-test.js
@@ -586,6 +586,7 @@ describe('MultiSelect', () => {
});
it('should respect slug prop', async () => {
+ const spy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const items = generateItems(4, generateGenericItem);
const label = 'test-label';
const { container } = render(
@@ -596,6 +597,25 @@ describe('MultiSelect', () => {
expect(container.firstChild).toHaveClass(
`${prefix}--list-box__wrapper--slug`
);
+ spy.mockRestore();
+ });
+
+ it('should respect decorator prop', async () => {
+ const items = generateItems(4, generateGenericItem);
+ const label = 'test-label';
+ const { container } = render(
+ }
+ />
+ );
+ await waitForPosition();
+
+ expect(container.firstChild).toHaveClass(
+ `${prefix}--list-box__wrapper--decorator`
+ );
});
it('should select all options when isSelectAll property in an item is provided', async () => {