From b18ad091407991227b4f827866a6abb3712d46ee Mon Sep 17 00:00:00 2001 From: Mikhail Petrov Date: Sat, 28 Oct 2023 11:15:52 +0200 Subject: [PATCH] feat: support mouse wheel --- README.md | 10 +++++++ src/InputNumber.tsx | 13 ++++++++ tests/wheel.test.tsx | 71 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 tests/wheel.test.tsx 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/src/InputNumber.tsx b/src/InputNumber.tsx index 205096ee..f280caba 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,16 @@ const InternalInputNumber = React.forwardRef( shiftKeyRef.current = false; }; + 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(); + }; + // >>> Focus & Blur const onBlur = () => { if (changeOnBlur) { @@ -575,6 +587,7 @@ const InternalInputNumber = React.forwardRef( onBlur={onBlur} onKeyDown={onKeyDown} onKeyUp={onKeyUp} + onWheel={onWheel} onCompositionStart={onCompositionStart} onCompositionEnd={onCompositionEnd} onBeforeInput={onBeforeInput} 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); + }); +});