Skip to content

Commit

Permalink
feat: Add labelRender (#367)
Browse files Browse the repository at this point in the history
* feat: Add labelRender

* test: Patch test case
  • Loading branch information
zombieJ authored Jun 22, 2021
1 parent af3f36d commit f343e14
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 37 deletions.
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100
"printWidth": 100,
"arrowParens": "avoid"
}
17 changes: 12 additions & 5 deletions examples/debug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,25 @@ class Demo extends React.Component {
allowClear
treeDefaultExpandAll
onChange={this.onChange}
labelRender={entity => {
let current = entity;
const nodes = [];

while (current) {
nodes.unshift(current.data.title);
current = current.parent;
}

return nodes.join('>');
}}
>
<TreeNode value="parent 1" title="parent 1" key="0-1">
<TreeNode value="parent 1-0" title="parent 1-0" key="0-1-1">
<TreeNode value="leaf1" title="my leaf" key="random" />
<TreeNode value="leaf2" title="your leaf" key="random1" />
</TreeNode>
<TreeNode value="parent 1-1" title="parent 1-1" key="random2">
<TreeNode
value="sss"
title={<b style={{ color: '#08c' }}>sss</b>}
key="random3"
/>
<TreeNode value="sss" title={<b style={{ color: '#08c' }}>sss</b>} key="random3" />
</TreeNode>
</TreeNode>
</TreeSelect>
Expand Down
43 changes: 27 additions & 16 deletions src/generate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ChangeEventExtra,
LegacyDataNode,
SelectSource,
FlattenDataNode,
} from './interface';
import {
flattenOptions,
Expand Down Expand Up @@ -130,6 +131,9 @@ export interface TreeSelectProps<ValueType = DefaultValueType>
// Legacy
/** `searchPlaceholder` has been removed since search box has been merged into input box */
searchPlaceholder?: React.ReactNode;

/** @private This is not standard API since we only used in `rc-cascader`. Do not use in your production */
labelRender?: (entity: FlattenDataNode) => React.ReactNode;
}

