Skip to content

Commit 243d54c

Browse files
committed
Feat: support 'treeExpandAction' prop for TreeSelect
1 parent ddc4ce0 commit 243d54c

File tree

7 files changed

+174
-16
lines changed

7 files changed

+174
-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);

tests/Select.tree.treeExpandAction.js

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

tests/setup.js

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,16 @@ 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');
21+
},
22+
clickNodeTitle(title) {
23+
this.find(`[title="${title}"]`).hostNodes().simulate('click');
24+
},
25+
doubleClickNodeTitle(title) {
26+
this.find(`[title="${title}"]`).hostNodes().simulate('doubleClick');
2527
},
2628
getSelection(index) {
2729
const selections = this.find('.rc-tree-select-selection-item');
@@ -41,17 +43,12 @@ Object.assign(Enzyme.ReactWrapper.prototype, {
4143
.simulate('click');
4244
},
4345
clearAll() {
44-
return this.find('.rc-tree-select-clear')
45-
.first()
46-
.simulate('mouseDown');
46+
return this.find('.rc-tree-select-clear').first().simulate('mouseDown');
4747
},
4848
search(text) {
49-
this.find('input.rc-tree-select-selection-search-input').simulate(
50-
'change',
51-
{
52-
target: { value: text },
53-
},
54-
);
49+
this.find('input.rc-tree-select-selection-search-input').simulate('change', {
50+
target: { value: text },
51+
});
5552
},
5653
isOpen() {
5754
return this.find('.rc-tree-select').hasClass('rc-tree-select-open');

0 commit comments

Comments
 (0)