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

@Joelei Joelei Apr 16, 2025

Choose a reason for hiding this comment

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

@zombieJ 是的,上排普通的数字键没有问题,两边的事件类型好像不一样。

Copy link
Member

Choose a reason for hiding this comment

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

thx,我再试试。

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 这里是我打开系统看到的设置
image

然后在输入法右下角这里的设置里面,只有选择“半角字母数字”的时候没有问题。上面这四个选项都能复现bug。
image

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, 请问一下你那边可以复现出来吗?


// ============================ 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