Skip to content

Commit

Permalink
feat: replace slug with decorator ComboBox, MultiSelect, FilterableMu…
Browse files Browse the repository at this point in the history
…ltiSelect (#18069)

* feat(combobox): replace slug prop with decorator

* chore: update tests

* feat: add decorator prop to multiselect

* feat: add decorator prop to filterablemultiselect

* chore: format and snapshot

* chore: update form story

* feat: add with ailabel stories to fluid and form stories

* chore:format

---------

Co-authored-by: Guilherme Datilio Ribeiro <[email protected]>
  • Loading branch information
alisonjoseph and guidari authored Nov 20, 2024
1 parent cf5dc88 commit f5a056f
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 58 deletions.
28 changes: 16 additions & 12 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,9 @@ Map {
"className": Object {
"type": "string",
},
"decorator": Object {
"type": "node",
},
"direction": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -1362,9 +1365,7 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"slug": [Function],
"titleText": Object {
"type": "node",
},
Expand Down Expand Up @@ -3544,6 +3545,9 @@ Map {
"compareItems": Object {
"type": "func",
},
"decorator": Object {
"type": "node",
},
"direction": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -3758,9 +3762,7 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"slug": [Function],
"sortItems": Object {
"type": "func",
},
Expand Down Expand Up @@ -5224,6 +5226,9 @@ Map {
"compareItems": Object {
"type": "func",
},
"decorator": Object {
"type": "node",
},
"direction": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -5438,9 +5443,7 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"slug": [Function],
"sortItems": Object {
"type": "func",
},
Expand Down Expand Up @@ -5478,6 +5481,9 @@ Map {
"compareItems": Object {
"type": "func",
},
"decorator": Object {
"type": "node",
},
"direction": Object {
"args": Array [
Array [
Expand Down Expand Up @@ -5565,9 +5571,7 @@ Map {
],
"type": "oneOf",
},
"slug": Object {
"type": "node",
},
"slug": [Function],
"sortItems": Object {
"type": "func",
},
Expand Down
12 changes: 12 additions & 0 deletions packages/react/src/components/ComboBox/ComboBox-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,13 +285,25 @@ describe('ComboBox', () => {
});

it('should respect slug prop', async () => {
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {});
const { container } = render(
<ComboBox {...mockProps} slug={<AILabel />} />
);
await waitForPosition();
expect(container.firstChild).toHaveClass(
`${prefix}--list-box__wrapper--slug`
);
spy.mockRestore();
});

it('should respect decorator prop', async () => {
const { container } = render(
<ComboBox {...mockProps} decorator={<AILabel />} />
);
await waitForPosition();
expect(container.firstChild).toHaveClass(
`${prefix}--list-box__wrapper--decorator`
);
});

describe('should display initially selected item found in `initialSelectedItem`', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/ComboBox/ComboBox.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ export const withAILabel = () => (
itemToString={(item) => (item ? item.text : '')}
titleText="ComboBox title"
helperText="Combobox helper text"
slug={aiLabel}
decorator={aiLabel}
/>
</div>
);
Expand Down
51 changes: 40 additions & 11 deletions packages/react/src/components/ComboBox/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ export interface ComboBoxProps<ItemType>
*/
className?: string;

/**
* **Experimental**: Provide a `decorator` component to be rendered inside the `ComboBox` component
*/
decorator?: ReactNode;

/**
* Specify the direction of the combobox dropdown. Can be either top or bottom.
*/
Expand Down Expand Up @@ -349,6 +354,7 @@ export interface ComboBoxProps<ItemType>
size?: ListBoxSize;

/**
* @deprecated please use decorator instead.
* **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` component
*/
slug?: ReactNode;
Expand Down Expand Up @@ -388,6 +394,7 @@ const ComboBox = forwardRef(
ariaLabel: deprecatedAriaLabel,
autoAlign = false,
className: containerClassName,
decorator,
direction = 'bottom',
disabled = false,
downshiftActions,
Expand Down Expand Up @@ -694,6 +701,7 @@ const ComboBox = forwardRef(
[`${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,
},
]);

Expand All @@ -705,12 +713,20 @@ const ComboBox = forwardRef(
// needs to be Capitalized for react to render it correctly
const ItemToElement = itemToElement;

// Slug is always size `mini`
let normalizedSlug;
if (slug && slug['type']?.displayName === 'AILabel') {
normalizedSlug = React.cloneElement(slug as React.ReactElement<any>, {
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<any>,
{
size: 'mini',
}
);
}

const {
Expand Down Expand Up @@ -1038,7 +1054,15 @@ const ComboBox = forwardRef(
translateWithId={translateWithId}
/>
</div>
{normalizedSlug}
{slug ? (
normalizedDecorator
) : decorator ? (
<div className={`${prefix}--list-box__inner-wrapper--decorator`}>
{normalizedDecorator}
</div>
) : (
''
)}
<ListBox.Menu {...menuProps}>
{isOpen
? filterItems(items, itemToString, inputValue).map(
Expand Down Expand Up @@ -1133,6 +1157,11 @@ ComboBox.propTypes = {
*/
className: PropTypes.string,

/**
* **Experimental**: Provide a decorator component to be rendered inside the `ComboBox` component
*/
decorator: PropTypes.node,

/**
* Specify the direction of the combobox dropdown. Can be either top or bottom.
*/
Expand Down Expand Up @@ -1283,10 +1312,10 @@ ComboBox.propTypes = {
*/
size: ListBoxPropTypes.ListBoxSize,

/**
* **Experimental**: Provide a `Slug` component to be rendered inside the `ComboBox` 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 text to be used in a `<label>` element that is tied to the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -92,6 +95,51 @@ export const Condensed = () => (
</div>
);

const aiLabel = (
<AILabel className="ai-label-container">
<AILabelContent>
<div>
<p className="secondary">AI Explained</p>
<h1>84%</h1>
<p className="secondary bold">Confidence score</p>
<p className="secondary">
Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
</p>
<hr />
<p className="secondary">Model type</p>
<p className="bold">Foundation model</p>
</div>
<AILabelActions>
<IconButton kind="ghost" label="View">
<View />
</IconButton>
<IconButton kind="ghost" label="Open Folder">
<FolderOpen />
</IconButton>
<IconButton kind="ghost" label="Folders">
<Folders />
</IconButton>
<Button>View details</Button>
</AILabelActions>
</AILabelContent>
</AILabel>
);

export const withAILabel = () => (
<div style={{ width: '400px' }}>
<FluidComboBox
onChange={() => {}}
id="default"
titleText="Label"
label="Choose an option"
items={items}
itemToString={(item) => (item ? item.text : '')}
decorator={aiLabel}
/>
</div>
);

export const Playground = (args) => (
<div style={{ width: args.playgroundWidth }}>
<FluidComboBox
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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__FluidDropdown',
Expand Down Expand Up @@ -91,6 +94,51 @@ export const Condensed = () => (
</div>
);

const aiLabel = (
<AILabel className="ai-label-container">
<AILabelContent>
<div>
<p className="secondary">AI Explained</p>
<h1>84%</h1>
<p className="secondary bold">Confidence score</p>
<p className="secondary">
Lorem ipsum dolor sit amet, di os consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut fsil labore et dolore magna aliqua.
</p>
<hr />
<p className="secondary">Model type</p>
<p className="bold">Foundation model</p>
</div>
<AILabelActions>
<IconButton kind="ghost" label="View">
<View />
</IconButton>
<IconButton kind="ghost" label="Open Folder">
<FolderOpen />
</IconButton>
<IconButton kind="ghost" label="Folders">
<Folders />
</IconButton>
<Button>View details</Button>
</AILabelActions>
</AILabelContent>
</AILabel>
);

export const withAILabel = () => (
<div style={{ width: '400px' }}>
<FluidDropdown
initialSelectedItem={items[2]}
id="default"
titleText="Label"
label="Choose an option"
items={items}
itemToString={(item) => (item ? item.text : '')}
decorator={aiLabel}
/>
</div>
);

export const Playground = (args) => (
<div style={{ width: args.playgroundWidth }}>
<FluidDropdown
Expand Down
Loading

0 comments on commit f5a056f

Please sign in to comment.