Skip to content

Commit efa6551

Browse files
authored
Merge pull request #1092 from rvsia/carbonSelectCategories
feat(carbon): allow to group options in single select
2 parents 589495f + 6ccc436 commit efa6551

File tree

3 files changed

+91
-7
lines changed

3 files changed

+91
-7
lines changed

packages/carbon-component-mapper/src/select/select.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { useFieldApi } from '@data-driven-forms/react-form-renderer';
55
import DataDrivenSelect from '@data-driven-forms/common/select';
66
import fnToString from '@data-driven-forms/common/utils/fn-to-string';
77

8-
import { Select as CarbonSelect, MultiSelect, SelectItem, ComboBox } from 'carbon-components-react';
8+
import { Select as CarbonSelect, MultiSelect, SelectItem, ComboBox, SelectItemGroup } from 'carbon-components-react';
99
import prepareProps from '../prepare-props';
1010

1111
const onChangeWrapper = (onChange) => ({ selectedItem, selectedItems }) => onChange(selectedItems || selectedItem);
@@ -15,6 +15,21 @@ export const getMultiValue = (value, options) =>
1515
typeof item === 'object' ? item : options.find(({ value }) => value === item)
1616
);
1717

18+
const renderOptions = (options) =>
19+
options.map((option, index) => {
20+
const { options, ...rest } = option;
21+
22+
if (options) {
23+
return (
24+
<SelectItemGroup key={rest.value || index} text={rest.label} {...rest}>
25+
{renderOptions(options)}
26+
</SelectItemGroup>
27+
);
28+
}
29+
30+
return <SelectItem key={rest.value || index} text={rest.label} {...rest} />;
31+
});
32+
1833
const ClearedMultiSelectFilterable = ({
1934
invalidText,
2035
hideSelectedOptions,
@@ -147,9 +162,7 @@ const ClearedSelect = ({
147162
invalidText={invalidText}
148163
>
149164
{isFetching && <SelectItem text={placeholder} value={''} />}
150-
{options.map((option, index) => (
151-
<SelectItem key={option.value || index} text={option.label} {...option} />
152-
))}
165+
{renderOptions(options)}
153166
</CarbonSelect>
154167
);
155168

@@ -252,8 +265,15 @@ const Select = (props) => {
252265
}, [loadOptionsStr]);
253266
const isSearchClear = isSearchable || isClearable;
254267

255-
const Component =
256-
isMulti && isSearchClear ? ClearedMultiSelectFilterable : isMulti ? ClearedMultiSelect : isSearchClear ? ClearedSelectSearchable : ClearedSelect;
268+
let Component = ClearedSelect;
269+
270+
if (isMulti && isSearchClear) {
271+
Component = ClearedMultiSelectFilterable;
272+
} else if (isMulti) {
273+
Component = ClearedMultiSelect;
274+
} else if (isSearchClear) {
275+
Component = ClearedSelectSearchable;
276+
}
257277

258278
const invalidText = ((meta.touched || validateOnMount) && (meta.error || meta.submitError)) || '';
259279
const text = ((meta.touched || validateOnMount) && meta.warning) || helperText;

packages/carbon-component-mapper/src/tests/select.test.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FormRenderer, componentTypes } from '@data-driven-forms/react-form-rend
55

66
import FormTemplate from '../form-template';
77
import componentMapper from '../component-mapper';
8-
import { Select, MultiSelect, ComboBox } from 'carbon-components-react';
8+
import { Select, MultiSelect, ComboBox, SelectItem, SelectItemGroup } from 'carbon-components-react';
99
import { getMultiValue } from '../select/select';
1010

1111
describe('<Select />', () => {
@@ -31,6 +31,42 @@ describe('<Select />', () => {
3131
expect(wrapper.find(Select)).toHaveLength(1);
3232
});
3333

34+
it('renders select with categories', () => {
35+
const schema = {
36+
fields: [
37+
{
38+
component: componentTypes.SELECT,
39+
name: 'select',
40+
label: 'select',
41+
options: [
42+
{
43+
label: 'Category 1',
44+
options: [
45+
{ label: 'value 1', value: '111' },
46+
{ label: 'value 2', value: '222' }
47+
]
48+
},
49+
{
50+
label: 'Category 2',
51+
options: [
52+
{ label: 'value 3', value: '333' },
53+
{ label: 'value 4', value: '444' }
54+
]
55+
}
56+
]
57+
}
58+
]
59+
};
60+
61+
const wrapper = mount(
62+
<FormRenderer onSubmit={jest.fn()} FormTemplate={(props) => <FormTemplate {...props} />} schema={schema} componentMapper={componentMapper} />
63+
);
64+
65+
expect(wrapper.find(Select)).toHaveLength(1);
66+
expect(wrapper.find(SelectItemGroup)).toHaveLength(2);
67+
expect(wrapper.find(SelectItem)).toHaveLength(4);
68+
});
69+
3470
['isSearchable', 'isClearable'].forEach((setting) => {
3571
it(`renders select ${setting}`, () => {
3672
const schema = {
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
11
import SelectCommon from '../select.md';
22

3+
## Single select with categories
4+
5+
For single (not clearable/not searchable) select, you can use categories to group your options by adding an `options` array.
6+
7+
```jsx
8+
{
9+
component: 'select',
10+
name: 'select-with-categories',
11+
label: 'With categories',
12+
options: [
13+
{
14+
label: 'Category 1',
15+
options: [
16+
{ label: 'value 1', value: '111' },
17+
{ label: 'value 2', value: '222' }
18+
]
19+
},
20+
{
21+
label: 'Category 2',
22+
options: [
23+
{ label: 'value 3', value: '333' },
24+
{ label: 'value 4', value: '444' }
25+
]
26+
}
27+
]
28+
}
29+
```
30+
331
<SelectCommon/>

0 commit comments

Comments
 (0)