Skip to content

Commit

Permalink
feat: Tree/TreeSelect add autoMergeValue API
Browse files Browse the repository at this point in the history
  • Loading branch information
YyumeiZhang committed Jun 3, 2024
1 parent 8aea255 commit 5a893a0
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 61 deletions.
1 change: 1 addition & 0 deletions content/input/treeselect/index-en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -1412,6 +1412,7 @@ function Demo() {
| arrowIcon|Customize the right drop-down arrow Icon, when the showClear switch is turned on and there is currently a selected value, hover will give priority to the clear icon| ReactNode | | 1.15.0|
|autoAdjustOverflow|Whether the pop-up layer automatically adjusts the direction when it is obscured (only vertical direction is supported for the time being, and the inserted parent is body)|boolean | true| 0.34.0|
| autoExpandParent | Toggle whether to expand parent nodes automatically | boolean | false | 0.34.0 |
| autoMergeValue | Sets the automerge value. Specifically, when enabled, when a parent node is selected, value will include that node and its children. (Works if leafOnly is false)| boolean | false | 2.60.0 |
| borderless | borderless mode >=2.33.0 | boolean | |
| checkRelation | In multiple, the relationship between the checked states of the nodes, optional: 'related'、'unRelated' | string | 'related' | 2.5.0 |
| className | Class name | string | - | - |
Expand Down
1 change: 1 addition & 0 deletions content/input/treeselect/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1395,6 +1395,7 @@ function Demo() {
| arrowIcon| 自定义右侧下拉箭头Icon,当showClear开关打开且当前有选中值时,hover会优先显示clear icon | ReactNode | | 1.15.0|
| autoAdjustOverflow| 浮层被遮挡时是否自动调整方向(暂时仅支持竖直方向,且插入的父级为 body) |boolean | true| 0.34.0|
| autoExpandParent | 是否自动展开父节点 | boolean | false | 0.34.0 |
| autoMergeValue | 设置自动合并 value。具体而言是,开启后,当某个父节点被选中时,value 将包括该节点以及该子孙节点。(在leafOnly为false的情况下生效)| boolean | false | 2.60.0 |
| borderless | 无边框模式 >=2.33.0 | boolean | |
| checkRelation | 多选时,节点之间选中状态的关系,可选:'related'、'unRelated' | string | 'related' | 2.5.0 |
| className | 选择框的 `className` 属性 | string | - | - |
Expand Down
2 changes: 1 addition & 1 deletion content/navigation/tree/index-en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -2271,7 +2271,7 @@ import { IconFixedStroked, IconSectionStroked, IconAbsoluteStroked, IconInnerSec
| ------------------- | --------------------- | ------------------------------------------------- | ------- | ------ |
| autoExpandParent | Toggle whether to expand parent node automatically | boolean | false | 0.34.0 |
| autoExpandWhenDragEnter | Toggle whether allow autoExpand when drag enter node | boolean | true | 1.8.0 |
| autoMergeValue | Sets the automerge value. Specifically, when enabled, when a parent node is selected, value will include that node and its children. (Works if leafOnly is false)| boolean | false | - |
| autoMergeValue | Sets the automerge value. Specifically, when enabled, when a parent node is selected, value will include that node and its children. (Works if leafOnly is false)| boolean | false | 2.60.0 |
| blockNode | Toggle whether to display node as row | boolean | true | - |
| checkRelation | In multiple, the relationship between the checked states of the nodes, optional: 'related'、'unRelated' | string | 'related' | 2.5.0 |
| className | Class name| string | - | - |
Expand Down
2 changes: 1 addition & 1 deletion content/navigation/tree/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2286,7 +2286,7 @@ import { IconFixedStroked, IconSectionStroked, IconAbsoluteStroked, IconInnerSec
|------------- | ----------- | -------------- | -------------- | --------|
| autoExpandParent | 是否自动展开父节点,默认为 false,当组件初次挂载时为 true | boolean | false | 0.34.0 |
| autoExpandWhenDragEnter | 是否允许拖拽到节点上时自动展开改节点 | boolean | true | 1.8.0 |
| autoMergeValue | 设置自动合并 value。具体而言是,开启后,当某个父节点被选中时,value 将包括该节点以及该子孙节点。(在leafOnly为false的情况下生效)| boolean | false | - |
| autoMergeValue | 设置自动合并 value。具体而言是,开启后,当某个父节点被选中时,value 将包括该节点以及该子孙节点。(在leafOnly为false的情况下生效)| boolean | false | 2.60.0 |
| blockNode | 行显示节点 | boolean | true | - |
| checkRelation | 多选时,节点之间选中状态的关系,可选:'related'、'unRelated' | string | 'related' | 2.5.0 |
| className | 类名 | string | - | - |
Expand Down
2 changes: 1 addition & 1 deletion packages/semi-foundation/tree/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ export default class TreeFoundation extends BaseFoundation<TreeAdapter, BasicTre
let value;
let keyList = [];
if (checkRelation === 'related') {
keyList = normalizeKeyList(key, keyEntities, leafOnly, autoMergeValue, true);
keyList = autoMergeValue ? normalizeKeyList(key, keyEntities, leafOnly, true) : key;
} else if (checkRelation === 'unRelated') {
keyList = key;
}
Expand Down
30 changes: 13 additions & 17 deletions packages/semi-foundation/tree/treeUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,27 +454,23 @@ export function normalizedArr(val: any) {

// flag is used to determine whether to return when the key does not belong to the keys in keyEntities
// export function normalizeKeyList(keyList: any, keyEntities: KeyEntities, leafOnly = false) {
export function normalizeKeyList(keyList: any, keyEntities: KeyEntities, leafOnly = false, autoMergeValue = false, flag?: boolean) {
export function normalizeKeyList(keyList: any, keyEntities: KeyEntities, leafOnly = false, flag?: boolean) {
const res: string[] = [];
const keyListSet = new Set(keyList);
if (!leafOnly) {
if (!autoMergeValue) {
keyList.forEach((key: string) => {
if (!keyEntities[key]) {
if (flag) {
res.push(key);
}
return;
}
const { parent } = keyEntities[key];
if (parent && keyListSet.has(parent.key)) {
return;
keyList.forEach((key: string) => {
if (!keyEntities[key]) {
if (flag) {
res.push(key);
}
res.push(key);
});
} else {
return keyList;
}
return;
}
const { parent } = keyEntities[key];
if (parent && keyListSet.has(parent.key)) {
return;
}
res.push(key);
});
} else {
keyList.forEach(key => {
if (keyEntities[key] && !isValid(keyEntities[key].children)) {
Expand Down
4 changes: 2 additions & 2 deletions packages/semi-foundation/treeSelect/foundation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,10 @@ export default class TreeSelectFoundation<P = Record<string, any>, S = Record<st

_notifyMultipleChange(key: string[], e: any) {
const { keyEntities } = this.getStates();
const { leafOnly, checkRelation, keyMaps } = this.getProps();
const { leafOnly, checkRelation, keyMaps, autoMergeValue } = this.getProps();
let keyList = [];
if (checkRelation === 'related') {
keyList = normalizeKeyList(key, keyEntities, leafOnly, true);
keyList = autoMergeValue ? normalizeKeyList(key, keyEntities, leafOnly, true) : key;
} else if (checkRelation === 'unRelated') {
keyList = key as string[];
}
Expand Down
21 changes: 21 additions & 0 deletions packages/semi-ui/tree/__test__/treeMultiple.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -821,4 +821,25 @@ describe('Tree', () => {
expect(spyOnChange.calledWithMatch(['fish', 'Yazhou'])).toEqual(true);
tree.unmount();
})

it('onChange + autoMergeValue', () => {
let spyOnSelect = sinon.spy(() => { });
let spyOnChange = sinon.spy(() => { });
let treeSelect = getTree({
defaultExpandAll: true,
onSelect: spyOnSelect,
onChange: spyOnChange,
autoMergeValue: false,
});
let nodeChina = treeSelect.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0);
// select China
nodeChina.simulate('click');
// onSelect & onChange
expect(spyOnSelect.calledOnce).toBe(true);
expect(spyOnChange.calledOnce).toBe(true);
expect(spyOnSelect.calledWithMatch('zhongguo', true, { key: "zhongguo" })).toEqual(true);
expect(spyOnChange.calledWithMatch(
['Zhongguo', 'Beijing', 'Shanghai'],
)).toEqual(true);
});
})
22 changes: 22 additions & 0 deletions packages/semi-ui/tree/_story/tree.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3116,4 +3116,26 @@ export const CustomRenderIcon = () => {
treeData={treeDataWithSuffix}
icon={iconFunc}
/>);
}

export const AutoMerge = () => {
const [value, setValue] = useState([]);

const onChange = useCallback((val) => {
console.log('onChange', val);
setValue(val);
}, []);

return (
<>
<Tree
autoMergeValue={false}
style={{ width: 300}}
multiple
value={value}
onChange={onChange}
treeData={treeData1}
/>
</>
)
}
1 change: 1 addition & 0 deletions packages/semi-ui/tree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class Tree extends BaseComponent<TreeProps, TreeState> {
draggable: false,
autoExpandWhenDragEnter: true,
checkRelation: 'related',
autoMergeValue: true,
};

static TreeNode: typeof TreeNode;
Expand Down
3 changes: 2 additions & 1 deletion packages/semi-ui/tree/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ export interface TreeProps extends BasicTreeProps {
onSelect?: (selectedKey: string, selected: boolean, selectedNode: TreeNodeData) => void;
renderDraggingNode?: (nodeInstance: HTMLElement, node: TreeNodeData) => HTMLElement;
renderFullLabel?: (renderFullLabelProps: RenderFullLabelProps) => ReactNode;
renderLabel?: (label?: ReactNode, treeNode?: TreeNodeData) => ReactNode
renderLabel?: (label?: ReactNode, treeNode?: TreeNodeData) => ReactNode;
autoMergeValue?: boolean
}
export interface OptionProps {
index: number;
Expand Down
24 changes: 24 additions & 0 deletions packages/semi-ui/treeSelect/__test__/treeMultiple.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1129,4 +1129,28 @@ describe('TreeSelect', () => {
let selectContentNode = treeSelect.find(`.${BASE_CLASS_PREFIX}-tree-select-selection`).at(0);
expect(selectContentNode.find(`.${BASE_CLASS_PREFIX}-tag-content`).instance().textContent).toEqual('中国');
});

it('onChange + autoMergeValue', () => {
let spyOnSelect = sinon.spy(() => { });
let spyOnChange = sinon.spy(() => { });
let treeSelect = getTreeSelect({
defaultExpandAll: true,
onSelect: spyOnSelect,
onChange: spyOnChange,
autoMergeValue: false,
});
let nodeChina = treeSelect.find(`.${BASE_CLASS_PREFIX}-tree-option.${BASE_CLASS_PREFIX}-tree-option-level-2`).at(0);
// select China
nodeChina.simulate('click');
// onSelect & onChange
expect(spyOnSelect.calledOnce).toBe(true);
expect(spyOnChange.calledOnce).toBe(true);
expect(spyOnSelect.calledWithMatch('zhongguo', true, { key: "zhongguo" })).toEqual(true);
expect(spyOnChange.calledWithMatch(
['Zhongguo', 'Beijing', 'Shanghai'],
)).toEqual(true);

let tagGroup = treeSelect.find(`.${BASE_CLASS_PREFIX}-tag`);
expect(tagGroup.length).toEqual(3);
});
})
22 changes: 22 additions & 0 deletions packages/semi-ui/treeSelect/_story/treeSelect.stories.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2790,3 +2790,25 @@ export const CustomSelectAll = () => {
</>
);
};

export const AutoMerge = () => {
const [value, setValue] = useState([]);

const onChange = useCallback((val) => {
console.log('onChange', val);
setValue(val);
}, []);

return (
<>
<TreeSelect
autoMergeValue={false}
style={{ width: 300}}
multiple
value={value}
onChange={onChange}
treeData={treeData1}
/>
</>
)
}
Loading

0 comments on commit 5a893a0

Please sign in to comment.