Skip to content

Commit 032a5e9

Browse files
authored
Merge branch 'react-component:master' into master
2 parents 0c116c6 + de38d1a commit 032a5e9

8 files changed

Lines changed: 118 additions & 79 deletions

File tree

README.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,31 @@
22

33
Input number control.
44

5-
[![NPM version][npm-image]][npm-url] [![dumi](https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square)](https://github.com/umijs/dumi) [![build status][github-actions-image]][github-actions-url] [![Test coverage][coveralls-image]][coveralls-url] [![Dependencies][david-image]][david-url] [![DevDependencies][david-dev-image]][david-dev-url] [![npm download][download-image]][download-url] [![bundle size][bundlephobia-image]][bundlephobia-url]
5+
[![NPM version][npm-image]][npm-url]
6+
[![npm download][download-image]][download-url]
7+
[![build status][github-actions-image]][github-actions-url]
8+
[![Codecov][codecov-image]][codecov-url]
9+
[![bundle size][bundlephobia-image]][bundlephobia-url]
10+
[![dumi][dumi-image]][dumi-url]
611

712
[npm-image]: http://img.shields.io/npm/v/rc-input-number.svg?style=flat-square
813
[npm-url]: http://npmjs.org/package/rc-input-number
14+
[travis-image]: https://img.shields.io/travis/react-component/input-number/master?style=flat-square
15+
[travis-url]: https://travis-ci.com/react-component/input-number
916
[github-actions-image]: https://github.com/react-component/input-number/workflows/CI/badge.svg
1017
[github-actions-url]: https://github.com/react-component/input-number/actions
11-
[circleci-image]: https://img.shields.io/circleci/react-component/input-number/master?style=flat-square
12-
[circleci-url]: https://circleci.com/gh/react-component/input-number
13-
[coveralls-image]: https://img.shields.io/coveralls/react-component/input-number.svg?style=flat-square
14-
[coveralls-url]: https://coveralls.io/r/react-component/input-number?branch=master
18+
[codecov-image]: https://img.shields.io/codecov/c/github/react-component/input-number/master.svg?style=flat-square
19+
[codecov-url]: https://app.codecov.io/gh/react-component/input-number
1520
[david-url]: https://david-dm.org/react-component/input-number
1621
[david-image]: https://david-dm.org/react-component/input-number/status.svg?style=flat-square
1722
[david-dev-url]: https://david-dm.org/react-component/input-number?type=dev
1823
[david-dev-image]: https://david-dm.org/react-component/input-number/dev-status.svg?style=flat-square
1924
[download-image]: https://img.shields.io/npm/dm/rc-input-number.svg?style=flat-square
2025
[download-url]: https://npmjs.org/package/rc-input-number
21-
[bundlephobia-url]: https://bundlephobia.com/result?p=rc-input-number
26+
[bundlephobia-url]: https://bundlephobia.com/package/rc-input-number
2227
[bundlephobia-image]: https://badgen.net/bundlephobia/minzip/rc-input-number
28+
[dumi-url]: https://github.com/umijs/dumi
29+
[dumi-image]: https://img.shields.io/badge/docs%20by-dumi-blue?style=flat-square
2330

2431
## Screenshots
2532

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949
"@babel/runtime": "^7.10.1",
5050
"@rc-component/mini-decimal": "^1.0.1",
5151
"classnames": "^2.2.5",
52-
"rc-input": "~1.4.0",
53-
"rc-util": "^5.28.0"
52+
"rc-input": "~1.5.0",
53+
"rc-util": "^5.40.1"
5454
},
5555
"devDependencies": {
5656
"@rc-component/father-plugin": "^1.0.1",

src/InputNumber.tsx

Lines changed: 78 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,24 @@ import getMiniDecimal, {
99
import clsx from 'classnames';
1010
import { BaseInput } from 'rc-input';
1111
import { useLayoutUpdateEffect } from 'rc-util/lib/hooks/useLayoutEffect';
12+
import proxyObject from 'rc-util/lib/proxyObject';
1213
import { composeRef } from 'rc-util/lib/ref';
1314
import * as React from 'react';
1415
import useCursor from './hooks/useCursor';
1516
import StepHandler from './StepHandler';
1617
import { getDecupleSteps } from './utils/numberUtil';
1718

19+
import type { HolderRef } from 'rc-input/lib/BaseInput';
20+
import { BaseInputProps } from 'rc-input/lib/interface';
1821
import { InputFocusOptions, triggerFocus } from 'rc-input/lib/utils/commonUtils';
1922
import useFrame from './hooks/useFrame';
20-
import { BaseInputProps } from 'rc-input/lib/interface';
2123

2224
export type { ValueType };
2325

26+
export interface InputNumberRef extends HTMLInputElement {
27+
nativeElement: HTMLElement;
28+
}
29+
2430
/**
2531
* We support `stringMode` which need handle correct type when user call in onChange
2632
* format max or min value
@@ -105,12 +111,14 @@ export interface InputNumberProps<T extends ValueType = ValueType>
105111
changeOnBlur?: boolean;
106112
}
107113

108-
type InternalInputNumberProps = Omit<InputNumberProps, 'prefix' | 'suffix'>;
114+
type InternalInputNumberProps = Omit<InputNumberProps, 'prefix' | 'suffix'> & {
115+
domRef: React.Ref<HTMLDivElement>;
116+
};
109117

110118
const InternalInputNumber = React.forwardRef(
111119
(props: InternalInputNumberProps, ref: React.Ref<HTMLInputElement>) => {
112120
const {
113-
prefixCls = 'rc-input-number',
121+
prefixCls,
114122
className,
115123
style,
116124
min,
@@ -142,6 +150,8 @@ const InternalInputNumber = React.forwardRef(
142150

143151
changeOnBlur = true,
144152

153+
domRef,
154+
145155
...inputProps
146156
} = props;
147157

@@ -478,7 +488,7 @@ const InternalInputNumber = React.forwardRef(
478488
*/
479489
const flushInputValue = (userTyping: boolean) => {
480490
const parsedValue = getMiniDecimal(mergedParser(inputValue));
481-
let formatValue: DecimalClass = parsedValue;
491+
let formatValue: DecimalClass;
482492

483493
if (!parsedValue.isNaN()) {
484494
// Only validate value or empty value can be re-fill to inputValue
@@ -595,6 +605,7 @@ const InternalInputNumber = React.forwardRef(
595605
// ============================ Render ============================
596606
return (
597607
<div
608+
ref={domRef}
598609
className={clsx(prefixCls, className, {
599610
[`${prefixCls}-focused`]: focus,
600611
[`${prefixCls}-disabled`]: disabled,
@@ -645,66 +656,76 @@ const InternalInputNumber = React.forwardRef(
645656
},
646657
);
647658

648-
const InputNumber = React.forwardRef(
649-
(props: InputNumberProps, ref: React.Ref<HTMLInputElement>) => {
650-
const {
651-
disabled,
652-
style,
653-
prefixCls,
654-
value,
655-
prefix,
656-
suffix,
657-
addonBefore,
658-
addonAfter,
659-
className,
660-
classNames,
661-
...rest
662-
} = props;
663-
664-
const inputFocusRef = React.useRef<HTMLInputElement>(null);
665-
666-
const focus = (option?: InputFocusOptions) => {
667-
if (inputFocusRef.current) {
668-
triggerFocus(inputFocusRef.current, option);
669-
}
670-
};
659+
const InputNumber = React.forwardRef<InputNumberRef, InputNumberProps>((props, ref) => {
660+
const {
661+
disabled,
662+
style,
663+
prefixCls = 'rc-input-number',
664+
value,
665+
prefix,
666+
suffix,
667+
addonBefore,
668+
addonAfter,
669+
className,
670+
classNames,
671+
...rest
672+
} = props;
673+
674+
const holderRef = React.useRef<HolderRef>(null);
675+
const inputNumberDomRef = React.useRef<HTMLDivElement>(null);
676+
const inputFocusRef = React.useRef<HTMLInputElement>(null);
677+
678+
const focus = (option?: InputFocusOptions) => {
679+
if (inputFocusRef.current) {
680+
triggerFocus(inputFocusRef.current, option);
681+
}
682+
};
671683

672-
return (
673-
<BaseInput
674-
className={className}
675-
triggerFocus={focus}
684+
React.useImperativeHandle(ref, () =>
685+
proxyObject(inputFocusRef.current, {
686+
nativeElement: holderRef.current.nativeElement || inputNumberDomRef.current,
687+
}),
688+
);
689+
690+
return (
691+
<BaseInput
692+
className={className}
693+
triggerFocus={focus}
694+
prefixCls={prefixCls}
695+
value={value}
696+
disabled={disabled}
697+
style={style}
698+
prefix={prefix}
699+
suffix={suffix}
700+
addonAfter={addonAfter}
701+
addonBefore={addonBefore}
702+
classNames={classNames}
703+
components={{
704+
affixWrapper: 'div',
705+
groupWrapper: 'div',
706+
wrapper: 'div',
707+
groupAddon: 'div',
708+
}}
709+
ref={holderRef}
710+
>
711+
<InternalInputNumber
676712
prefixCls={prefixCls}
677-
value={value}
678713
disabled={disabled}
679-
style={style}
680-
prefix={prefix}
681-
suffix={suffix}
682-
addonAfter={addonAfter}
683-
addonBefore={addonBefore}
684-
classNames={classNames}
685-
components={{
686-
affixWrapper: 'div',
687-
groupWrapper: 'div',
688-
wrapper: 'div',
689-
groupAddon: 'div',
690-
}}
691-
>
692-
<InternalInputNumber
693-
prefixCls={prefixCls}
694-
disabled={disabled}
695-
ref={composeRef(inputFocusRef, ref)}
696-
className={classNames?.input}
697-
{...rest}
698-
/>
699-
</BaseInput>
700-
);
701-
},
702-
) as (<T extends ValueType = ValueType>(
714+
ref={inputFocusRef}
715+
domRef={inputNumberDomRef}
716+
className={classNames?.input}
717+
{...rest}
718+
/>
719+
</BaseInput>
720+
);
721+
}) as (<T extends ValueType = ValueType>(
703722
props: React.PropsWithChildren<InputNumberProps<T>> & {
704723
ref?: React.Ref<HTMLInputElement>;
705724
},
706725
) => React.ReactElement) & { displayName?: string };
707726

708-
InputNumber.displayName = 'InputNumber';
727+
if (process.env.NODE_ENV !== 'production') {
728+
InputNumber.displayName = 'InputNumber';
729+
}
709730

710731
export default InputNumber;

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { InputNumberProps, ValueType } from './InputNumber';
1+
import type { InputNumberProps, ValueType, InputNumberRef } from './InputNumber';
22
import InputNumber from './InputNumber';
33

4-
export type { InputNumberProps, ValueType };
4+
export type { InputNumberProps, ValueType, InputNumberRef };
55

66
export default InputNumber;

tests/github.test.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import KeyCode from 'rc-util/lib/KeyCode';
22
import React from 'react';
3-
import { act } from 'react-dom/test-utils';
43
import InputNumber from '../src';
5-
import { fireEvent, render, screen, waitFor } from './util/wrapper';
4+
import { act, fireEvent, render, screen, waitFor } from './util/wrapper';
65

76
// Github issues
87
describe('InputNumber.Github', () => {

tests/input.test.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import KeyCode from 'rc-util/lib/KeyCode';
22
import React from 'react';
3-
import InputNumber, { InputNumberProps } from '../src';
3+
import InputNumber, { InputNumberProps, InputNumberRef } from '../src';
44
import { fireEvent, render } from './util/wrapper';
55

66
describe('InputNumber.Input', () => {
@@ -223,4 +223,20 @@ describe('InputNumber.Input', () => {
223223
fireEvent.blur(container.querySelector('input'));
224224
expect(onChange).not.toHaveBeenCalled();
225225
});
226+
227+
describe('nativeElement', () => {
228+
it('basic', () => {
229+
const ref = React.createRef<InputNumberRef>();
230+
const { container } = render(<InputNumber ref={ref} />);
231+
expect(ref.current.nativeElement).toBe(container.querySelector('.rc-input-number'));
232+
});
233+
234+
it('wrapper', () => {
235+
const ref = React.createRef<InputNumberRef>();
236+
const { container } = render(<InputNumber ref={ref} suffix="suffix" />);
237+
expect(ref.current.nativeElement).toBe(
238+
container.querySelector('.rc-input-number-affix-wrapper'),
239+
);
240+
});
241+
});
226242
});

tests/longPress.test.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import React from 'react';
2-
import { act } from 'react-dom/test-utils';
3-
import { render, fireEvent, waitFor } from './util/wrapper';
41
import InputNumber from '../src';
2+
import { act, fireEvent, render, waitFor } from './util/wrapper';
53

64
// Jest will mass of advanceTimersByTime if other test case not use fakeTimer.
75
// Let's create a pure file here for test.

tests/util/wrapper.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import type { ReactElement } from 'react';
2-
import { act } from 'react-dom/test-utils';
31
import type { RenderOptions } from '@testing-library/react';
4-
import { render } from '@testing-library/react';
2+
import { act, render } from '@testing-library/react';
3+
import type { ReactElement } from 'react';
54

65
const globalTimeout = global.setTimeout;
76

87
export const sleep = async (timeout = 0) => {
98
await act(async () => {
10-
await new Promise(resolve => {
9+
await new Promise((resolve) => {
1110
globalTimeout(resolve, timeout);
1211
});
1312
});
@@ -16,6 +15,5 @@ export const sleep = async (timeout = 0) => {
1615
const customRender = (ui: ReactElement, options?: Omit<RenderOptions, 'wrapper'>) =>
1716
render(ui, { ...options });
1817

19-
export { customRender as render };
20-
2118
export * from '@testing-library/react';
19+
export { customRender as render };

0 commit comments

Comments
 (0)