Skip to content

Commit

Permalink
feat(Multiselect): add itemToElement to Multiselect (#9559)
Browse files Browse the repository at this point in the history
* feat(Multiselect): add itemToElement to Multiselect

* test(Multiselect): update snapshots, add new test for itemToElement

* fix(MultiSelect): use existing variable

* fix(MultiSelect): remove itemToElement defaultProp

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
  • Loading branch information
tw15egan and kodiakhq[bot] authored Aug 31, 2021
1 parent 177689c commit fdff63e
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 2 deletions.
9 changes: 9 additions & 0 deletions packages/react/__tests__/__snapshots__/PublicAPI-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3052,6 +3052,9 @@ Map {
"invalidText": Object {
"type": "node",
},
"itemToElement": Object {
"type": "func",
},
"itemToString": Object {
"type": "func",
},
Expand Down Expand Up @@ -3982,6 +3985,9 @@ Map {
"invalidText": Object {
"type": "node",
},
"itemToElement": Object {
"type": "func",
},
"itemToString": Object {
"type": "func",
},
Expand Down Expand Up @@ -4223,6 +4229,9 @@ Map {
"invalidText": Object {
"type": "node",
},
"itemToElement": Object {
"type": "func",
},
"itemToString": Object {
"type": "func",
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ export default class FilterableMultiSelect extends React.Component {
*/
invalidText: PropTypes.node,

/**
* Function to render items as custom components instead of strings.
* Defaults to null and is overridden by a getter
*/
itemToElement: PropTypes.func,

/**
* Helper function passed to downshift that allows the library to render a
* given item to a string label. By default, it extracts the `label` field
Expand Down Expand Up @@ -287,6 +293,7 @@ export default class FilterableMultiSelect extends React.Component {
disabled,
filterItems,
items,
itemToElement,
itemToString,
titleText,
helperText,
Expand All @@ -310,6 +317,9 @@ export default class FilterableMultiSelect extends React.Component {
const inline = type === 'inline';
const showWarning = !invalid && warn;

// needs to be capitalized for react to render it correctly
const ItemToElement = itemToElement;

const wrapperClasses = cx(
`${prefix}--multi-select__wrapper`,
`${prefix}--list-box__wrapper`,
Expand Down Expand Up @@ -561,7 +571,14 @@ export default class FilterableMultiSelect extends React.Component {
className={`${prefix}--checkbox-label`}
data-contained-checkbox-state={isChecked}
id={`${itemProps.id}-item`}>
{itemText}
{itemToElement ? (
<ItemToElement
key={itemProps.id}
{...item}
/>
) : (
itemText
)}
</span>
</div>
</ListBox.MenuItem>
Expand Down
46 changes: 46 additions & 0 deletions packages/react/src/components/MultiSelect/MultiSelect-story.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,52 @@ export const Default = withReadme(readme, () => {
);
});

export const ItemToElement = withReadme(readme, () => {
return (
<div style={{ width: 300 }}>
<MultiSelect
titleText="Multiselect with element items"
label="Choose an item"
items={items}
itemToString={(item) => (item ? item.text : '')}
itemToElement={(item) =>
item ? (
<span className="test">
{item.text}{' '}
<span role="img" alt="fire">
{' '}
🔥
</span>
</span>
) : (
''
)
}
/>
<br />
<FilterableMultiSelect
titleText="Filterable Multiselect with element items"
placeholder="itemToElement example"
items={items}
itemToString={(item) => (item ? item.text : '')}
itemToElement={(item) =>
item ? (
<span className="test">
{item.text}{' '}
<span role="img" alt="fire">
{' '}
🔥
</span>
</span>
) : (
''
)
}
/>
</div>
);
});

Default.storyName = 'default';

Default.parameters = {
Expand Down
16 changes: 15 additions & 1 deletion packages/react/src/components/MultiSelect/MultiSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const MultiSelect = React.forwardRef(function MultiSelect(
className: containerClassName,
id,
items,
itemToElement,
itemToString,
titleText,
helperText,
Expand Down Expand Up @@ -155,6 +156,9 @@ const MultiSelect = React.forwardRef(function MultiSelect(
[`${prefix}--list-box--up`]: direction === 'top',
});

// needs to be capitalized for react to render it correctly
const ItemToElement = itemToElement;

const sortOptions = {
selectedItems: controlledSelectedItems,
itemToString,
Expand Down Expand Up @@ -284,7 +288,11 @@ const MultiSelect = React.forwardRef(function MultiSelect(
className={`${prefix}--checkbox-label`}
data-contained-checkbox-state={isChecked}
id={`${itemProps.id}__checkbox`}>
{itemText}
{itemToElement ? (
<ItemToElement key={itemProps.id} {...item} />
) : (
itemText
)}
</span>
</div>
</ListBox.MenuItem>
Expand Down Expand Up @@ -351,6 +359,12 @@ MultiSelect.propTypes = {
*/
invalidText: PropTypes.node,

/**
* Function to render items as custom components instead of strings.
* Defaults to null and is overridden by a getter
*/
itemToElement: PropTypes.func,

/**
* Helper function passed to downshift that allows the library to render a
* given item to a string label. By default, it extracts the `label` field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,38 @@ describe('MultiSelect', () => {
expect(getByText(container, 'marky')).toBeTruthy();
});

it('should support a custom itemToElement', () => {
const items = [{ text: 'test-item' }];
const label = 'test-label';
const { container } = render(
<MultiSelect
id="custom-id"
label={label}
items={items}
itemToString={(item) => (item ? item.text : '')}
itemToElement={(item) =>
item ? (
<span className="test-element">
{item.text}{' '}
<span role="img" alt="fire">
{' '}
🔥
</span>
</span>
) : (
''
)
}
/>
);

const labelNode = getByText(container, label);
Simulate.click(labelNode);

expect(document.querySelector('.test-element')).toBeTruthy();
expect(document.querySelector('span[role="img"]')).toBeTruthy();
});

it('should support custom translation with translateWithId', () => {
const items = generateItems(4, generateGenericItem);
const label = 'test-label';
Expand Down

0 comments on commit fdff63e

Please sign in to comment.