Skip to content

fix: improve wheel step precision#733

Open
QDyanbing wants to merge 2 commits into
react-component:masterfrom
QDyanbing:fix-wheel-precision
Open

fix: improve wheel step precision#733
QDyanbing wants to merge 2 commits into
react-component:masterfrom
QDyanbing:fix-wheel-precision

Conversation

@QDyanbing

@QDyanbing QDyanbing commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Normalize wheel delta across pixel, line, and page modes.
  • Accumulate wheel delta before triggering one InputNumber step.
  • Reset accumulated delta when wheel gestures pause or reverse direction.
  • Update wheel tests for threshold and high precision wheel behavior.

Why

When changeOnWheel is enabled, each wheel event currently triggers one step. Low precision mouse wheels can emit many events for a small physical scroll, causing InputNumber values to jump too quickly.

Related to ant-design/ant-design#58328.

Test

  • npm test -- tests/wheel.test.tsx --runInBand
  • npm test -- --runInBand
  • npm run lint

Summary by CodeRabbit

  • 功能改进

    • 优化 InputNumber 的鼠标滚轮交互:引入增量累积与阈值触发,提升小幅滚轮输入的响应一致性与灵敏度。
    • 扩展滚轮模式兼容性:支持像素/行/页等 delta 模式,跨浏览器表现更统一。
    • 交互稳健性增强:在失焦或方向切换时重置滚轮状态,避免历史滚动影响后续操作。
  • 测试

    • 增补和调整滚轮相关测试,覆盖高精度累积、deltaMode 行/页模式、空增量忽略及方向切换重置等场景。

@vercel

vercel Bot commented Jun 11, 2026

Copy link
Copy Markdown

@QDyanbing is attempting to deploy a commit to the React Component Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 377817d4-c05c-4384-b3a8-1cc79ac8c18c

📥 Commits

Reviewing files that changed from the base of the PR and between 8a538a2 and b4f700c.

📒 Files selected for processing (1)
  • tests/wheel.test.tsx

Walkthrough

InputNumber 增加了 wheel 事件的增量规范化与跨事件累积机制:按 deltaMode 换算增量,使用 refs 累积高精度 delta 并在达到阈值时触发一次步进。同步更新并新增 wheel 相关测试覆盖多种 deltaMode、精度与方向切换场景。

Changes

滚轮增量累积和阈值触发

Layer / File(s) Summary
滚轮规范化和状态管理
src/InputNumber.tsx
定义 WHEEL_STEP_DISTANCE、WHEEL_DELTA_RESET_INTERVAL 等常量和 getWheelDeltaY,根据 WheelEvent.deltaMode 将 pixels/lines/pages 换算为统一增量;新增 wheelDeltaRefwheelTimestampRef 两个 ref 用于跨事件累积与时间记录。
累积触发和事件处理
src/InputNumber.tsx
重写 onInternalWheel:获取规范化增量、按时间间隔或方向变化重置累积、累积绝对值到达 WHEEL_STEP_DISTANCE 时根据正负触发 onInternalStep(up/down) 并清零累积;将 changeOnWheel effect 的监听回调改为 onInternalWheel,并在 cleanup 与 onBlur 中重置相关 refs。
测试用例更新与新增
tests/wheel.test.tsx
将已有“wheel up/down/with shift/disabled/limited”用例的 deltaY 调整为更大值以匹配累积阈值;新增测试覆盖高精度滚轮增量的多次累积触发、deltaMode:1(line)和 deltaMode:2(page)的换算、空增量忽略以及方向切换时重置累积的行为。

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • zombieJ
  • crazyair

Poem

🐰 细微的滚动轻声来,
我把增量小心收藏,
累积成势在阈值跃起,
数字倏然向前一行,
测试为此拍掌欢唱。

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确反映了主要变更内容:改进鼠标滚轮步长的精度和处理机制。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

