Skip to content

Commit

Permalink
feat: add groupLabel FieldName (#941)
Browse files Browse the repository at this point in the history
* fix: OptGroup label not display when set fieldNames

* feat: groupLabel fieldName

* chore: add test case

* chore: put groupLabel api in fileName

* chore: separate label and groupLabel

* chore: coding style

* fix: coding style again

* fix: style

---------

Co-authored-by: 洋 <hetongyang@bytedance.com>
  • Loading branch information
BoyYangzai and authored May 17, 2023
1 parent 0c8db0c commit 9eed16b
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 29 deletions.
6 changes: 5 additions & 1 deletion src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export type FilterFunc<OptionType> = (inputValue: string, option?: OptionType) =
export interface FieldNames {
value?: string;
label?: string;
groupLabel?: string;
options?: string;
}

Expand Down Expand Up @@ -410,7 +411,10 @@ const Select = React.forwardRef(

const displayOptions = React.useMemo(
() =>
flattenOptions(orderedFilteredOptions, { fieldNames: mergedFieldNames, childrenAsData }),
flattenOptions(orderedFilteredOptions, {
fieldNames: mergedFieldNames,
childrenAsData,
}),
[orderedFilteredOptions, mergedFieldNames, childrenAsData],
);

Expand Down
10 changes: 7 additions & 3 deletions src/utils/valueUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ function getKey(data: BaseOptionType, index: number) {
}

export function fillFieldNames(fieldNames: FieldNames | undefined, childrenAsData: boolean) {
const { label, value, options } = fieldNames || {};
const { label, value, options, groupLabel } = fieldNames || {};
const mergedLabel = label || (childrenAsData ? 'children' : 'label');

return {
label: label || (childrenAsData ? 'children' : 'label'),
label: mergedLabel,
value: value || 'value',
options: options || 'options',
groupLabel: groupLabel || mergedLabel,
};
}

Expand All @@ -45,11 +47,13 @@ export function flattenOptions<OptionType extends BaseOptionType = DefaultOption
label: fieldLabel,
value: fieldValue,
options: fieldOptions,
groupLabel
} = fillFieldNames(fieldNames, false);

function dig(list: OptionType[], isGroupOption: boolean) {
list.forEach((data) => {
const label = data[fieldLabel];

const label = data[isGroupOption ? groupLabel : fieldLabel];

if (isGroupOption || !(fieldOptions in data)) {
const value = data[fieldValue];
Expand Down
68 changes: 48 additions & 20 deletions tests/Select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,51 @@ describe('Select.Basic', () => {
);
expect(wrapper).toMatchSnapshot();
});

it('should support fieldName', () => {
// groupLabel > fieldNames > self-label
function genOpts(OptLabelName) {
return [
{
groupLabel: 'Manager',
options: [
{
data: 'value',
[OptLabelName]: 'label',
},
],
},
];
}

const { container: containerFirst } = testingRender(
<Select
options={genOpts('test')}
fieldNames={{
value: 'data',
label: 'test',
groupLabel: 'groupLabel',
}}
/>,
);
const { container: containerSecond } = testingRender(
<Select
options={genOpts('groupLabel')}
fieldNames={{ value: 'data', label: 'groupLabel' }}
/>,
);
const { container: containerThird } = testingRender(
<Select
options={genOpts('noGroupLabel')}
fieldNames={{ value: 'data', label: 'noGroupLabel' }}
/>,
);

// these generate the same snapshots
expect(containerFirst).toMatchSnapshot();
expect(containerSecond).toMatchSnapshot();
expect(containerThird).toMatchSnapshot();
});
});

it('convert value to array', () => {
Expand Down Expand Up @@ -1925,30 +1970,13 @@ describe('Select.Basic', () => {
});

it('should support title', () => {
const wrapper1 = mount(
<Select
defaultValue="lucy"
options={[]}
/>,
);
const wrapper1 = mount(<Select defaultValue="lucy" options={[]} />);
expect(wrapper1.find('.rc-select').prop('title')).toBe(undefined);
expect(wrapper1.find('.rc-select-selection-item').prop('title')).toBe('lucy');
const wrapper2 = mount(
<Select
defaultValue="lucy"
options={[]}
title=""
/>,
);
const wrapper2 = mount(<Select defaultValue="lucy" options={[]} title="" />);
expect(wrapper2.find('.rc-select').prop('title')).toBe('');
expect(wrapper2.find('.rc-select-selection-item').prop('title')).toBe('');
const wrapper3 = mount(
<Select
defaultValue="lucy"
options={[]}
title="title"
/>,
);
const wrapper3 = mount(<Select defaultValue="lucy" options={[]} title="title" />);
expect(wrapper3.find('.rc-select').prop('title')).toBe('title');
expect(wrapper3.find('.rc-select-selection-item').prop('title')).toBe('title');
});
Expand Down
149 changes: 145 additions & 4 deletions tests/__snapshots__/Select.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Select.Basic does not filter when filterOption value is false 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
>
<div>
<div
Expand Down Expand Up @@ -94,7 +94,7 @@ exports[`Select.Basic does not filter when filterOption value is false 1`] = `
exports[`Select.Basic filterOption could be true as described in default value 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-empty rc-select-dropdown-placement-bottomLeft"
style="left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
>
<div>
<div
Expand Down Expand Up @@ -433,10 +433,151 @@ exports[`Select.Basic render renders role prop correctly 1`] = `
</div>
`;

exports[`Select.Basic render should support fieldName 1`] = `
<div>
<div
class="rc-select rc-select-single rc-select-show-arrow"
>
<div
class="rc-select-selector"
>
<span
class="rc-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="rc-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="rc-select-selection-placeholder"
/>
</div>
<span
aria-hidden="true"
class="rc-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
class="rc-select-arrow-icon"
/>
</span>
</div>
</div>
`;

exports[`Select.Basic render should support fieldName 2`] = `
<div>
<div
class="rc-select rc-select-single rc-select-show-arrow"
>
<div
class="rc-select-selector"
>
<span
class="rc-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="rc-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="rc-select-selection-placeholder"
/>
</div>
<span
aria-hidden="true"
class="rc-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
class="rc-select-arrow-icon"
/>
</span>
</div>
</div>
`;

exports[`Select.Basic render should support fieldName 3`] = `
<div>
<div
class="rc-select rc-select-single rc-select-show-arrow"
>
<div
class="rc-select-selector"
>
<span
class="rc-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="rc-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="rc-select-selection-placeholder"
/>
</div>
<span
aria-hidden="true"
class="rc-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
class="rc-select-arrow-icon"
/>
</span>
</div>
</div>
`;

exports[`Select.Basic should contain falsy children 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
>
<div>
<div
Expand Down Expand Up @@ -529,7 +670,7 @@ exports[`Select.Basic should contain falsy children 1`] = `
exports[`Select.Basic should render custom dropdown correctly 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
>
<div>
<div>
Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/Tags.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ exports[`Select.Tags OptGroup renders correctly 1`] = `
</div>
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
>
<div>
<div
Expand Down

0 comments on commit 9eed16b

Please sign in to comment.