diff --git a/README.md b/README.md
index ac0d874e..b8085838 100644
--- a/README.md
+++ b/README.md
@@ -238,6 +238,12 @@ online example: https://input-number.vercel.app/
Specifies the inputmode of input
+
+ wheel
+ Boolean
+ true
+ Allows changing value with mouse wheel
+
@@ -246,6 +252,10 @@ online example: https://input-number.vercel.app/
* With the Shift key (Shift+⬆ , Shift+⬇ ), the input value will be changed by `10 * step`
* With the Ctrl or ⌘ key (Ctrl+⬆ or ⌘+⬆ or Ctrl+⬇ or ⌘+⬇ ), the input value will be changed by `0.1 * step`
+## Mouse Wheel
+* When you scroll up or down, the input value will be increased or decreased by `step`
+* Scrolling with the Shift key, the input value will be changed by `10 * step`
+
## Test Case
```
diff --git a/docs/demo/simple.tsx b/docs/demo/simple.tsx
index 1a8da31c..dbfa3762 100644
--- a/docs/demo/simple.tsx
+++ b/docs/demo/simple.tsx
@@ -7,6 +7,7 @@ export default () => {
const [disabled, setDisabled] = React.useState(false);
const [readOnly, setReadOnly] = React.useState(false);
const [keyboard, setKeyboard] = React.useState(true);
+ const [wheel, setWheel] = React.useState(true);
const [stringMode, setStringMode] = React.useState(false);
const [value, setValue] = React.useState(93);
@@ -28,6 +29,7 @@ export default () => {
readOnly={readOnly}
disabled={disabled}
keyboard={keyboard}
+ wheel={wheel}
stringMode={stringMode}
/>
@@ -43,6 +45,9 @@ export default () => {
setStringMode(!stringMode)}>
toggle stringMode ({String(stringMode)})
+ setWheel(!wheel)}>
+ toggle wheel ({String(wheel)})
+
diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx
index 205096ee..4a64d68c 100644
--- a/src/InputNumber.tsx
+++ b/src/InputNumber.tsx
@@ -83,6 +83,7 @@ export interface InputNumberProps
upHandler?: React.ReactNode;
downHandler?: React.ReactNode;
keyboard?: boolean;
+ wheel?: boolean;
/** Parse display value to validate number */
parser?: (displayValue: string | undefined) => T;
@@ -127,6 +128,7 @@ const InternalInputNumber = React.forwardRef(
upHandler,
downHandler,
keyboard,
+ wheel,
controls = true,
classNames,
@@ -517,6 +519,26 @@ const InternalInputNumber = React.forwardRef(
shiftKeyRef.current = false;
};
+ React.useEffect(() => {
+ const onWheel = (event) => {
+ if (wheel === false) {
+ return;
+ };
+ // moving mouse wheel rises wheel event with deltaY < 0
+ // scroll value grows from top to bottom, as screen Y coordinate
+ onInternalStep(event.deltaY < 0);
+ event.preventDefault();
+ };
+ const input = inputRef.current;
+ if (input) {
+ // React onWheel is passive and we can't preventDefault() in it.
+ // That's why we should subscribe with DOM listener
+ // https://stackoverflow.com/questions/63663025/react-onwheel-handler-cant-preventdefault-because-its-a-passive-event-listenev
+ input.addEventListener('wheel', onWheel);
+ return () => input.removeEventListener('wheel', onWheel);
+ };
+ }, [onInternalStep]);
+
// >>> Focus & Blur
const onBlur = () => {
if (changeOnBlur) {
diff --git a/tests/wheel.test.tsx b/tests/wheel.test.tsx
new file mode 100644
index 00000000..8356129c
--- /dev/null
+++ b/tests/wheel.test.tsx
@@ -0,0 +1,71 @@
+import KeyCode from 'rc-util/lib/KeyCode';
+import InputNumber from '../src';
+import { fireEvent, render } from './util/wrapper';
+
+describe('InputNumber.Wheel', () => {
+ it('wheel up', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+ fireEvent.wheel(container.querySelector('input'), {deltaY: -1});
+ expect(onChange).toHaveBeenCalledWith(1);
+ });
+
+ it('wheel up with pressing shift key', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+ fireEvent.keyDown(container.querySelector('input'), {
+ which: KeyCode.SHIFT,
+ key: 'Shift',
+ keyCode: KeyCode.SHIFT,
+ shiftKey: true,
+ });
+ fireEvent.wheel(container.querySelector('input'), {deltaY: -1});
+ expect(onChange).toHaveBeenCalledWith(1.3);
+ });
+
+ it('wheel down', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+ fireEvent.wheel(container.querySelector('input'), {deltaY: 1});
+ expect(onChange).toHaveBeenCalledWith(-1);
+ });
+
+ it('wheel down with pressing shift key', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+ fireEvent.keyDown(container.querySelector('input'), {
+ which: KeyCode.SHIFT,
+ key: 'Shift',
+ keyCode: KeyCode.SHIFT,
+ shiftKey: true,
+ });
+ fireEvent.wheel(container.querySelector('input'), {deltaY: 1});
+ expect(onChange).toHaveBeenCalledWith(1.1);
+ });
+
+ it('disabled wheel', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+
+ fireEvent.wheel(container.querySelector('input'), {deltaY: -1});
+ expect(onChange).not.toHaveBeenCalled();
+
+ fireEvent.wheel(container.querySelector('input'), {deltaY: 1});
+ expect(onChange).not.toHaveBeenCalled();
+ });
+
+ it('wheel is limited to range', () => {
+ const onChange = jest.fn();
+ const { container } = render( );
+ fireEvent.keyDown(container.querySelector('input'), {
+ which: KeyCode.SHIFT,
+ key: 'Shift',
+ keyCode: KeyCode.SHIFT,
+ shiftKey: true,
+ });
+ fireEvent.wheel(container.querySelector('input'), {deltaY: -1});
+ expect(onChange).toHaveBeenCalledWith(3);
+ fireEvent.wheel(container.querySelector('input'), {deltaY: 1});
+ expect(onChange).toHaveBeenCalledWith(-3);
+ });
+});