tests/wheel.test.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@QDyanbing QDyanbing marked this pull request as ready for review June 11, 2026 03:23

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a wheel delta accumulation mechanism to the InputNumber component to support high-precision scrolling and different wheel delta modes (pixel, line, and page). It tracks the accumulated delta and triggers a step change once a threshold is reached. The review feedback suggests a valuable improvement: instead of resetting the accumulated wheel delta to zero when a step is triggered, subtracting the step distance would preserve any remaining fractional delta, leading to a smoother scrolling experience for high-precision wheels.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/InputNumber.tsx
Comment on lines +606 to +611
if (Math.abs(wheelDeltaRef.current) >= WHEEL_STEP_DISTANCE) {
// moving mouse wheel rises wheel event with deltaY < 0
// scroll value grows from top to bottom, as screen Y coordinate
onInternalStep(wheelDeltaRef.current < 0, 'wheel');
wheelDeltaRef.current = 0;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Instead of resetting wheelDeltaRef.current to 0 when a step is triggered, consider subtracting WHEEL_STEP_DISTANCE (preserving the sign). This ensures that any fractional delta beyond the threshold (e.g., from high-precision wheels or fast scrolls) is preserved for subsequent events rather than being discarded, making the scrolling experience much smoother and more precise.

Suggested change
if (Math.abs(wheelDeltaRef.current) >= WHEEL_STEP_DISTANCE) {
// moving mouse wheel rises wheel event with deltaY < 0
// scroll value grows from top to bottom, as screen Y coordinate
onInternalStep(wheelDeltaRef.current < 0, 'wheel');
wheelDeltaRef.current = 0;
}
if (Math.abs(wheelDeltaRef.current) >= WHEEL_STEP_DISTANCE) {
// moving mouse wheel rises wheel event with deltaY < 0
// scroll value grows from top to bottom, as screen Y coordinate
onInternalStep(wheelDeltaRef.current < 0, 'wheel');
wheelDeltaRef.current -= Math.sign(wheelDeltaRef.current) * WHEEL_STEP_DISTANCE;
}

@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.78%. Comparing base (45ebc94) to head (b4f700c).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #733      +/-   ##
==========================================
+ Coverage   95.31%   95.78%   +0.46%     
==========================================
  Files           6        6              
  Lines         299      332      +33     
  Branches       83       92       +9     
==========================================
+ Hits          285      318      +33     
  Misses         14       14              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/wheel.test.tsx (1)

107-115: 💤 Low value

建议补充 page mode 和边界场景的测试覆盖。

当前测试覆盖了 deltaMode: 1(line mode),但缺少以下场景:

  • deltaMode: 2(page mode)的换算验证
  • 滚轮方向变化时累积值重置的行为
  • 超过 200ms 间隔后累积值重置的行为
📝 建议新增的测试用例
it('supports page mode wheel delta', () => {
  const onChange = jest.fn();
  const { container } = render(<InputNumber onChange={onChange} changeOnWheel />);

  fireEvent.focus(container.firstChild);
  // deltaMode: 2, deltaY: -1 → -1 * 800 = -800, |-800| >= 100
  fireEvent.wheel(container.querySelector('input'), { deltaMode: 2, deltaY: -1 });

  expect(onChange).toHaveBeenCalledWith(1);
});

it('resets accumulated delta on direction change', () => {
  const onChange = jest.fn();
  const { container } = render(<InputNumber onChange={onChange} changeOnWheel />);
  const input = container.querySelector('input');

  fireEvent.focus(container.firstChild);

  // Accumulate 90 in negative direction
  for (let i = 0; i < 18; i += 1) {
    fireEvent.wheel(input, { deltaY: -5 });
  }
  expect(onChange).not.toHaveBeenCalled();

  // Change direction - should reset accumulator
  fireEvent.wheel(input, { deltaY: 5 });
  expect(onChange).not.toHaveBeenCalled();

  // Now need full 100 in positive direction
  for (let i = 0; i < 19; i += 1) {
    fireEvent.wheel(input, { deltaY: 5 });
  }
  expect(onChange).toHaveBeenCalledWith(-1);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/wheel.test.tsx` around lines 107 - 115, Add tests to cover page-mode
conversion and accumulator reset behavior for the InputNumber changeOnWheel
handling: add a test that fires a wheel event with deltaMode: 2 (page mode) and
a small deltaY (e.g., -1) to assert the value change after page-to-pixel scaling
is applied (reference: InputNumber, changeOnWheel, fireEvent.wheel,
deltaMode/deltaY); add a test that accumulates wheel deltas in one direction
then fires a wheel in the opposite direction to assert the accumulator resets on
direction change (reference: accumulated delta logic used by changeOnWheel and
the input element); and add a test that waits longer than 200ms between wheel
events to assert the accumulator resets after the timeout (reference: the 200ms
accumulator timeout in the wheel handling). Ensure each test focuses on the
onChange calls and uses container.querySelector('input') and fireEvent.wheel to
simulate events.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/wheel.test.tsx`:
- Around line 107-115: Add tests to cover page-mode conversion and accumulator
reset behavior for the InputNumber changeOnWheel handling: add a test that fires
a wheel event with deltaMode: 2 (page mode) and a small deltaY (e.g., -1) to
assert the value change after page-to-pixel scaling is applied (reference:
InputNumber, changeOnWheel, fireEvent.wheel, deltaMode/deltaY); add a test that
accumulates wheel deltas in one direction then fires a wheel in the opposite
direction to assert the accumulator resets on direction change (reference:
accumulated delta logic used by changeOnWheel and the input element); and add a
test that waits longer than 200ms between wheel events to assert the accumulator
resets after the timeout (reference: the 200ms accumulator timeout in the wheel
handling). Ensure each test focuses on the onChange calls and uses
container.querySelector('input') and fireEvent.wheel to simulate events.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d51d730-665f-4d3f-85e5-6cc4fb7c80ea

📥 Commits

Reviewing files that changed from the base of the PR and between 45ebc94 and 8a538a2.

📒 Files selected for processing (2)
  • src/InputNumber.tsx
  • tests/wheel.test.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant