Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/BaseSelect/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type { RefTriggerProps } from '../SelectTrigger';
import SelectTrigger from '../SelectTrigger';
import { getSeparatedContent, isValidCount } from '../utils/valueUtil';
import Polite from './Polite';
import useOpen from '../hooks/useOpen';
import useOpen, { macroTask } from '../hooks/useOpen';
import { useEvent } from '@rc-component/util';
import type { SelectInputRef } from '../SelectInput';
import SelectInput from '../SelectInput';
Expand Down Expand Up @@ -547,8 +547,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
useSelectTriggerControl(getSelectElements, mergedOpen, triggerOpen, !!mergedComponents.root);

// ========================== Focus / Blur ==========================
/** Record real focus status */
// const focusRef = React.useRef<boolean>(false);
const internalMouseDownRef = React.useRef(false);

const onInternalFocus: React.FocusEventHandler<HTMLElement> = (event) => {
setFocused(true);
Expand All @@ -565,7 +564,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)

const onRootBlur = () => {
// Delay close should check the activeElement
if (mergedOpen) {
if (mergedOpen && !internalMouseDownRef.current) {
triggerOpen(false, {
cancelFun: () => isInside(getSelectElements(), document.activeElement as HTMLElement),
});
Expand Down Expand Up @@ -605,6 +604,11 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
}

onMouseDown?.(event, ...restArgs);

internalMouseDownRef.current = true;
macroTask(() => {
internalMouseDownRef.current = false;
});
};

// ============================ Dropdown ============================
Expand Down
2 changes: 2 additions & 0 deletions tests/Combobox.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,8 @@ describe('Select.Combobox', () => {
for (let i = 0; i < 10; i += 1) {
fireEvent.mouseDown(container.querySelector('input')!);
expectOpen(container);

await delay(100);
}

fireEvent.blur(container.querySelector('input')!);
Comment on lines 500 to 507

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

await delay(100) 放在循环内部会导致测试运行时间不必要地增加(在这个例子中超过1秒)。这个 delay 的目的是为了确保在触发 blur 事件之前,由最后一次 mouseDown 事件触发的 macroTask 已经执行完毕,将 internalMouseDownRef 重置为 false

因此,这个延迟只需要在循环之后、blur 事件之前执行一次即可。另外,使用 delay(0) 通常足以等待下一个宏任务,比 delay(100) 更高效,可以避免测试中的硬编码等待时间。

建议将 delay 移出循环,以提高测试效率。

Suggested change
for (let i = 0; i < 10; i += 1) {
fireEvent.mouseDown(container.querySelector('input')!);
expectOpen(container);
await delay(100);
}
fireEvent.blur(container.querySelector('input')!);
for (let i = 0; i < 10; i += 1) {
fireEvent.mouseDown(container.querySelector('input')!);
expectOpen(container);
}
await delay(0);
fireEvent.blur(container.querySelector('input')!);

Expand Down
21 changes: 21 additions & 0 deletions tests/focus.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,25 @@ describe('Select.Focus', () => {

expect(onPopupVisibleChange).toHaveBeenCalledWith(false);
});

it('click inner that no have focusable element should not close the popup', () => {
const onPopupVisibleChange = jest.fn();

const { container } = render(
<Select
open
onPopupVisibleChange={onPopupVisibleChange}
popupRender={() => <div className="bamboo" />}
/>,
);

fireEvent.mouseDown(container.querySelector('.bamboo'));
fireEvent.blur(container.querySelector('input'));

act(() => {
jest.runAllTimers();
});

expect(onPopupVisibleChange).not.toHaveBeenCalled();
});
});
Loading