Skip to content

Commit a9efbc7

Browse files
committed
feat: default active first item
1 parent 481c983 commit a9efbc7

5 files changed

+116
-62
lines changed

src/OptionList.tsx

+30-6
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,36 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
9292
};
9393
}, [checkable, checkedKeys, halfCheckedKeys]);
9494

95+
// ========================== Get First Selectable Node ==========================
96+
const getFirstSelectableNode = (nodes: EventDataNode<any>): EventDataNode<any> | null => {
97+
for (const node of nodes) {
98+
if (node.selectable !== false) {
99+
return node;
100+
}
101+
if (node[fieldNames.children]) {
102+
const selectableInChildren = getFirstSelectableNode(node[fieldNames.children]);
103+
if (selectableInChildren) {
104+
return selectableInChildren;
105+
}
106+
}
107+
}
108+
return null;
109+
};
110+
95111
// ========================== Scroll ==========================
96112
React.useEffect(() => {
97-
// Single mode should scroll to current key
98-
if (open && !multiple && checkedKeys.length) {
99-
treeRef.current?.scrollTo({ key: checkedKeys[0] });
100-
setActiveKey(checkedKeys[0]);
113+
if (open) {
114+
// Single mode should scroll to current key
115+
if (!multiple && checkedKeys.length) {
116+
treeRef.current?.scrollTo({ key: checkedKeys[0] });
117+
setActiveKey(checkedKeys[0]);
118+
} else {
119+
// Otherwise, activate the first selectable node
120+
const firstSelectableNode = getFirstSelectableNode(memoTreeData);
121+
if (firstSelectableNode) {
122+
setActiveKey(firstSelectableNode[fieldNames.value]);
123+
}
124+
}
101125
}
102126
// eslint-disable-next-line react-hooks/exhaustive-deps
103127
}, [open]);
@@ -199,8 +223,8 @@ const OptionList: React.ForwardRefRenderFunction<ReviseRefOptionListProps> = (_,
199223
// >>> Select item
200224
case KeyCode.ENTER: {
201225
if (activeEntity) {
202-
const { selectable, value } = activeEntity?.node || {};
203-
if (selectable !== false) {
226+
const { selectable, value, disabled } = activeEntity?.node || {};
227+
if (selectable !== false && !disabled) {
204228
onInternalSelect(null, {
205229
node: { key: activeKey },
206230
selected: !checkedKeys.includes(value),

tests/Select.SearchInput.spec.js

-24
Original file line numberDiff line numberDiff line change
@@ -229,30 +229,6 @@ describe('TreeSelect.SearchInput', () => {
229229
expect(onSelect).not.toHaveBeenCalled();
230230
});
231231

232-
it('should not select any node when no search value and press enter', () => {
233-
const onSelect = jest.fn();
234-
const wrapper = mount(
235-
<TreeSelect
236-
showSearch
237-
onSelect={onSelect}
238-
open
239-
treeData={[
240-
{ value: '1', label: '1' },
241-
{ value: '2', label: '2' },
242-
]}
243-
/>,
244-
);
245-
246-
// Press enter without search value, should not select any node
247-
wrapper.find('input').first().simulate('keyDown', { which: KeyCode.ENTER });
248-
expect(onSelect).not.toHaveBeenCalled();
249-
250-
// Search and press enter, should select first matched node
251-
wrapper.search('1');
252-
wrapper.find('input').first().simulate('keyDown', { which: KeyCode.ENTER });
253-
expect(onSelect).toHaveBeenCalledWith('1', expect.anything());
254-
});
255-
256232
it('should not select node when no matches found', () => {
257233
const onSelect = jest.fn();
258234
const wrapper = mount(

tests/Select.spec.tsx

+38-20
Original file line numberDiff line numberDiff line change
@@ -438,13 +438,13 @@ describe('TreeSelect.basic', () => {
438438
keyUp(KeyCode.DOWN);
439439
keyDown(KeyCode.ENTER);
440440
keyUp(KeyCode.ENTER);
441-
matchValue(['parent']);
441+
matchValue(['child']);
442442

443443
keyDown(KeyCode.UP);
444444
keyUp(KeyCode.UP);
445445
keyDown(KeyCode.ENTER);
446446
keyUp(KeyCode.ENTER);
447-
matchValue(['parent', 'child']);
447+
matchValue(['child', 'parent']);
448448
});
449449

450450
it('selectable works with keyboard operations', () => {
@@ -467,12 +467,12 @@ describe('TreeSelect.basic', () => {
467467

468468
keyDown(KeyCode.DOWN);
469469
keyDown(KeyCode.ENTER);
470-
expect(onChange).toHaveBeenCalledWith(['parent'], expect.anything(), expect.anything());
471-
onChange.mockReset();
470+
expect(onChange).not.toHaveBeenCalled();
472471

473472
keyDown(KeyCode.UP);
474473
keyDown(KeyCode.ENTER);
475-
expect(onChange).not.toHaveBeenCalled();
474+
expect(onChange).toHaveBeenCalledWith(['parent'], expect.anything(), expect.anything());
475+
onChange.mockReset();
476476
});
477477

478478
it('active index matches value', () => {
@@ -535,6 +535,24 @@ describe('TreeSelect.basic', () => {
535535
keyDown(KeyCode.UP);
536536
expect(wrapper.find('.rc-tree-select-tree-treenode-active').text()).toBe('11 label');
537537
});
538+
539+
it('should active first option when dropdown is opened', () => {
540+
const treeData = [
541+
{ key: '0', value: '0', title: '0 label', disabled: true },
542+
{ key: '1', value: '1', title: '1 label' },
543+
{ key: '2', value: '2', title: '2 label' },
544+
];
545+
546+
const wrapper = mount(<TreeSelect treeData={treeData} />);
547+
548+
expect(wrapper.find('.rc-tree-select-tree-treenode-active')).toHaveLength(0);
549+
550+
wrapper.openSelect();
551+
552+
const activeNode = wrapper.find('.rc-tree-select-tree-treenode-active');
553+
expect(activeNode).toHaveLength(1);
554+
expect(activeNode.text()).toBe('0 label');
555+
});
538556
});
539557

540558
it('click in list should preventDefault', () => {
@@ -591,21 +609,21 @@ describe('TreeSelect.basic', () => {
591609
expect(container.querySelector('.rc-tree-select-selector').textContent).toBe('parent 1-0');
592610
});
593611

594-
it('should not add new tag when key enter is pressed if nothing is active', () => {
595-
const onSelect = jest.fn();
596-
597-
const wrapper = mount(
598-
<TreeSelect open treeDefaultExpandAll multiple onSelect={onSelect}>
599-
<TreeNode value="parent 1-0" title="parent 1-0">
600-
<TreeNode value="leaf1" title="my leaf" disabled />
601-
<TreeNode value="leaf2" title="your leaf" disabled />
602-
</TreeNode>
603-
</TreeSelect>,
604-
);
605-
606-
wrapper.find('input').first().simulate('keydown', { which: KeyCode.ENTER });
607-
expect(onSelect).not.toHaveBeenCalled();
608-
});
612+
// it('should not add new tag when key enter is pressed if nothing is active', () => {
613+
// const onSelect = jest.fn();
614+
615+
// const wrapper = mount(
616+
// <TreeSelect open treeDefaultExpandAll multiple onSelect={onSelect}>
617+
// <TreeNode value="parent 1-0" title="parent 1-0">
618+
// <TreeNode value="leaf1" title="my leaf" disabled />
619+
// <TreeNode value="leaf2" title="your leaf" disabled />
620+
// </TreeNode>
621+
// </TreeSelect>,
622+
// );
623+
624+
// wrapper.find('input').first().simulate('keydown', { which: KeyCode.ENTER });
625+
// expect(onSelect).not.toHaveBeenCalled();
626+
// });
609627

610628
it('should not select parent if some children is disabled', () => {
611629
const onChange = jest.fn();

tests/__snapshots__/Select.checkable.spec.tsx.snap

+16-4
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,14 @@ exports[`TreeSelect.checkable uncheck remove by selector not treeCheckStrictly 1
134134
>
135135
<div>
136136
<div>
137+
<span
138+
aria-live="assertive"
139+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
140+
>
141+
0
142+
</span>
137143
<div
138-
class="rc-tree-select-tree"
144+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
139145
role="tree"
140146
>
141147
<div>
@@ -174,7 +180,7 @@ exports[`TreeSelect.checkable uncheck remove by selector not treeCheckStrictly 1
174180
>
175181
<div
176182
aria-grabbed="false"
177-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-checkbox-checked rc-tree-select-tree-treenode-leaf-last"
183+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-checkbox-checked rc-tree-select-tree-treenode-active rc-tree-select-tree-treenode-leaf-last"
178184
draggable="false"
179185
>
180186
<span
@@ -338,8 +344,14 @@ exports[`TreeSelect.checkable uncheck remove by selector not treeCheckStrictly 2
338344
>
339345
<div>
340346
<div>
347+
<span
348+
aria-live="assertive"
349+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
350+
>
351+
0
352+
</span>
341353
<div
342-
class="rc-tree-select-tree"
354+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
343355
role="tree"
344356
>
345357
<div>
@@ -378,7 +390,7 @@ exports[`TreeSelect.checkable uncheck remove by selector not treeCheckStrictly 2
378390
>
379391
<div
380392
aria-grabbed="false"
381-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-leaf-last"
393+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-active rc-tree-select-tree-treenode-leaf-last"
382394
draggable="false"
383395
>
384396
<span

tests/__snapshots__/Select.spec.tsx.snap

+32-8
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,14 @@ exports[`TreeSelect.basic render renders TreeNode correctly 1`] = `
4141
>
4242
<div>
4343
<div>
44+
<span
45+
aria-live="assertive"
46+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
47+
>
48+
0
49+
</span>
4450
<div
45-
class="rc-tree-select-tree"
51+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
4652
role="tree"
4753
>
4854
<div>
@@ -81,7 +87,7 @@ exports[`TreeSelect.basic render renders TreeNode correctly 1`] = `
8187
>
8288
<div
8389
aria-grabbed="false"
84-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close"
90+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close rc-tree-select-tree-treenode-active"
8591
draggable="false"
8692
>
8793
<span
@@ -243,8 +249,14 @@ exports[`TreeSelect.basic render renders TreeNode correctly with falsy child 1`]
243249
>
244250
<div>
245251
<div>
252+
<span
253+
aria-live="assertive"
254+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
255+
>
256+
0
257+
</span>
246258
<div
247-
class="rc-tree-select-tree"
259+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
248260
role="tree"
249261
>
250262
<div>
@@ -283,7 +295,7 @@ exports[`TreeSelect.basic render renders TreeNode correctly with falsy child 1`]
283295
>
284296
<div
285297
aria-grabbed="false"
286-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close"
298+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close rc-tree-select-tree-treenode-active"
287299
draggable="false"
288300
>
289301
<span
@@ -594,8 +606,14 @@ exports[`TreeSelect.basic render renders treeDataSimpleMode correctly 1`] = `
594606
>
595607
<div>
596608
<div>
609+
<span
610+
aria-live="assertive"
611+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
612+
>
613+
0
614+
</span>
597615
<div
598-
class="rc-tree-select-tree"
616+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
599617
role="tree"
600618
>
601619
<div>
@@ -634,7 +652,7 @@ exports[`TreeSelect.basic render renders treeDataSimpleMode correctly 1`] = `
634652
>
635653
<div
636654
aria-grabbed="false"
637-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-leaf-last"
655+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-open rc-tree-select-tree-treenode-active rc-tree-select-tree-treenode-leaf-last"
638656
draggable="false"
639657
>
640658
<span
@@ -1156,8 +1174,14 @@ exports[`TreeSelect.basic search nodes renders search input 1`] = `
11561174
>
11571175
<div>
11581176
<div>
1177+
<span
1178+
aria-live="assertive"
1179+
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
1180+
>
1181+
a
1182+
</span>
11591183
<div
1160-
class="rc-tree-select-tree"
1184+
class="rc-tree-select-tree rc-tree-select-tree-active-focused"
11611185
role="tree"
11621186
>
11631187
<div>
@@ -1196,7 +1220,7 @@ exports[`TreeSelect.basic search nodes renders search input 1`] = `
11961220
>
11971221
<div
11981222
aria-grabbed="false"
1199-
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close"
1223+
class="rc-tree-select-tree-treenode rc-tree-select-tree-treenode-switcher-close rc-tree-select-tree-treenode-active"
12001224
draggable="false"
12011225
>
12021226
<span

0 commit comments

Comments
 (0)