Skip to content

Commit afe99b4

Browse files
authored
Merge branch 'react-component:master' into master
2 parents fecd638 + df0c51c commit afe99b4

File tree

6 files changed

+120
-1
lines changed

6 files changed

+120
-1
lines changed

docs/api.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,23 @@ nav:
186186
</tr>
187187
</tbody>
188188
</table>
189+
190+
## inputRef
191+
192+
```tsx | pure
193+
import InputNumber, { InputNumberRef } from 'rc-input-number';
194+
195+
const inputRef = useRef<InputNumberRef>(null);
196+
197+
useEffect(() => {
198+
inputRef.current.focus(); // the input will get focus
199+
inputRef.current.blur(); // the input will lose focus
200+
}, []);
201+
// ....
202+
<InputNumber ref={inputRef} />;
203+
```
204+
205+
| Property | Type | Description |
206+
| -------- | --------------------------------------- | --------------------------------- |
207+
| focus | `(options?: InputFocusOptions) => void` | The input get focus when called |
208+
| blur | `() => void` | The input loses focus when called |

docs/demo/focus.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/* eslint no-console:0 */
2+
import InputNumber, { InputNumberRef } from 'rc-input-number';
3+
import React from 'react';
4+
import '../../assets/index.less';
5+
6+
export default () => {
7+
const inputRef = React.useRef<InputNumberRef>(null);
8+
9+
return (
10+
<div style={{ margin: 10 }}>
11+
<InputNumber aria-label="focus example" value={10} style={{ width: 100 }} ref={inputRef} />
12+
<div style={{ marginTop: 10 }}>
13+
<button type="button" onClick={() => inputRef.current?.focus({ cursor: 'start' })}>
14+
focus at start
15+
</button>
16+
<button type="button" onClick={() => inputRef.current?.focus({ cursor: 'end' })}>
17+
focus at end
18+
</button>
19+
<button type="button" onClick={() => inputRef.current?.focus({ cursor: 'all' })}>
20+
focus to select all
21+
</button>
22+
<button type="button" onClick={() => inputRef.current?.focus({ preventScroll: true })}>
23+
focus prevent scroll
24+
</button>
25+
</div>
26+
</div>
27+
);
28+
};

docs/example.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,6 @@ nav:
4545

4646
<code src="./demo/wheel.tsx"></code>
4747

48+
## focus
4849

50+
<code src="./demo/focus.tsx"></code>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rc-input-number",
3-
"version": "9.2.0",
3+
"version": "9.3.0",
44
"description": "React input-number component",
55
"keywords": [
66
"react",

src/InputNumber.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import useFrame from './hooks/useFrame';
2424
export type { ValueType };
2525

2626
export interface InputNumberRef extends HTMLInputElement {
27+
focus: (options?: InputFocusOptions) => void;
28+
blur: () => void;
2729
nativeElement: HTMLElement;
2830
}
2931

@@ -675,6 +677,7 @@ const InputNumber = React.forwardRef<InputNumberRef, InputNumberProps>((props, r
675677

676678
React.useImperativeHandle(ref, () =>
677679
proxyObject(inputFocusRef.current, {
680+
focus,
678681
nativeElement: holderRef.current.nativeElement || inputNumberDomRef.current,
679682
}),
680683
);

tests/focus.test.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { fireEvent, render } from '@testing-library/react';
2+
import InputNumber, { InputNumberRef } from 'rc-input-number';
3+
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
4+
import React from 'react';
5+
6+
const getInputRef = () => {
7+
const ref = React.createRef<InputNumberRef>();
8+
render(<InputNumber ref={ref} defaultValue={12345} />);
9+
return ref;
10+
};
11+
12+
describe('InputNumber.Focus', () => {
13+
let inputSpy: ReturnType<typeof spyElementPrototypes>;
14+
let focus: ReturnType<typeof jest.fn>;
15+
let setSelectionRange: ReturnType<typeof jest.fn>;
16+
17+
beforeEach(() => {
18+
focus = jest.fn();
19+
setSelectionRange = jest.fn();
20+
inputSpy = spyElementPrototypes(HTMLInputElement, {
21+
focus,
22+
setSelectionRange,
23+
});
24+
});
25+
26+
afterEach(() => {
27+
inputSpy.mockRestore();
28+
});
29+
30+
it('start', () => {
31+
const input = getInputRef();
32+
input.current?.focus({ cursor: 'start' });
33+
34+
expect(focus).toHaveBeenCalled();
35+
expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 0, 0);
36+
});
37+
38+
it('end', () => {
39+
const input = getInputRef();
40+
input.current?.focus({ cursor: 'end' });
41+
42+
expect(focus).toHaveBeenCalled();
43+
expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 5, 5);
44+
});
45+
46+
it('all', () => {
47+
const input = getInputRef();
48+
input.current?.focus({ cursor: 'all' });
49+
50+
expect(focus).toHaveBeenCalled();
51+
expect(setSelectionRange).toHaveBeenCalledWith(expect.anything(), 0, 5);
52+
});
53+
54+
it('disabled should reset focus', () => {
55+
const { container, rerender } = render(<InputNumber prefixCls="rc-input-number" />);
56+
const input = container.querySelector('input')!;
57+
58+
fireEvent.focus(input);
59+
expect(container.querySelector('.rc-input-number-focused')).toBeTruthy();
60+
61+
rerender(<InputNumber prefixCls="rc-input-number" disabled />);
62+
fireEvent.blur(input);
63+
64+
expect(container.querySelector('.rc-input-number-focused')).toBeFalsy();
65+
});
66+
});

0 commit comments

Comments
 (0)