Skip to content

fix: number is duplicate when input number by keyboard's numeric keypad in Chrome #709

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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: 12 additions & 0 deletions src/InputNumber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ const InternalInputNumber = React.forwardRef(
const userTypingRef = React.useRef(false);
const compositionRef = React.useRef(false);
const shiftKeyRef = React.useRef(false);
const imeCompositionRef = React.useRef(false);
Copy link
Member

Choose a reason for hiding this comment

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

单独靠 compositionRef 解决不了这个?

Copy link
Member

Choose a reason for hiding this comment

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

compositionRef 感觉就是用来做类似处理的,是不是改 compositionRef 的逻辑就可以了?避免新增这个 imeCompositionRef 吧?

Copy link
Author

@Joelei Joelei Apr 9, 2025

Choose a reason for hiding this comment

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

@yoyo837 compositionRef 不够的。

chrome环境下,日文输入法,小键盘连续键入数字 1234, 不按Enter键,点击页面其他地方。输入框内的数字变成了 $ 11,234。

这个问题的主要原因就是在onCompositionEnd 之后 还有一次input的 onChange 事件被触发,这个时候compositionRef.current的值已经为false了。

Copy link
Member

Choose a reason for hiding this comment

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

这个事件顺序是符合预期的:

onCompositionStart -> onCompositionEnd -> onBlur

退出后触发一次收集值也是符合预期的行为,能录个屏看看不?我想了解一下这个输入法的行为是什么样子的。

Copy link
Author

@Joelei Joelei Apr 10, 2025

Choose a reason for hiding this comment

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

@zombieJ 可以的。输入的时候用的是小键盘,NumLock开启。

2025-04-10.11-49-21.mp4

Copy link
Author

Choose a reason for hiding this comment

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

@zombieJ hello, 请问一下你那边可以复现出来吗?

Copy link
Member

Choose a reason for hiding this comment

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

我这边输入如通过是切的数字直出就是直接有效,如果是其他的类型就是变成全角数字,然后点击外侧就直接清空。复现不出来这个效果。

Copy link
Author

Choose a reason for hiding this comment

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

@zombieJ hello, 你的系统版本是多少?方便录一个视频吗?

Copy link
Member

Choose a reason for hiding this comment

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

@Joelei 我是 win10系统,不过每次回去都忘记录屏这事儿。抱歉……
你这边能把完整的事件和对应得到的值列一下不。我 test case 里模拟一下。(composition change blur 这些)

Copy link
Author

Choose a reason for hiding this comment

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

@zombieJ 啊,抱歉忘了及时回复了。这是我打印出来的所有log:
image


// ============================ Value =============================
// Real value control
Expand Down Expand Up @@ -428,6 +429,9 @@ const InternalInputNumber = React.forwardRef(

// >>> Input
const onInternalInput: React.ChangeEventHandler<HTMLInputElement> = (e) => {
if (imeCompositionRef.current && !compositionRef.current) {
return;
}
collectInputValue(e.target.value);
};

Expand Down Expand Up @@ -498,6 +502,12 @@ const InternalInputNumber = React.forwardRef(

shiftKeyRef.current = shiftKey;

if (event.key === 'Process' || compositionRef.current) {
imeCompositionRef.current = true;
} else {
imeCompositionRef.current = false;
}

if (key === 'Enter') {
if (!compositionRef.current) {
userTypingRef.current = false;
Expand Down Expand Up @@ -543,6 +553,8 @@ const InternalInputNumber = React.forwardRef(

// >>> Focus & Blur
const onBlur = () => {
imeCompositionRef.current = false;

if (changeOnBlur) {
flushInputValue(false);
}
Expand Down
66 changes: 66 additions & 0 deletions tests/formatter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,72 @@ describe('InputNumber.Formatter', () => {
expect(onChange).toHaveBeenCalledWith(100);
});

it('formatter on IME numeric keypad input', () => {
const { container } = render(
<InputNumber formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} />
);
const input = container.querySelector('input');
fireEvent.focus(input);
fireEvent.compositionStart(input);
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Numpad1',
keyCode: 229,
composed: true,
});
fireEvent.change(input, { target: { value: '1' } });
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Numpad2',
keyCode: 229,
composed: true,
});
fireEvent.change(input, { target: { value: '12' } });
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Numpad3',
keyCode: 229,
composed: true,
});
fireEvent.change(input, { target: { value: '123' } });
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Numpad4',
keyCode: 229,
composed: true,
});
fireEvent.change(input, { target: { value: '1234' } });
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Enter',
keyCode: 229,
composed: true,
});
fireEvent.compositionEnd(input);
fireEvent.blur(input);
expect(input.value).toEqual('1,234');

fireEvent.focus(input);
fireEvent.compositionStart(input);
fireEvent.keyDown(input, {
which: 229,
key: 'Process',
code: 'Numpad5',
keyCode: 229,
composed: true,
});
fireEvent.change(input, { target: { value: '12345' } });
fireEvent.compositionEnd(input);
fireEvent.change(input, { target: { value: '1234' } });
fireEvent.blur(input);
expect(input.value).toEqual('12,345');
});

it('formatter and parser', () => {
const onChange = jest.fn();
const { container } = render(
Expand Down
Loading