Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support custom label render #995

Merged
merged 11 commits into from
Jan 2, 2024
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export default () => (
| virtual | Disable virtual scroll | boolean | true |
| direction | direction of dropdown | 'ltr' \| 'rtl' | 'ltr' |
| optionRender | Custom rendering options | (oriOption: FlattenOptionData\<BaseOptionType\> , info: { index: number }) => React.ReactNode | - |
| labelRender | Custom rendering label | (props: LabelInValueType) => React.ReactNode | - |

### Methods

Expand Down
8 changes: 8 additions & 0 deletions docs/demo/custom-label.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
title: custom-label
nav:
title: Demo
path: /demo
---

<code src="../examples/custom-label.tsx"></code>
66 changes: 66 additions & 0 deletions docs/examples/custom-label.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable no-console */
import Select, { Option } from 'rc-select';
import React from 'react';
import '../../assets/index.less';

const children = [];
for (let i = 10; i < 36; i += 1) {
children.push(
<Option key={i.toString(36) + i} test={i}>
{i.toString(36) + i}
</Option>,
);
}

const Test: React.FC = () => {
const [value, setValue] = React.useState<string>('test');

return (
<div>
<h2>custom label render</h2>

<div>
<Select
placeholder="placeholder"
style={{ width: 500 }}
value={value}
onChange={(val: string, option) => {
console.log('change', val, option);
setValue(val);
}}
onSelect={(val, option) => {
console.log('selected', val, option);
}}
onDeselect={(val, option) => {
console.log('deselected', val, option);
}}
tokenSeparators={[',']}
labelRender={(props) => {
const { label, value: _value } = props;
const style: React.CSSProperties = { backgroundColor: 'red' };
if (label) {
return _value;
} else return <span style={style}>no this value in options</span>;
}}
onFocus={() => console.log('focus')}
onBlur={() => console.log('blur')}
>
{children}
</Select>
</div>
<p>
<button
type="button"
onClick={() => {
setValue('test');
}}
>
set value as test
</button>
</p>
</div>
);
};

export default Test;
/* eslint-enable */
8 changes: 5 additions & 3 deletions src/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export interface SelectProps<ValueType = any, OptionType extends BaseOptionType
direction?: 'ltr' | 'rtl';
listHeight?: number;
listItemHeight?: number;
labelRender?: (props: LabelInValueType) => React.ReactNode;

// >>> Icon
menuItemSelectedIcon?: RenderNode;
Expand Down Expand Up @@ -197,6 +198,7 @@ const Select = React.forwardRef(
direction,
listHeight = 200,
listItemHeight = 20,
labelRender,

// Value
value,
Expand Down Expand Up @@ -323,7 +325,7 @@ const Select = React.forwardRef(

// Fill label with cache to avoid option remove
const [mergedValues, getMixedOption] = useCache(rawLabeledValues, valueOptions);

xliez marked this conversation as resolved.
Show resolved Hide resolved
const displayValues = React.useMemo(() => {
// `null` need show as placeholder instead
// https://github.com/ant-design/ant-design/issues/25057
Expand All @@ -339,9 +341,9 @@ const Select = React.forwardRef(

return mergedValues.map((item) => ({
...item,
label: item.label ?? item.value,
label: (typeof labelRender === 'function' ? labelRender(item) : item.label) ?? item.value,
yoyo837 marked this conversation as resolved.
Show resolved Hide resolved
}));
}, [mode, mergedValues]);
}, [mode, mergedValues, labelRender]);

/** Convert `displayValues` to raw value type set */
const rawValues = React.useMemo(
Expand Down
28 changes: 28 additions & 0 deletions tests/Select.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2114,4 +2114,32 @@ describe('Select.Basic', () => {
'test1 - 0',
);
});

it('labelRender', () => {
const onLabelRender = jest.fn();
const labelRender = (props: any) => {
const { label, value } = props;
onLabelRender();
return `${label}-${value}`;
};
const wrapper = mount(
<Select options={[{ label: 'realLabel', value: 'a' }]} value="a" labelRender={labelRender} />,
);

expect(onLabelRender).toHaveBeenCalled();
expect(findSelection(wrapper).text()).toEqual('realLabel-a');
});

it('labelRender when value is not in options', () => {
const onLabelRender = jest.fn();
const labelRender = (props: any) => {
const { label, value } = props;
onLabelRender();
return `${label || 'fakeLabel'}-${value}`;
xliez marked this conversation as resolved.
Show resolved Hide resolved
};
const wrapper = mount(<Select value="a" labelRender={labelRender} options={[{ label: 'realLabel', value: 'b' }]} />);

expect(onLabelRender).toHaveBeenCalled();
expect(findSelection(wrapper).text()).toEqual('fakeLabel-a');
});
xliez marked this conversation as resolved.
Show resolved Hide resolved
});
Loading