export default function generate(config: {
Expand All @@ -153,7 +157,7 @@ export default function generate(config: {
findValueOption,
omitDOMProps: (props: object) => {
const cloneProps = { ...props };
OMIT_PROPS.forEach((prop) => {
OMIT_PROPS.forEach(prop => {
delete cloneProps[prop];
});
return cloneProps;
Expand Down Expand Up @@ -195,6 +199,7 @@ export default function generate(config: {
onDropdownVisibleChange,
onSelect,
onDeselect,
labelRender,
} = props;
const mergedCheckable: React.ReactNode | boolean = treeCheckable || treeCheckStrictly;
const mergedMultiple = multiple || mergedCheckable;
Expand All @@ -211,7 +216,13 @@ export default function generate(config: {
return node.label || node.title;
};

const getTreeNodeLabelProp = (node: DataNode): React.ReactNode => {
const getTreeNodeLabelProp = (entity: FlattenDataNode): React.ReactNode => {
const node = entity.data;

if (labelRender) {
return labelRender(entity);
}

if (treeNodeLabelProp) {
return node[treeNodeLabelProp];
}
Expand Down Expand Up @@ -259,7 +270,7 @@ export default function generate(config: {
const existRawValues = [];

// Keep missing value in the cache
newRawValues.forEach((val) => {
newRawValues.forEach(val => {
if (getEntityByValue(val)) {
existRawValues.push(val);
} else {
Expand All @@ -274,7 +285,7 @@ export default function generate(config: {
const valueHalfCheckedKeys: RawValueType[] = [];
const newRawValues: RawValueType[] = [];

toArray(value).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 @@ -290,11 +301,11 @@ export default function generate(config: {
// We need do conduction of values
if (treeConduction) {
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
const keyList = existRawValues.map((val) => getEntityByValue(val).key);
const keyList = existRawValues.map(val => getEntityByValue(val).key);

const { checkedKeys, halfCheckedKeys } = conductCheck(keyList, true, conductKeyEntities);
return [
[...missingRawValues, ...checkedKeys.map((key) => getEntityByKey(key).data.value)],
[...missingRawValues, ...checkedKeys.map(key => getEntityByKey(key).data.value)],
halfCheckedKeys,
];
}
Expand All @@ -319,7 +330,7 @@ export default function generate(config: {
if (onChange) {
let eventValues: RawValueType[] = newRawValues;
if (treeConduction && showCheckedStrategy !== 'SHOW_ALL') {
const keyList = newRawValues.map((val) => {
const keyList = newRawValues.map(val => {
const entity = getEntityByValue(val);
return entity ? entity.key : val;
});
Expand All @@ -329,7 +340,7 @@ export default function generate(config: {
conductKeyEntities,
);

eventValues = formattedKeyList.map((key) => {
eventValues = formattedKeyList.map(key => {
const entity = getEntityByKey(key);
return entity ? entity.data.value : key;
});
Expand All @@ -347,11 +358,11 @@ export default function generate(config: {
// We need fill half check back
if (treeCheckStrictly) {
const halfValues = rawHalfCheckedKeys
.map((key) => {
.map(key => {
const entity = getEntityByKey(key);
return entity ? entity.data.value : key;
})
.filter((val) => !eventValues.includes(val));
.filter(val => !eventValues.includes(val));

returnValues = [
...(returnValues as LabelValueType[]),
Expand Down Expand Up @@ -391,9 +402,9 @@ export default function generate(config: {
mergedMultiple ? returnValues : returnValues[0],
mergedLabelInValue
? null
: eventValues.map((val) => {
: eventValues.map(val => {
const entity = getEntityByValue(val);
return entity ? getTreeNodeLabelProp(entity.data) : null;
return entity ? getTreeNodeLabelProp(entity) : null;
}),
additionalInfo,
);
Expand All @@ -417,11 +428,11 @@ export default function generate(config: {
if (treeConduction) {
// Should keep missing values
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
const keyList = existRawValues.map((val) => getEntityByValue(val).key);
const keyList = existRawValues.map(val => getEntityByValue(val).key);
const { checkedKeys } = conductCheck(keyList, true, conductKeyEntities);
newRawValues = [
...missingRawValues,
...checkedKeys.map((key) => getEntityByKey(key).data.value),
...checkedKeys.map(key => getEntityByKey(key).data.value),
];
}

Expand All @@ -445,15 +456,15 @@ export default function generate(config: {
// Remove keys if tree conduction
if (treeConduction) {
const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
const keyList = existRawValues.map((val) => getEntityByValue(val).key);
const keyList = existRawValues.map(val => getEntityByValue(val).key);
const { checkedKeys } = conductCheck(
keyList,
{ checked: false, halfCheckedKeys: rawHalfCheckedKeys },
conductKeyEntities,
);
newRawValues = [
...missingRawValues,
...checkedKeys.map((key) => getEntityByKey(key).data.value),
...checkedKeys.map(key => getEntityByKey(key).data.value),
];
}

Expand Down
8 changes: 4 additions & 4 deletions src/hooks/useSelectValues.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import type { DefaultValueType } from 'rc-select/lib/interface/generator';
import type { DataEntity } from 'rc-tree/lib/interface';
import type { RawValueType, FlattenDataNode, Key, LabelValueType, DataNode } from '../interface';
import type { RawValueType, FlattenDataNode, Key, LabelValueType } from '../interface';
import type { SkipType } from './useKeyValueMapping';
import { getRawValueLabeled } from '../utils/valueUtil';
import type { CheckedStrategy } from '../utils/strategyUtil';
Expand All @@ -19,7 +19,7 @@ interface Config {
skipType?: SkipType,
ignoreDisabledCheck?: boolean,
) => FlattenDataNode;
getLabelProp: (node: DataNode) => React.ReactNode;
getLabelProp: (entity: FlattenDataNode) => React.ReactNode;
}

/** Return */
Expand All @@ -40,15 +40,15 @@ export default function useSelectValues(

if (treeConduction) {
const rawKeys = formatStrategyKeys(
rawValues.map((val) => {
rawValues.map(val => {
const entity = getEntityByValue(val);
return entity ? entity.key : val;
}),
showCheckedStrategy,
conductKeyEntities,
);

mergedRawValues = rawKeys.map((key) => {
mergedRawValues = rawKeys.map(key => {
const entity = getEntityByKey(key);
return entity ? entity.data.value : key;
});
Expand Down
22 changes: 11 additions & 11 deletions src/utils/valueUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ export function toArray<T>(value: T | T[]): T[] {
export function findValueOption(values: RawValueType[], options: CompatibleDataNode[]): DataNode[] {
const optionMap: Map<RawValueType, DataNode> = new Map();

options.forEach((flattenItem) => {
options.forEach(flattenItem => {
const { data } = flattenItem;
optionMap.set(data.value, data);
});

return values.map((val) => fillLegacyProps(optionMap.get(val)));
return values.map(val => fillLegacyProps(optionMap.get(val)));
}

export function isValueDisabled(value: RawValueType, options: CompatibleDataNode[]): boolean {
Expand Down Expand Up @@ -68,7 +68,7 @@ function getLevel({ parent }: FlattenNode): number {
export function flattenOptions(options: DataNode[]): FlattenDataNode[] {
// Add missing key
function fillKey(list: DataNode[]): TreeDataNode[] {
return (list || []).map((node) => {
return (list || []).map(node => {
const { value, key, children } = node;

const clone = {
Expand All @@ -88,7 +88,7 @@ export function flattenOptions(options: DataNode[]): FlattenDataNode[] {

const cacheMap = new Map<React.Key, FlattenDataNode>();
const flattenDateNodeList: (FlattenDataNode & { parentKey?: React.Key })[] = flattenList.map(
(node) => {
node => {
const { data } = node;
const { key } = data;

Expand All @@ -106,7 +106,7 @@ export function flattenOptions(options: DataNode[]): FlattenDataNode[] {
);

// Fill parent
flattenDateNodeList.forEach((flattenNode) => {
flattenDateNodeList.forEach(flattenNode => {
// eslint-disable-next-line no-param-reassign
flattenNode.parent = cacheMap.get(flattenNode.parentKey);
});
Expand Down Expand Up @@ -147,7 +147,7 @@ export function filterOptions(

function dig(list: DataNode[], keepAll: boolean = false) {
return list
.map((dataNode) => {
.map(dataNode => {
const { children } = dataNode;

const match = keepAll || filterOptionFunc(searchValue, fillLegacyProps(dataNode));
Expand All @@ -161,7 +161,7 @@ export function filterOptions(
}
return null;
})
.filter((node) => node);
.filter(node => node);
}

return dig(options);
Expand All @@ -175,20 +175,20 @@ export function getRawValueLabeled(
skipType?: SkipType,
ignoreDisabledCheck?: boolean,
) => FlattenDataNode,
getLabelProp: (node: DataNode) => React.ReactNode,
getLabelProp: (entity: FlattenDataNode) => React.ReactNode,
): LabelValueType[] {
const valueMap = new Map<RawValueType, LabelValueType>();

toArray(prevValue).forEach((item) => {
toArray(prevValue).forEach(item => {
if (item && typeof item === 'object' && 'value' in item) {
valueMap.set(item.value, item);
}
});

return values.map((val) => {
return values.map(val => {
const item: LabelValueType = { value: val };
const entity = getEntityByValue(val, 'select', true);
const label = entity ? getLabelProp(entity.data) : val;
const label = entity ? getLabelProp(entity) : val;

if (valueMap.has(val)) {
const labeledValue = valueMap.get(val);
Expand Down
34 changes: 34 additions & 0 deletions tests/Select.internal.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { mount } from 'enzyme';
import TreeSelect from '../src';

describe('TreeSelect.InternalAPI', () => {
it('labelRender', () => {
const wrapper = mount(
<TreeSelect
value="little"
treeData={[
{
label: 'Bamboo',
value: 'bamboo',
children: [
{ label: 'Light', value: 'light', children: [{ label: 'Little', value: 'little' }] },
],
},
]}
labelRender={entity => {
let current = entity;
const nodes = [];

while (current) {
nodes.unshift(current.data.label);
current = current.parent;
}

return nodes.join('>');
}}
/>,
);
expect(wrapper.find('.rc-tree-select-selection-item').text()).toEqual('Bamboo>Light>Little');
});
});

1 comment on commit f343e14

@vercel
Copy link

@vercel vercel bot commented on f343e14 Jun 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.