Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions examples/treeNodeLabelProp.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import '../assets/index.less';
import React from 'react';
import TreeSelect, { TreeNode } from '../src';

const treeData = [
{
title: 'a list is option only',
showTitle: 'Node2',
value: '0-1',
},
];

function Demo() {
return (
<>
<TreeSelect
style={{ width: '100%' }}
treeDefaultExpandAll
treeData={treeData}
treeNodeLabelProp="showTitle"
/>
<TreeSelect style={{ width: '100%' }} treeDefaultExpandAll treeNodeLabelProp="showTitle">
<TreeNode value="0-0" title="a list is option only" showTitle="Node2" />
</TreeSelect>
</>
);
}

export default Demo;
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-select": "^11.0.4",
"rc-tree": "^3.6.0",
"rc-util": "^5.0.1"
"rc-tree": "^3.8.0",
"rc-util": "^5.0.5"
}
}
39 changes: 23 additions & 16 deletions src/TreeSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import * as React from 'react';
import { useMemo } from 'react';
import generateSelector, { SelectProps, RefSelectProps } from 'rc-select/lib/generate';
import { getLabeledValue } from 'rc-select/lib/utils/valueUtil';
import { convertDataToEntities } from 'rc-tree/lib/utils/treeUtil';
import { conductCheck } from 'rc-tree/lib/utils/conductUtil';
import { IconType } from 'rc-tree/lib/interface';
import { FilterFunc, INTERNAL_PROPS_MARK } from 'rc-select/lib/interface/generator';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import warning from 'rc-util/lib/warning';
import OptionList from './OptionList';
import TreeNode from './TreeNode';
Expand Down Expand Up @@ -206,37 +208,42 @@ const RefTreeSelect = React.forwardRef<RefSelectProps, TreeSelectProps>((props,
// ======================= Tree Data =======================
// Legacy both support `label` or `title` if not set.
// We have to fallback to function to handle this
const getTreeNodeTitle = (node: DataNode): React.ReactNode => {
if (!treeData) {
return node.title;
}
return node.label || node.title;
};

const getTreeNodeLabelProp = (node: DataNode): React.ReactNode => {
if (treeNodeLabelProp) {
return node[treeNodeLabelProp];
}

if (!treeData) {
return node.title;
}
return node.label || node.title;
return getTreeNodeTitle(node);
};

const mergedTreeData = useTreeData(treeData, children, {
getLabelProp: getTreeNodeLabelProp,
getLabelProp: getTreeNodeTitle,
simpleMode: treeDataSimpleMode,
});

const flattedOptions = React.useMemo(() => flattenOptions(mergedTreeData), [mergedTreeData]);
const flattedOptions = useMemo(() => flattenOptions(mergedTreeData), [mergedTreeData]);
const [cacheKeyMap, cacheValueMap] = useKeyValueMap(flattedOptions);
const [getEntityByKey, getEntityByValue] = useKeyValueMapping(cacheKeyMap, cacheValueMap);

// Only generate keyEntities for check conduction when is `treeCheckable`
const { keyEntities: conductKeyEntities } = React.useMemo(() => {
const { keyEntities: conductKeyEntities } = useMemo(() => {
if (treeConduction) {
return convertDataToEntities(mergedTreeData as any);
}
return { keyEntities: null };
}, [mergedTreeData, treeCheckable, treeCheckStrictly]);

// ========================= Value =========================
const [value, setValue] = React.useState<DefaultValueType>(props.defaultValue);
const mergedValue = 'value' in props ? props.value : value;
const [value, setValue] = useMergedState<DefaultValueType>(props.defaultValue, {
value: props.value,
});

/** Get `missingRawValues` which not exist in the tree yet */
const splitRawValues = (newRawValues: RawValueType[]) => {
Expand All @@ -255,11 +262,11 @@ const RefTreeSelect = React.forwardRef<RefSelectProps, TreeSelectProps>((props,
return { missingRawValues, existRawValues };
};

const [rawValues, rawHalfCheckedKeys]: [RawValueType[], RawValueType[]] = React.useMemo(() => {
const [rawValues, rawHalfCheckedKeys]: [RawValueType[], RawValueType[]] = useMemo(() => {
const valueHalfCheckedKeys: RawValueType[] = [];
const newRawValues: RawValueType[] = [];

toArray(mergedValue).forEach(item => {
toArray(value).forEach(item => {
if (item && typeof item === 'object' && 'value' in item) {
if (item.halfChecked && treeCheckStrictly) {
const entity = getEntityByValue(item.value);
Expand All @@ -284,10 +291,10 @@ const RefTreeSelect = React.forwardRef<RefSelectProps, TreeSelectProps>((props,
];
}
return [newRawValues, valueHalfCheckedKeys];
}, [mergedValue, mergedMultiple, mergedLabelInValue, treeCheckable, treeCheckStrictly]);
}, [value, mergedMultiple, mergedLabelInValue, treeCheckable, treeCheckStrictly]);
const selectValues = useSelectValues(rawValues, {
treeConduction,
value: mergedValue,
value,
showCheckedStrategy,
conductKeyEntities,
getEntityByValue,
Expand Down Expand Up @@ -326,7 +333,7 @@ const RefTreeSelect = React.forwardRef<RefSelectProps, TreeSelectProps>((props,
};

let returnValues = mergedLabelInValue
? getRawValueLabeled(eventValues, mergedValue, getEntityByValue, getTreeNodeLabelProp)
? getRawValueLabeled(eventValues, value, getEntityByValue, getTreeNodeLabelProp)
: eventValues;

// We need fill half check back
Expand All @@ -340,7 +347,7 @@ const RefTreeSelect = React.forwardRef<RefSelectProps, TreeSelectProps>((props,

returnValues = [
...(returnValues as LabelValueType[]),
...getRawValueLabeled(halfValues, mergedValue, getEntityByValue, getTreeNodeLabelProp),
...getRawValueLabeled(halfValues, value, getEntityByValue, getTreeNodeLabelProp),
];
}

Expand Down
25 changes: 25 additions & 0 deletions tests/Select.tree.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,29 @@ describe('TreeSelect.tree', () => {

expect(wrapper.getSelection(0).text()).toEqual('empty string');
});

describe('treeNodeLabelProp', () => {
[
{ name: 'treeDate', treeData: [{ title: 'a light', op: 'Light', value: 'light' }] },
{
name: 'children',
children: <SelectNode title="a light" op="Light" value="light" />,
},
].forEach(({ name, ...restProps }) => {
it(name, () => {
const wrapper = mount(
<TreeSelect
open
treeDefaultExpandAll
treeNodeLabelProp="op"
value="light"
{...restProps}
/>,
);

expect(wrapper.find('.rc-tree-select-tree-title').text()).toEqual('a light');
expect(wrapper.find('.rc-tree-select-selection-item').text()).toEqual('Light');
});
});
});
});