From 09a4e7b3f4e0a7bde15e2bfe7c11a69eeabc2dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com> Date: Thu, 31 Oct 2024 00:24:46 +0800 Subject: [PATCH 1/5] feat: improve focus behavior --- docs/api.md | 22 ++++++++++++++++++++++ docs/demo/focus.tsx | 28 ++++++++++++++++++++++++++++ docs/example.md | 2 ++ src/InputNumber.tsx | 23 +++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 docs/demo/focus.tsx diff --git a/docs/api.md b/docs/api.md index fb173828..b799988f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -186,3 +186,25 @@ nav: + +## inputRef + +```tsx | pure +import InputNumber, { InputNumberRef } from 'rc-input-number'; + +const inputRef = useRef(null); + +useEffect(() => { + inputRef.current.focus(); // the input will get focus + inputRef.current.blur(); // the input will lose focus + console.log(inputRef.current.input); // The origin input element +}, []); +// .... +; +``` + +| Property | Type | Description | +| -------- | --------------------------------------- | --------------------------------- | +| focus | `(options?: InputFocusOptions) => void` | The input get focus when called | +| blur | `() => void` | The input loses focus when called | +| input | `HTMLInputElement \| null` | The origin input element | diff --git a/docs/demo/focus.tsx b/docs/demo/focus.tsx new file mode 100644 index 00000000..7b114b63 --- /dev/null +++ b/docs/demo/focus.tsx @@ -0,0 +1,28 @@ +/* eslint no-console:0 */ +import InputNumber, { InputNumberRef } from 'rc-input-number'; +import React from 'react'; +import '../../assets/index.less'; + +export default () => { + const inputRef = React.useRef(null); + + return ( +
+ +
+ + + + +
+
+ ); +}; diff --git a/docs/example.md b/docs/example.md index 72af5617..8252ae2d 100644 --- a/docs/example.md +++ b/docs/example.md @@ -45,4 +45,6 @@ nav: +## focus + diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx index 1169f2a3..e6f3c2bb 100644 --- a/src/InputNumber.tsx +++ b/src/InputNumber.tsx @@ -24,6 +24,14 @@ import useFrame from './hooks/useFrame'; export type { ValueType }; export interface InputNumberRef extends HTMLInputElement { + focus: (options?: InputFocusOptions) => void; + blur: () => void; + setSelectionRange: ( + start: number, + end: number, + direction?: 'forward' | 'backward' | 'none', + ) => void; + select: () => void; nativeElement: HTMLElement; } @@ -660,6 +668,21 @@ const InputNumber = React.forwardRef((props, r React.useImperativeHandle(ref, () => proxyObject(inputFocusRef.current, { + focus, + blur: () => { + inputFocusRef.current?.blur(); + }, + setSelectionRange: ( + start: number, + end: number, + direction?: 'forward' | 'backward' | 'none', + ) => { + inputFocusRef.current?.setSelectionRange(start, end, direction); + }, + select: () => { + inputFocusRef.current?.select(); + }, + input: inputFocusRef.current, nativeElement: holderRef.current.nativeElement || inputNumberDomRef.current, }), ); From 12942842db14ce1799b971d4cf643f44aab3c44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com> Date: Thu, 31 Oct 2024 01:25:00 +0800 Subject: [PATCH 2/5] feat: add type definition --- src/InputNumber.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx index e6f3c2bb..9a3b6849 100644 --- a/src/InputNumber.tsx +++ b/src/InputNumber.tsx @@ -32,6 +32,7 @@ export interface InputNumberRef extends HTMLInputElement { direction?: 'forward' | 'backward' | 'none', ) => void; select: () => void; + input: HTMLInputElement | null; nativeElement: HTMLElement; } From 96f715599b715f83b273d3b811f2ecf5cc4fc141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com> Date: Thu, 31 Oct 2024 01:25:17 +0800 Subject: [PATCH 3/5] test: add test case --- tests/focus.test.tsx | 66 ++++++++++++++++++++++++++++++++++++++++++++ tests/input.test.tsx | 10 +++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/focus.test.tsx diff --git a/tests/focus.test.tsx b/tests/focus.test.tsx new file mode 100644 index 00000000..a71bd577 --- /dev/null +++ b/tests/focus.test.tsx @@ -0,0 +1,66 @@ +import { fireEvent, render } from '@testing-library/react'; +import InputNumber, { InputNumberRef } from 'rc-input-number'; +import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; +import React from 'react'; + +const getInputRef = () => { + const ref = React.createRef(); + render(); + return ref; +}; + +describe('InputNumber.Focus', () => { + let inputSpy: ReturnType; + let focus: ReturnType; + let setSelectionRange: ReturnType; + + beforeEach(() => { + focus = jest.fn(); + setSelectionRange = jest.fn(); + inputSpy = spyElementPrototypes(HTMLInputElement, { + focus, + setSelectionRange, + }); + }); + + afterEach(() => { + inputSpy.mockRestore(); + }); + + it('start', () => { + const input = getInputRef(); + input.current?.focus({ cursor: 'start' }); + + expect(focus).toHaveBeenCalled(); + expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 0, 0); + }); + + it('end', () => { + const input = getInputRef(); + input.current?.focus({ cursor: 'end' }); + + expect(focus).toHaveBeenCalled(); + expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 5, 5); + }); + + it('all', () => { + const input = getInputRef(); + input.current?.focus({ cursor: 'all' }); + + expect(focus).toHaveBeenCalled(); + expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 0, 5); + }); + + it('disabled should reset focus', () => { + const { container, rerender } = render(); + const input = container.querySelector('input')!; + + fireEvent.focus(input); + expect(container.querySelector('.rc-input-number-focused')).toBeTruthy(); + + rerender(); + fireEvent.blur(input); + + expect(container.querySelector('.rc-input-number-focused')).toBeFalsy(); + }); +}); diff --git a/tests/input.test.tsx b/tests/input.test.tsx index 095aa11d..4df8e6e7 100644 --- a/tests/input.test.tsx +++ b/tests/input.test.tsx @@ -224,6 +224,16 @@ describe('InputNumber.Input', () => { expect(onChange).not.toHaveBeenCalled(); }); + it('input should work', () => { + const ref = React.createRef(); + const { container } = render(); + const inputEl = container.querySelector('input')!; + const rootEl = container.querySelector('.rc-input-number')!; + + expect(ref.current?.input).toBe(inputEl); + expect(ref.current?.nativeElement).toBe(rootEl); + }); + describe('nativeElement', () => { it('basic', () => { const ref = React.createRef(); From f8c1a7b58c997b8e4244a581a761e2125ab74888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com> Date: Thu, 31 Oct 2024 17:43:57 +0800 Subject: [PATCH 4/5] refactor: remove some api --- docs/api.md | 2 -- src/InputNumber.tsx | 7 ------- tests/input.test.tsx | 10 ---------- 3 files changed, 19 deletions(-) diff --git a/docs/api.md b/docs/api.md index b799988f..9dae0301 100644 --- a/docs/api.md +++ b/docs/api.md @@ -197,7 +197,6 @@ const inputRef = useRef(null); useEffect(() => { inputRef.current.focus(); // the input will get focus inputRef.current.blur(); // the input will lose focus - console.log(inputRef.current.input); // The origin input element }, []); // .... ; @@ -207,4 +206,3 @@ useEffect(() => { | -------- | --------------------------------------- | --------------------------------- | | focus | `(options?: InputFocusOptions) => void` | The input get focus when called | | blur | `() => void` | The input loses focus when called | -| input | `HTMLInputElement \| null` | The origin input element | diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx index 9a3b6849..9796b1ad 100644 --- a/src/InputNumber.tsx +++ b/src/InputNumber.tsx @@ -26,13 +26,6 @@ export type { ValueType }; export interface InputNumberRef extends HTMLInputElement { focus: (options?: InputFocusOptions) => void; blur: () => void; - setSelectionRange: ( - start: number, - end: number, - direction?: 'forward' | 'backward' | 'none', - ) => void; - select: () => void; - input: HTMLInputElement | null; nativeElement: HTMLElement; } diff --git a/tests/input.test.tsx b/tests/input.test.tsx index 4df8e6e7..095aa11d 100644 --- a/tests/input.test.tsx +++ b/tests/input.test.tsx @@ -224,16 +224,6 @@ describe('InputNumber.Input', () => { expect(onChange).not.toHaveBeenCalled(); }); - it('input should work', () => { - const ref = React.createRef(); - const { container } = render(); - const inputEl = container.querySelector('input')!; - const rootEl = container.querySelector('.rc-input-number')!; - - expect(ref.current?.input).toBe(inputEl); - expect(ref.current?.nativeElement).toBe(rootEl); - }); - describe('nativeElement', () => { it('basic', () => { const ref = React.createRef(); From 237422b27eff640303ba96bb905956efeb8bab60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E8=B1=AA?= <1844749591@qq.com> Date: Fri, 1 Nov 2024 10:29:10 +0800 Subject: [PATCH 5/5] chore: remove useless code --- src/InputNumber.tsx | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/InputNumber.tsx b/src/InputNumber.tsx index 9796b1ad..78c04b9b 100644 --- a/src/InputNumber.tsx +++ b/src/InputNumber.tsx @@ -663,20 +663,6 @@ const InputNumber = React.forwardRef((props, r React.useImperativeHandle(ref, () => proxyObject(inputFocusRef.current, { focus, - blur: () => { - inputFocusRef.current?.blur(); - }, - setSelectionRange: ( - start: number, - end: number, - direction?: 'forward' | 'backward' | 'none', - ) => { - inputFocusRef.current?.setSelectionRange(start, end, direction); - }, - select: () => { - inputFocusRef.current?.select(); - }, - input: inputFocusRef.current, nativeElement: holderRef.current.nativeElement || inputNumberDomRef.current, }), );