Skip to content

Commit 7a19c50

Browse files
RyanDubowskyemyarod
authored andcommitted
feat(combobox): add itemToElement to render items as custom components (#2766)
1 parent b2a63ae commit 7a19c50

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

packages/react/src/components/ComboBox/ComboBox-story.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ const props = () => ({
4949
onChange: action('onChange'),
5050
});
5151

52+
const itemToElement = item => {
53+
const itemAsArray = item.text.split(' ');
54+
return (
55+
<div>
56+
<span>{itemAsArray[0]}</span>
57+
<span style={{ color: 'red' }}> {itemAsArray[1]}</span>
58+
</div>
59+
);
60+
};
61+
5262
storiesOf('ComboBox', module)
5363
.addDecorator(withKnobs)
5464
.add(
@@ -68,6 +78,24 @@ storiesOf('ComboBox', module)
6878
},
6979
}
7080
)
81+
.add(
82+
'items as components',
83+
() => (
84+
<div style={{ width: 300 }}>
85+
<ComboBox
86+
items={items}
87+
itemToString={item => (item ? item.text : '')}
88+
itemToElement={itemToElement}
89+
{...props()}
90+
/>
91+
</div>
92+
),
93+
{
94+
info: {
95+
text: 'ComboBox',
96+
},
97+
}
98+
)
7199
.add(
72100
'custom text input handling',
73101
() => (

packages/react/src/components/ComboBox/ComboBox-test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ describe('ComboBox', () => {
8282
expect(onInputChange).toHaveBeenCalledWith('something');
8383
});
8484

85+
it('should render custom item components', () => {
86+
const wrapper = mount(<ComboBox {...mockProps} />);
87+
wrapper.setProps({
88+
itemToElement: item => <div className="mock-item">{item.text}</div>,
89+
});
90+
openMenu(wrapper);
91+
92+
expect(wrapper.find(`.mock-item`).length).toBe(mockProps.items.length);
93+
});
94+
8595
describe('should display initially selected item found in `initialSelectedItem`', () => {
8696
it('using an object type for the `initialSelectedItem` prop', () => {
8797
const wrapper = mount(

packages/react/src/components/ComboBox/ComboBox.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ export default class ComboBox extends React.Component {
9494
*/
9595
itemToString: PropTypes.func,
9696

97+
/**
98+
* Optional function to render items as custom components instead of strings.
99+
* Defaults to null and is overriden by a getter
100+
*/
101+
itemToElement: PropTypes.func,
102+
97103
/**
98104
* `onChange` is a utility for this controlled component to communicate to a
99105
* consuming component when a specific dropdown item is selected.
@@ -156,6 +162,7 @@ export default class ComboBox extends React.Component {
156162
static defaultProps = {
157163
disabled: false,
158164
itemToString: defaultItemToString,
165+
itemToElement: null,
159166
shouldFilterItem: defaultShouldFilterItem,
160167
type: 'default',
161168
ariaLabel: 'Choose an item',
@@ -229,6 +236,7 @@ export default class ComboBox extends React.Component {
229236
id,
230237
items,
231238
itemToString,
239+
itemToElement,
232240
titleText,
233241
helperText,
234242
placeholder,
@@ -261,6 +269,9 @@ export default class ComboBox extends React.Component {
261269
<div className={helperClasses}>{helperText}</div>
262270
) : null;
263271
const wrapperClasses = cx(`${prefix}--list-box__wrapper`);
272+
273+
// needs to be Capitalized for react to render it correctly
274+
const ItemToElement = itemToElement;
264275
const input = (
265276
<Downshift
266277
{...downshiftProps}
@@ -337,7 +348,11 @@ export default class ComboBox extends React.Component {
337348
false
338349
}
339350
{...getItemProps({ item, index })}>
340-
{itemToString(item)}
351+
{itemToElement ? (
352+
<ItemToElement key={itemToString(item)} {...item} />
353+
) : (
354+
itemToString(item)
355+
)}
341356
</ListBox.MenuItem>
342357
)
343358
)}

0 commit comments

Comments
 (0)