Skip to content

Commit 61abf4b

Browse files
authored
feat: Format support more ability (#338)
1 parent b3f80b7 commit 61abf4b

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

docs/examples/formatter.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,18 @@ class App extends React.Component {
8484
aria-label="Controlled number input demonstrating a custom format"
8585
value={this.state.value}
8686
onChange={(value) => {
87-
console.log(value);
87+
// console.log(value);
8888
this.setState({ value });
8989
}}
90-
formatter={(value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
90+
formatter={(value, { userTyping, input }) => {
91+
if (userTyping) {
92+
return input;
93+
}
94+
return `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
95+
}}
9196
/>
9297

93-
<InputNumber
98+
<InputNumber<string | number>
9499
aria-label="Controlled number input demonstrating a custom format"
95100
value={this.state.value}
96101
onChange={(value) => {

src/InputNumber.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export interface InputNumberProps<T extends ValueType = ValueType>
5151
/** Parse display value to validate number */
5252
parser?: (displayValue: string | undefined) => T;
5353
/** Transform `value` to display value show in input */
54-
formatter?: (value: T | undefined) => string;
54+
formatter?: (value: T | undefined, info: { userTyping: boolean; input: string }) => string;
5555
/** Syntactic sugar of `formatter`. Config precision of display. */
5656
precision?: number;
5757
/** Syntactic sugar of `formatter`. Config decimal separator of display. */
@@ -170,10 +170,11 @@ const InputNumber = React.forwardRef(
170170
);
171171

172172
// >>> Formatter
173+
const inputValueRef = React.useRef<string | number>('');
173174
const mergedFormatter = React.useCallback(
174175
(number: string, userTyping: boolean) => {
175176
if (formatter) {
176-
return formatter(number);
177+
return formatter(number, { userTyping, input: String(inputValueRef.current) });
177178
}
178179

179180
let str = typeof number === 'number' ? num2str(number) : number;
@@ -212,6 +213,7 @@ const InputNumber = React.forwardRef(
212213
}
213214
return mergedFormatter(decimalValue.toString(), false);
214215
});
216+
inputValueRef.current = inputValue;
215217

216218
// Should always be string
217219
function setInputValue(newValue: DecimalClass, userTyping: boolean) {
@@ -469,7 +471,7 @@ const InputNumber = React.forwardRef(
469471
// But let it go if user set `formatter`
470472
if (newValue.isNaN() || !userTypingRef.current || formatter) {
471473
// Update value as effect
472-
setInputValue(newValue, false);
474+
setInputValue(newValue, userTypingRef.current);
473475
}
474476
}, [value]);
475477

tests/formatter.test.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,34 @@ describe('InputNumber.Formatter', () => {
7070
expect(wrapper.getInputValue()).toEqual('$ 6 boeing 737');
7171
expect(onChange).toHaveBeenLastCalledWith(6);
7272
});
73+
74+
it('control not block user input', () => {
75+
const Demo = () => {
76+
const [value, setValue] = React.useState<number>(null);
77+
78+
return (
79+
<InputNumber<number>
80+
value={value}
81+
onChange={setValue}
82+
formatter={(num, info) => {
83+
if (info.userTyping) {
84+
return info.input;
85+
}
86+
87+
return String(num);
88+
}}
89+
parser={(num) => Number(num)}
90+
/>
91+
);
92+
};
93+
94+
const wrapper = mount(<Demo />);
95+
96+
wrapper.changeValue('-');
97+
wrapper.changeValue('-0');
98+
expect(wrapper.findInput().props().value).toEqual('-0');
99+
100+
wrapper.findInput().simulate('blur');
101+
expect(wrapper.findInput().props().value).toEqual('0');
102+
});
73103
});

0 commit comments

Comments
 (0)