Skip to content

Commit a695041

Browse files
authored
fix: Do not sync invalidate active index (#658)
* test: Test driven * fix: searchValue update should refresh scroll logic
1 parent 9b2fa1d commit a695041

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

src/OptionList.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react';
2+
import { useEffect } from 'react';
23
import KeyCode from 'rc-util/lib/KeyCode';
34
import omit from 'rc-util/lib/omit';
45
import pickAttrs from 'rc-util/lib/pickAttrs';
@@ -140,12 +141,12 @@ const OptionList: React.ForwardRefRenderFunction<
140141
};
141142

142143
// Auto active first item when list length or searchValue changed
143-
React.useEffect(() => {
144+
useEffect(() => {
144145
setActive(defaultActiveFirstOption !== false ? getEnabledActiveIndex(0) : -1);
145146
}, [memoFlattenOptions.length, searchValue]);
146147

147148
// Auto scroll to item position in single mode
148-
React.useEffect(() => {
149+
useEffect(() => {
149150
/**
150151
* React will skip `onChange` when component update.
151152
* `setActive` function will call root accessibility state update which makes re-render.
@@ -157,8 +158,11 @@ const OptionList: React.ForwardRefRenderFunction<
157158
const index = memoFlattenOptions.findIndex(
158159
({ data }) => (data as OptionData).value === value,
159160
);
160-
setActive(index);
161-
scrollIntoView(index);
161+
162+
if (index !== -1) {
163+
setActive(index);
164+
scrollIntoView(index);
165+
}
162166
}
163167
});
164168

@@ -168,7 +172,7 @@ const OptionList: React.ForwardRefRenderFunction<
168172
}
169173

170174
return () => clearTimeout(timeoutId);
171-
}, [open]);
175+
}, [open, searchValue]);
172176

173177
// ========================== Values ==========================
174178
const onSelectValue = (value: RawValueType) => {

tests/Accessibility.test.tsx

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { mount } from 'enzyme';
22
import * as React from 'react';
3+
import KeyCode from 'rc-util/lib/KeyCode';
34
import Select from '../src';
4-
import { injectRunAllTimers } from './utils/common';
5+
import { injectRunAllTimers, expectOpen } from './utils/common';
56

67
describe('Select.Accessibility', () => {
78
injectRunAllTimers(jest);
@@ -23,4 +24,49 @@ describe('Select.Accessibility', () => {
2324
}),
2425
);
2526
});
27+
28+
// https://github.com/ant-design/ant-design/issues/31850
29+
it('active index should keep', () => {
30+
const wrapper = mount(
31+
<Select
32+
showSearch
33+
options={[
34+
{
35+
label: 'Little',
36+
value: 'little',
37+
},
38+
{
39+
label: 'Bamboo',
40+
value: 'bamboo',
41+
},
42+
{
43+
label: 'Light',
44+
value: 'light',
45+
},
46+
]}
47+
/>,
48+
);
49+
50+
// First Match
51+
wrapper.find('input').simulate('change', { target: { value: 'b' } });
52+
jest.runAllTimers();
53+
54+
expectOpen(wrapper);
55+
expect(
56+
wrapper.find('.rc-select-item-option-active .rc-select-item-option-content').text(),
57+
).toEqual('Bamboo');
58+
59+
wrapper.find('input').simulate('keyDown', { which: KeyCode.ENTER });
60+
expectOpen(wrapper, false);
61+
62+
// Next Match
63+
wrapper.find('input').simulate('change', { target: { value: '' } });
64+
wrapper.find('input').simulate('change', { target: { value: 'g' } });
65+
jest.runAllTimers();
66+
67+
expectOpen(wrapper);
68+
expect(
69+
wrapper.find('.rc-select-item-option-active .rc-select-item-option-content').text(),
70+
).toEqual('Light');
71+
});
2672
});

0 commit comments

Comments
 (0)