Skip to content

Commit c939a47

Browse files
authored
Feat: support 'treeExpandAction' prop for TreeSelect (#411)
1 parent ddc4ce0 commit c939a47

File tree

7 files changed

+161
-16
lines changed

7 files changed

+161
-16
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ online example: https://tree-select-react-component.vercel.app/
8181
|treeDefaultExpandAll | default expand all treeNode | bool | false |
8282
|treeDefaultExpandedKeys | default expanded treeNode keys | Array<String> | - |
8383
|treeExpandedKeys | set tree expanded keys | Array<String> | - |
84+
|treeExpandAction | Tree open logic, optional: false \| `click` \| `doubleClick`, same as `expandAction` of `rc-tree` | string \| boolean | `click` |
8485
|treeCheckable | whether tree show checkbox (select callback will not fire) | bool | false |
8586
|treeCheckStrictly | check node precisely, parent and children nodes are not associated| bool | false |
8687
|filterTreeNode | whether filter treeNodes by input value. default filter by treeNode's treeNodeFilterProp prop's value | bool/Function(inputValue:string, treeNode:TreeNode) | Function |

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"@babel/runtime": "^7.10.1",
7070
"classnames": "2.x",
7171
"rc-select": "~14.1.0",
72-
"rc-tree": "~5.5.0",
72+
"rc-tree": "~5.6.1",
7373
"rc-util": "^5.16.1"
7474
}
7575
}

src/OptionList.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const OptionList: React.RefForwardingComponent<ReviseRefOptionListProps> = (_, r
4141
fieldNames,
4242
onSelect,
4343
dropdownMatchSelectWidth,
44+
treeExpandAction,
4445
} = React.useContext(TreeSelectContext);
4546

4647
const {
@@ -244,6 +245,7 @@ const OptionList: React.RefForwardingComponent<ReviseRefOptionListProps> = (_, r
244245
onExpand={onInternalExpand}
245246
onLoad={onTreeLoad}
246247
filterTreeNode={filterTreeNode}
248+
expandAction={treeExpandAction}
247249
/>
248250
</div>
249251
);

src/TreeSelect.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as React from 'react';
22
import { BaseSelect } from 'rc-select';
33
import type { IconType } from 'rc-tree/lib/interface';
4+
import type { ExpandAction } from 'rc-tree/lib/Tree';
45
import type {
56
BaseSelectRef,
67
BaseSelectPropsWithoutPrivate,
@@ -152,6 +153,7 @@ export interface TreeSelectProps<
152153
treeExpandedKeys?: React.Key[];
153154
treeDefaultExpandedKeys?: React.Key[];
154155
onTreeExpand?: (expandedKeys: React.Key[]) => void;
156+
treeExpandAction?: ExpandAction;
155157

156158
// >>> Options
157159
virtual?: boolean;
@@ -217,6 +219,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
217219
treeExpandedKeys,
218220
treeDefaultExpandedKeys,
219221
onTreeExpand,
222+
treeExpandAction,
220223

221224
// Options
222225
virtual,
@@ -647,6 +650,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
647650
treeData: filteredTreeData,
648651
fieldNames: mergedFieldNames,
649652
onSelect: onOptionSelect,
653+
treeExpandAction,
650654
}),
651655
[
652656
virtual,
@@ -656,6 +660,7 @@ const TreeSelect = React.forwardRef<BaseSelectRef, TreeSelectProps>((props, ref)
656660
filteredTreeData,
657661
mergedFieldNames,
658662
onOptionSelect,
663+
treeExpandAction,
659664
],
660665
);
661666

src/TreeSelectContext.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import type { ExpandAction } from 'rc-tree/lib/Tree';
23
import type { DefaultOptionType, InternalFieldName, OnInternalSelect } from './TreeSelect';
34

