Skip to content
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
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

Copy link
Member

Choose a reason for hiding this comment

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

这么诡异?
CompositionEnd 后值为对的,但是后续又跟了一个 Input 输入了 1。再触发一次 Input 填充了原来的内容。
这个我有点看不懂,这个 1 是输入法自己打的?

Copy link
Author

Choose a reason for hiding this comment

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

@zombieJ 是的,就是我一开始说的很奇怪的原因:

原因: 在onCompositionEnd 之后 还会有一次 onChange事件被触发。

Copy link
Member

Choose a reason for hiding this comment

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

如果是这样子的话那岂不无法感知是有意输入的还是输入法 patch 出来的?CompositionEnd 到 Blur 之间的 Input 事件还有什么可以判断是非故意产生的字符吗?


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