From e5f064f328036dfcdd7fc1b3c9e6b886963f86eb Mon Sep 17 00:00:00 2001 From: greymoth-jp <246701683+greymoth-jp@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:48:29 +0000 Subject: [PATCH] fix: avoid selecting active option when Enter confirms IME composition --- src/BaseSelect/index.tsx | 6 ++++- tests/Composition.test.tsx | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 tests/Composition.test.tsx diff --git a/src/BaseSelect/index.tsx b/src/BaseSelect/index.tsx index d856f0e74..5b2778a4e 100644 --- a/src/BaseSelect/index.tsx +++ b/src/BaseSelect/index.tsx @@ -490,6 +490,10 @@ const BaseSelect = React.forwardRef((props, ref) const isEnterKey = key === 'Enter'; + // The Enter key that confirms an IME composition should not select the active + // option, the same way the Selector skips the tags-mode submit while composing. + const isComposingEnter = isEnterKey && event.nativeEvent.isComposing; + if (isEnterKey) { // Do not submit form when type in the input if (mode !== 'combobox') { @@ -533,7 +537,7 @@ const BaseSelect = React.forwardRef((props, ref) } } - if (mergedOpen && (!isEnterKey || !keyLockRef.current)) { + if (mergedOpen && (!isEnterKey || !keyLockRef.current) && !isComposingEnter) { // Lock the Enter key after it is pressed to avoid repeated triggering of the onChange event. if (isEnterKey) { keyLockRef.current = true; diff --git a/tests/Composition.test.tsx b/tests/Composition.test.tsx new file mode 100644 index 000000000..2f9cf87bd --- /dev/null +++ b/tests/Composition.test.tsx @@ -0,0 +1,50 @@ +import { createEvent, fireEvent, render } from '@testing-library/react'; +import KeyCode from 'rc-util/lib/KeyCode'; +import { act } from 'react'; +import Select, { Option } from '../src'; +import { keyDown } from './utils/common'; + +// The keydown that confirms an IME composition still reports `which === ENTER` +// on some browsers (e.g. Safari) while `isComposing` is true. +function imeEnterKeyDown(element: HTMLElement) { + const event = createEvent.keyDown(element, { keyCode: KeyCode.ENTER }); + Object.defineProperties(event, { + which: { get: () => KeyCode.ENTER }, + isComposing: { get: () => true }, + }); + act(() => { + fireEvent(element, event); + }); +} + +describe('Select.Composition', () => { + it('does not select the active option when Enter only confirms the IME composition', () => { + const onChange = jest.fn(); + const onSelect = jest.fn(); + const { container } = render( + , + ); + + imeEnterKeyDown(container.querySelector('input')); + + expect(onChange).not.toHaveBeenCalled(); + expect(onSelect).not.toHaveBeenCalled(); + }); + + it('still selects the active option on a normal Enter', () => { + const onChange = jest.fn(); + const { container } = render( + , + ); + + keyDown(container.querySelector('input'), KeyCode.ENTER); + + expect(onChange).toHaveBeenCalledWith('1', expect.anything()); + }); +});