Skip to content

Commit fc47b2a

Browse files
committed
fix(Select): improved label handling
1 parent c34f864 commit fc47b2a

File tree

3 files changed

+60
-27
lines changed

3 files changed

+60
-27
lines changed

packages/components/_util/parseTNode.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import React, { ReactElement, ReactNode } from 'react';
1+
import React, { type ReactElement, type ReactNode } from 'react';
22
import { isFunction } from 'lodash-es';
33
import log from '@tdesign/common-js/log/index';
4-
import { TNode } from '../common';
4+
import type { TNode } from '../common';
55

66
// 解析 TNode 数据结构
77
export default function parseTNode(
@@ -37,3 +37,16 @@ export function parseContentTNode<T>(tnode: TNode<T>, props: T) {
3737
return null;
3838
}
3939
}
40+
41+
export function extractTextFromTNode(node: TNode): string {
42+
if (typeof node === 'string' || typeof node === 'number' || typeof node === 'boolean') return String(node);
43+
if (React.isValidElement(node)) {
44+
const { children } = node.props || {};
45+
if (children) return extractTextFromTNode(children);
46+
}
47+
if (Array.isArray(node)) {
48+
return node.map(extractTextFromTNode).join('');
49+
}
50+
// todo:兼容 ((props: T) => ReactNode) 函数类型
51+
return '';
52+
}

packages/components/select-input/useSingle.tsx

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, { useRef } from 'react';
33
import classNames from 'classnames';
44
import { isObject, pick } from 'lodash-es';
55

6+
import { extractTextFromTNode } from '../_util/parseTNode';
67
import useConfig from '../hooks/useConfig';
78
import useControlled from '../hooks/useControlled';
89
import Input, { type InputRef, type TdInputProps } from '../input';
@@ -39,8 +40,9 @@ const DEFAULT_KEYS: TdSelectInputProps['keys'] = {
3940
};
4041

4142
function getInputValue(value: TdSelectInputProps['value'], keys: TdSelectInputProps['keys']) {
43+
if (!value) return '';
4244
const iKeys = keys || DEFAULT_KEYS;
43-
return isObject(value) ? value[iKeys.label] : value;
45+
return isObject(value) ? extractTextFromTNode(value[iKeys.label]) : String(value);
4446
}
4547

4648
export default function useSingle(props: TdSelectInputProps) {
@@ -75,7 +77,23 @@ export default function useSingle(props: TdSelectInputProps) {
7577
) => {
7678
// 单选,值的呈现方式
7779
const singleValueDisplay: any = !props.multiple ? props.valueDisplay : null;
78-
const displayedValue = popupVisible && props.allowInput ? inputValue : getInputValue(value, keys);
80+
81+
let displayedValue: string;
82+
let displayPlaceholder: string;
83+
84+
if (popupVisible && props.allowInput) {
85+
// 弹窗打开且允许输入时
86+
displayedValue = inputValue;
87+
displayPlaceholder = extractTextFromTNode(props.placeholder);
88+
} else if (singleValueDisplay) {
89+
// 有选中值时
90+
displayedValue = extractTextFromTNode(singleValueDisplay);
91+
displayPlaceholder = extractTextFromTNode(singleValueDisplay);
92+
} else {
93+
// 没有选中值时
94+
displayedValue = getInputValue(value, keys);
95+
displayPlaceholder = props.placeholder;
96+
}
7997

8098
const handleBlur = (value, ctx) => {
8199
if (blurTimeoutRef.current) {
@@ -110,16 +128,9 @@ export default function useSingle(props: TdSelectInputProps) {
110128
{...commonInputProps}
111129
autoWidth={props.autoWidth}
112130
allowInput={props.allowInput}
113-
placeholder={singleValueDisplay ? '' : props.placeholder}
114-
value={singleValueDisplay ? ' ' : displayedValue}
115-
label={
116-
(props.label || singleValueDisplay) && (
117-
<>
118-
{props.label}
119-
{singleValueDisplay as React.ReactNode}
120-
</>
121-
)
122-
}
131+
placeholder={displayPlaceholder}
132+
value={displayedValue}
133+
label={props.label}
123134
onChange={onInnerInputChange}
124135
onClear={onInnerClear}
125136
// [Important Info]: SelectInput.blur is not equal to Input, example: click popup panel

packages/components/select/base/Select.tsx

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import composeRefs from '../../_util/composeRefs';
1616
import forwardRefWithStatics from '../../_util/forwardRefWithStatics';
1717
import { getOffsetTopToContainer } from '../../_util/helper';
1818
import noop from '../../_util/noop';
19-
import { parseContentTNode } from '../../_util/parseTNode';
19+
import { extractTextFromTNode, parseContentTNode } from '../../_util/parseTNode';
2020
import FakeArrow from '../../common/FakeArrow';
2121
import useConfig from '../../hooks/useConfig';
2222
import useControlled from '../../hooks/useControlled';
@@ -287,23 +287,30 @@ const Select = forwardRefWithStatics(
287287
return filter(value, option);
288288
}
289289
const upperValue = value.toUpperCase();
290-
return (option?.label || '').toUpperCase().includes(upperValue);
290+
const searchableText = extractTextFromTNode(option.label);
291+
return searchableText.toUpperCase().includes(upperValue);
291292
};
292293

293294
tmpPropOptions?.forEach((option) => {
294295
if (isSelectOptionGroup(option)) {
295-
filteredOptions.push({
296-
...option,
297-
children: option.children?.filter((child) => {
298-
if (filterMethods(child)) {
299-
filterLabels.push(child.label);
300-
return true;
301-
}
302-
return false;
303-
}),
296+
const filteredChildren = option.children?.filter((child) => {
297+
if (filterMethods(child)) {
298+
const searchableText = extractTextFromTNode(child?.label);
299+
filterLabels.push(searchableText);
300+
return true;
301+
}
302+
return false;
304303
});
304+
305+
if (filteredChildren && filteredChildren.length > 0) {
306+
filteredOptions.push({
307+
...option,
308+
children: filteredChildren,
309+
});
310+
}
305311
} else if (filterMethods(option)) {
306-
filterLabels.push(option.label);
312+
const searchableText = extractTextFromTNode(option?.label);
313+
filterLabels.push(searchableText);
307314
filteredOptions.push(option);
308315
}
309316
});
@@ -367,6 +374,7 @@ const Select = forwardRefWithStatics(
367374
}
368375
return child;
369376
});
377+
370378
// 渲染主体内容
371379
const renderContent = () => {
372380
const popupContentProps = {
@@ -404,6 +412,7 @@ const Select = forwardRefWithStatics(
404412
}
405413
return ({ value: val }) =>
406414
val.slice(0, minCollapsedNum ? minCollapsedNum : val.length).map((v: string, key: number) => {
415+
const originalLabel = get(selectedOptions[key], keys?.label || 'label');
407416
const filterOption: SelectOption & { disabled?: boolean } = options?.find((option) => option.label === v);
408417
return (
409418
<Tag
@@ -438,7 +447,7 @@ const Select = forwardRefWithStatics(
438447
});
439448
}}
440449
>
441-
{v}
450+
{originalLabel}
442451
</Tag>
443452
);
444453
});

0 commit comments

Comments
 (0)