Skip to content

Commit 6d84c2f

Browse files
zombieJclaude
andauthored
fix: apply rawOpen fix to multiple mode (#1202)
* fix: apply rawOpen fix to multiple mode Pass rawOpen through context and use it in MultipleContent to prevent search value from being cleared when emptyListContent blocks the dropdown from opening. Also adds test coverage for the multiple mode case. Co-Authored-By: Claude Opus 4.5 <[email protected]> * test: refactor typing test to use it.each Combine single and multiple mode tests into a parametrized test using it.each for better maintainability. Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 6f33131 commit 6d84c2f

File tree

4 files changed

+35
-25
lines changed

4 files changed

+35
-25
lines changed

src/BaseSelect/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
645645
notFoundContent,
646646
open: mergedOpen,
647647
triggerOpen: mergedOpen,
648+
rawOpen,
648649
id,
649650
showSearch,
650651
multiple,
@@ -662,6 +663,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
662663
showSearch,
663664
multiple,
664665
mergedOpen,
666+
rawOpen,
665667
showScrollBar,
666668
styles,
667669
classNames,

src/SelectInput/Content/MultipleContent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export default React.forwardRef<HTMLInputElement, SharedContentProps>(function M
3636
disabled,
3737
showSearch,
3838
triggerOpen,
39+
rawOpen,
3940
toggleOpen,
4041
autoClearSearchValue,
4142
tagRender: tagRenderFromContext,
@@ -50,8 +51,9 @@ export default React.forwardRef<HTMLInputElement, SharedContentProps>(function M
5051

5152
// ===================== Search ======================
5253
// Apply autoClearSearchValue logic: when dropdown is closed and autoClearSearchValue is not false (default true), clear search value
54+
// Use rawOpen to avoid clearing search when emptyListContent blocks open
5355
let computedSearchValue = searchValue;
54-
if (!triggerOpen && mode === 'multiple' && autoClearSearchValue !== false) {
56+
if (!rawOpen && mode === 'multiple' && autoClearSearchValue !== false) {
5557
computedSearchValue = '';
5658
}
5759

src/hooks/useBaseProps.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type { BaseSelectProps } from '../BaseSelect';
88

99
export interface BaseSelectContextProps extends BaseSelectProps {
1010
triggerOpen: boolean;
11+
rawOpen: boolean;
1112
multiple: boolean;
1213
toggleOpen: (open?: boolean) => void;
1314
lockOptions: boolean;

tests/Select.test.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,32 +1997,37 @@ describe('Select.Basic', () => {
19971997
expect(container.querySelector('.rc-select-dropdown-empty')).toBeFalsy();
19981998
});
19991999

2000-
it('should allow typing when notFoundContent is null and no options match', () => {
2001-
const onSearch = jest.fn();
2002-
const { container } = render(
2003-
<Select showSearch notFoundContent={null} onSearch={onSearch}>
2004-
<Option value="jack">Jack</Option>
2005-
<Option value="lucy">Lucy</Option>
2006-
</Select>,
2007-
);
2000+
describe('should allow typing when notFoundContent is null and no options match', () => {
2001+
it.each<{ mode: 'multiple' | undefined; label: string }>([
2002+
{ mode: undefined, label: 'single' },
2003+
{ mode: 'multiple', label: 'multiple' },
2004+
])('$label', ({ mode }) => {
2005+
const onSearch = jest.fn();
2006+
const { container } = render(
2007+
<Select mode={mode} showSearch notFoundContent={null} onSearch={onSearch}>
2008+
<Option value="jack">Jack</Option>
2009+
<Option value="lucy">Lucy</Option>
2010+
</Select>,
2011+
);
20082012

2009-
const input = container.querySelector('input');
2013+
const input = container.querySelector('input');
2014+
2015+
// Type 'j' - should match 'Jack'
2016+
fireEvent.change(input, { target: { value: 'j' } });
2017+
expect(onSearch).toHaveBeenLastCalledWith('j');
2018+
expect(input.value).toBe('j');
2019+
expect(container.querySelectorAll('.rc-select-item-option')).toHaveLength(1);
20102020

2011-
// Type 'j' - should match 'Jack'
2012-
fireEvent.change(input, { target: { value: 'j' } });
2013-
expect(onSearch).toHaveBeenLastCalledWith('j');
2014-
expect(input.value).toBe('j');
2015-
expect(container.querySelectorAll('.rc-select-item-option')).toHaveLength(1);
2016-
2017-
// Type 'x' - no match, but input should still work
2018-
fireEvent.change(input, { target: { value: 'x' } });
2019-
expect(onSearch).toHaveBeenLastCalledWith('x');
2020-
expect(input.value).toBe('x');
2021-
2022-
// Type more characters - should continue working
2023-
fireEvent.change(input, { target: { value: 'xyz' } });
2024-
expect(onSearch).toHaveBeenLastCalledWith('xyz');
2025-
expect(input.value).toBe('xyz');
2021+
// Type 'x' - no match, but input should still work
2022+
fireEvent.change(input, { target: { value: 'x' } });
2023+
expect(onSearch).toHaveBeenLastCalledWith('x');
2024+
expect(input.value).toBe('x');
2025+
2026+
// Type more characters - should continue working
2027+
fireEvent.change(input, { target: { value: 'xyz' } });
2028+
expect(onSearch).toHaveBeenLastCalledWith('xyz');
2029+
expect(input.value).toBe('xyz');
2030+
});
20262031
});
20272032

20282033
it('click outside to close select', () => {

0 commit comments

Comments
 (0)