45
export interface TreeSelectContextProps {
@@ -9,6 +10,7 @@ export interface TreeSelectContextProps {
910
treeData: DefaultOptionType[];
1011
fieldNames: InternalFieldName;
1112
onSelect: OnInternalSelect;
13+
treeExpandAction?: ExpandAction;
1214
}
1315

1416
const TreeSelectContext = React.createContext<TreeSelectContextProps>(null as any);
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/* eslint-disable no-undef, react/no-multi-comp, no-console */
2+
import React from 'react';
3+
import { mount } from 'enzyme';
4+
import TreeSelect from '../src';
5+
6+
describe('treeExpandAction with selectable props', () => {
7+
const treeData = [
8+
{
9+
title: '0-0',
10+
value: '0-0',
11+
selectable: false,
12+
children: [
13+
{
14+
title: '0-0-0',
15+
value: '0-0-0',
16+
selectable: false,
17+
children: [
18+
{
19+
title: '0-0-0-0',
20+
value: '0-0-0-0',
21+
selectable: false,
22+
},
23+
{
24+
title: '0-0-0-0',
25+
value: '0-0-0-1',
26+
selectable: false,
27+
},
28+
],
29+
},
30+
{
31+
title: '0-0-1',
32+
value: '0-0-1',
33+
selectable: false,
34+
children: [
35+
{
36+
title: '0-0-1-0',
37+
value: '0-0-1-0',
38+
selectable: false,
39+
},
40+
{
41+
title: '0-0-1-1',
42+
value: '0-0-1-1',
43+
selectable: false,
44+
},
45+
],
46+
},
47+
],
48+
},
49+
];
50+
51+
const clickNodeTitle = (wrapper, title) => {
52+
wrapper.find(`[title="${title}"]`).hostNodes().simulate('click');
53+
};
54+
55+
const doubleClickNodeTitle = (wrapper, title) => {
56+
wrapper.find(`[title="${title}"]`).hostNodes().simulate('doubleClick');
57+
};
58+
59+
it('title expandable when selectable is false and treeExpandAction is "click"', () => {
60+
const onSelect = jest.fn();
61+
const onTreeExpand = jest.fn();
62+
63+
const wrapper = mount(
64+
<TreeSelect
65+
open
66+
treeExpandAction="click"
67+
onTreeExpand={onTreeExpand}
68+
onSelect={onSelect}
69+
treeData={treeData}
70+
/>,
71+
);
72+
73+
clickNodeTitle(wrapper, '0-0');
74+
expect(onSelect).not.toHaveBeenCalled();
75+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0']);
76+
77+
onSelect.mockReset();
78+
onTreeExpand.mockReset();
79+
80+
clickNodeTitle(wrapper, '0-0-1');
81+
expect(onSelect).not.toHaveBeenCalled();
82+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0', '0-0-1']);
83+
84+
onSelect.mockReset();
85+
onTreeExpand.mockReset();
86+
87+
clickNodeTitle(wrapper, '0-0-1');
88+
expect(onSelect).not.toHaveBeenCalled();
89+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0']);
90+
});
91+
92+
it('title expandable when selectable is false and treeExpandAction is "doubleClick"', () => {
93+
const onSelect = jest.fn();
94+
const onTreeExpand = jest.fn();
95+
96+
const wrapper = mount(
97+
<TreeSelect
98+
open
99+
treeExpandAction="doubleClick"
100+
onTreeExpand={onTreeExpand}
101+
onSelect={onSelect}
102+
treeData={treeData}
103+
/>,
104+
);
105+
106+
doubleClickNodeTitle(wrapper, '0-0');
107+
expect(onSelect).not.toHaveBeenCalled();
108+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0']);
109+
110+
onSelect.mockReset();
111+
onTreeExpand.mockReset();
112+
113+
doubleClickNodeTitle(wrapper, '0-0-1');
114+
expect(onSelect).not.toHaveBeenCalled();
115+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0', '0-0-1']);
116+
117+
onSelect.mockReset();
118+
onTreeExpand.mockReset();
119+
120+
doubleClickNodeTitle(wrapper, '0-0-1');
121+
expect(onSelect).not.toHaveBeenCalled();
122+
expect(onTreeExpand).toHaveBeenCalledWith(['0-0']);
123+
});
124+
125+
it('title un-expandable when selectable is false and treeExpandAction is false', () => {
126+
const onSelect = jest.fn();
127+
const onTreeExpand = jest.fn();
128+
129+
const wrapper = mount(
130+
<TreeSelect
131+
open
132+
treeExpandAction={false}
133+
treeDefaultExpandedKeys={['0-0']}
134+
onTreeExpand={onTreeExpand}
135+
onSelect={onSelect}
136+
treeData={treeData}
137+
/>,
138+
);
139+
140+
clickNodeTitle(wrapper, '0-0-1');
141+
expect(onSelect).not.toHaveBeenCalled();
142+
expect(onTreeExpand).not.toHaveBeenCalled();
143+
});
144+
});

tests/setup.js

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,10 @@ Object.assign(Enzyme.ReactWrapper.prototype, {
1414
this.find('.rc-tree-select-selector').simulate('mousedown');
1515
},
1616
selectNode(index = 0) {
17-
this.find('.rc-tree-select-tree-node-content-wrapper')
18-
.at(index)
19-
.simulate('click');
17+
this.find('.rc-tree-select-tree-node-content-wrapper').at(index).simulate('click');
2018
},
2119
switchNode(index = 0) {
22-
this.find('.rc-tree-select-tree-switcher')
23-
.at(index)
24-
.simulate('click');
20+
this.find('.rc-tree-select-tree-switcher').at(index).simulate('click');
2521
},
2622
getSelection(index) {
2723
const selections = this.find('.rc-tree-select-selection-item');
@@ -41,17 +37,12 @@ Object.assign(Enzyme.ReactWrapper.prototype, {
4137
.simulate('click');
4238
},
4339
clearAll() {
44-
return this.find('.rc-tree-select-clear')
45-
.first()
46-
.simulate('mouseDown');
40+
return this.find('.rc-tree-select-clear').first().simulate('mouseDown');
4741
},
4842
search(text) {
49-
this.find('input.rc-tree-select-selection-search-input').simulate(
50-
'change',
51-
{
52-
target: { value: text },
53-
},
54-
);
43+
this.find('input.rc-tree-select-selection-search-input').simulate('change', {
44+
target: { value: text },
45+
});
5546
},
5647
isOpen() {
5748
return this.find('.rc-tree-select').hasClass('rc-tree-select-open');

0 commit comments

Comments
 (0)