1 | import _extends from "@babel/runtime/helpers/esm/extends";
|
2 | import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
3 | import _typeof from "@babel/runtime/helpers/esm/typeof";
|
4 | import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
5 | import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
|
6 | var _excluded = ["prefixCls", "className", "style", "min", "max", "step", "defaultValue", "value", "disabled", "readOnly", "upHandler", "downHandler", "keyboard", "controls", "stringMode", "parser", "formatter", "precision", "decimalSeparator", "onChange", "onInput", "onPressEnter", "onStep"];
|
7 | import * as React from 'react';
|
8 | import classNames from 'classnames';
|
9 | import KeyCode from "rc-util/es/KeyCode";
|
10 | import { composeRef } from "rc-util/es/ref";
|
11 | import getMiniDecimal, { toFixed } from './utils/MiniDecimal';
|
12 | import StepHandler from './StepHandler';
|
13 | import { getNumberPrecision, num2str, validateNumber } from './utils/numberUtil';
|
14 | import useCursor from './hooks/useCursor';
|
15 | import useUpdateEffect from './hooks/useUpdateEffect';
|
16 | import useFrame from './hooks/useFrame';
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | var getDecimalValue = function getDecimalValue(stringMode, decimalValue) {
|
22 | if (stringMode || decimalValue.isEmpty()) {
|
23 | return decimalValue.toString();
|
24 | }
|
25 |
|
26 | return decimalValue.toNumber();
|
27 | };
|
28 |
|
29 | var getDecimalIfValidate = function getDecimalIfValidate(value) {
|
30 | var decimal = getMiniDecimal(value);
|
31 | return decimal.isInvalidate() ? null : decimal;
|
32 | };
|
33 |
|
34 | var InputNumber = React.forwardRef(function (props, ref) {
|
35 | var _classNames;
|
36 |
|
37 | var _props$prefixCls = props.prefixCls,
|
38 | prefixCls = _props$prefixCls === void 0 ? 'rc-input-number' : _props$prefixCls,
|
39 | className = props.className,
|
40 | style = props.style,
|
41 | min = props.min,
|
42 | max = props.max,
|
43 | _props$step = props.step,
|
44 | step = _props$step === void 0 ? 1 : _props$step,
|
45 | defaultValue = props.defaultValue,
|
46 | value = props.value,
|
47 | disabled = props.disabled,
|
48 | readOnly = props.readOnly,
|
49 | upHandler = props.upHandler,
|
50 | downHandler = props.downHandler,
|
51 | keyboard = props.keyboard,
|
52 | _props$controls = props.controls,
|
53 | controls = _props$controls === void 0 ? true : _props$controls,
|
54 | stringMode = props.stringMode,
|
55 | parser = props.parser,
|
56 | formatter = props.formatter,
|
57 | precision = props.precision,
|
58 | decimalSeparator = props.decimalSeparator,
|
59 | onChange = props.onChange,
|
60 | onInput = props.onInput,
|
61 | onPressEnter = props.onPressEnter,
|
62 | onStep = props.onStep,
|
63 | inputProps = _objectWithoutProperties(props, _excluded);
|
64 |
|
65 | var inputClassName = "".concat(prefixCls, "-input");
|
66 | var inputRef = React.useRef(null);
|
67 |
|
68 | var _React$useState = React.useState(false),
|
69 | _React$useState2 = _slicedToArray(_React$useState, 2),
|
70 | focus = _React$useState2[0],
|
71 | setFocus = _React$useState2[1];
|
72 |
|
73 | var userTypingRef = React.useRef(false);
|
74 | var compositionRef = React.useRef(false);
|
75 |
|
76 |
|
77 | var _React$useState3 = React.useState(function () {
|
78 | return getMiniDecimal(value !== null && value !== void 0 ? value : defaultValue);
|
79 | }),
|
80 | _React$useState4 = _slicedToArray(_React$useState3, 2),
|
81 | decimalValue = _React$useState4[0],
|
82 | setDecimalValue = _React$useState4[1];
|
83 |
|
84 | function setUncontrolledDecimalValue(newDecimal) {
|
85 | if (value === undefined) {
|
86 | setDecimalValue(newDecimal);
|
87 | }
|
88 | }
|
89 |
|
90 | |
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | var getPrecision = React.useCallback(function (numStr, userTyping) {
|
104 | if (userTyping) {
|
105 | return undefined;
|
106 | }
|
107 |
|
108 | if (precision >= 0) {
|
109 | return precision;
|
110 | }
|
111 |
|
112 | return Math.max(getNumberPrecision(numStr), getNumberPrecision(step));
|
113 | }, [precision, step]);
|
114 |
|
115 | var mergedParser = React.useCallback(function (num) {
|
116 | var numStr = String(num);
|
117 |
|
118 | if (parser) {
|
119 | return parser(numStr);
|
120 | }
|
121 |
|
122 | var parsedStr = numStr;
|
123 |
|
124 | if (decimalSeparator) {
|
125 | parsedStr = parsedStr.replace(decimalSeparator, '.');
|
126 | }
|
127 |
|
128 |
|
129 | return parsedStr.replace(/[^\w.-]+/g, '');
|
130 | }, [parser, decimalSeparator]);
|
131 |
|
132 | var inputValueRef = React.useRef('');
|
133 | var mergedFormatter = React.useCallback(function (number, userTyping) {
|
134 | if (formatter) {
|
135 | return formatter(number, {
|
136 | userTyping: userTyping,
|
137 | input: String(inputValueRef.current)
|
138 | });
|
139 | }
|
140 |
|
141 | var str = typeof number === 'number' ? num2str(number) : number;
|
142 |
|
143 | if (!userTyping) {
|
144 | var mergedPrecision = getPrecision(str, userTyping);
|
145 |
|
146 | if (validateNumber(str) && (decimalSeparator || mergedPrecision >= 0)) {
|
147 |
|
148 | var separatorStr = decimalSeparator || '.';
|
149 | str = toFixed(str, separatorStr, mergedPrecision);
|
150 | }
|
151 | }
|
152 |
|
153 | return str;
|
154 | }, [formatter, getPrecision, decimalSeparator]);
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 | var _React$useState5 = React.useState(function () {
|
167 | var initValue = defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
|
168 |
|
169 | if (decimalValue.isInvalidate() && ['string', 'number'].includes(_typeof(initValue))) {
|
170 | return Number.isNaN(initValue) ? '' : initValue;
|
171 | }
|
172 |
|
173 | return mergedFormatter(decimalValue.toString(), false);
|
174 | }),
|
175 | _React$useState6 = _slicedToArray(_React$useState5, 2),
|
176 | inputValue = _React$useState6[0],
|
177 | setInternalInputValue = _React$useState6[1];
|
178 |
|
179 | inputValueRef.current = inputValue;
|
180 |
|
181 | function setInputValue(newValue, userTyping) {
|
182 | setInternalInputValue(mergedFormatter(
|
183 |
|
184 |
|
185 | newValue.isInvalidate() ? newValue.toString(false) : newValue.toString(!userTyping), userTyping));
|
186 | }
|
187 |
|
188 |
|
189 | var maxDecimal = React.useMemo(function () {
|
190 | return getDecimalIfValidate(max);
|
191 | }, [max]);
|
192 | var minDecimal = React.useMemo(function () {
|
193 | return getDecimalIfValidate(min);
|
194 | }, [min]);
|
195 | var upDisabled = React.useMemo(function () {
|
196 | if (!maxDecimal || !decimalValue || decimalValue.isInvalidate()) {
|
197 | return false;
|
198 | }
|
199 |
|
200 | return maxDecimal.lessEquals(decimalValue);
|
201 | }, [maxDecimal, decimalValue]);
|
202 | var downDisabled = React.useMemo(function () {
|
203 | if (!minDecimal || !decimalValue || decimalValue.isInvalidate()) {
|
204 | return false;
|
205 | }
|
206 |
|
207 | return decimalValue.lessEquals(minDecimal);
|
208 | }, [minDecimal, decimalValue]);
|
209 |
|
210 | var _useCursor = useCursor(inputRef.current, focus),
|
211 | _useCursor2 = _slicedToArray(_useCursor, 2),
|
212 | recordCursor = _useCursor2[0],
|
213 | restoreCursor = _useCursor2[1];
|
214 |
|
215 | |
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | var getRangeValue = function getRangeValue(target) {
|
225 |
|
226 | if (maxDecimal && !target.lessEquals(maxDecimal)) {
|
227 | return maxDecimal;
|
228 | }
|
229 |
|
230 |
|
231 | if (minDecimal && !minDecimal.lessEquals(target)) {
|
232 | return minDecimal;
|
233 | }
|
234 |
|
235 | return null;
|
236 | };
|
237 | |
238 |
|
239 |
|
240 |
|
241 |
|
242 | var isInRange = function isInRange(target) {
|
243 | return !getRangeValue(target);
|
244 | };
|
245 | |
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 | var triggerValueUpdate = function triggerValueUpdate(newValue, userTyping) {
|
252 | var updateValue = newValue;
|
253 | var isRangeValidate = isInRange(updateValue) || updateValue.isEmpty();
|
254 |
|
255 |
|
256 |
|
257 | if (!updateValue.isEmpty() && !userTyping) {
|
258 |
|
259 | updateValue = getRangeValue(updateValue) || updateValue;
|
260 | isRangeValidate = true;
|
261 | }
|
262 |
|
263 | if (!readOnly && !disabled && isRangeValidate) {
|
264 | var numStr = updateValue.toString();
|
265 | var mergedPrecision = getPrecision(numStr, userTyping);
|
266 |
|
267 | if (mergedPrecision >= 0) {
|
268 | updateValue = getMiniDecimal(toFixed(numStr, '.', mergedPrecision));
|
269 | }
|
270 |
|
271 |
|
272 | if (!updateValue.equals(decimalValue)) {
|
273 | setUncontrolledDecimalValue(updateValue);
|
274 | onChange === null || onChange === void 0 ? void 0 : onChange(updateValue.isEmpty() ? null : getDecimalValue(stringMode, updateValue));
|
275 |
|
276 | if (value === undefined) {
|
277 | setInputValue(updateValue, userTyping);
|
278 | }
|
279 | }
|
280 |
|
281 | return updateValue;
|
282 | }
|
283 |
|
284 | return decimalValue;
|
285 | };
|
286 |
|
287 |
|
288 | var onNextPromise = useFrame();
|
289 |
|
290 | var collectInputValue = function collectInputValue(inputStr) {
|
291 | recordCursor();
|
292 |
|
293 | setInternalInputValue(inputStr);
|
294 |
|
295 | if (!compositionRef.current) {
|
296 | var finalValue = mergedParser(inputStr);
|
297 | var finalDecimal = getMiniDecimal(finalValue);
|
298 |
|
299 | if (!finalDecimal.isNaN()) {
|
300 | triggerValueUpdate(finalDecimal, true);
|
301 | }
|
302 | }
|
303 |
|
304 |
|
305 | onInput === null || onInput === void 0 ? void 0 : onInput(inputStr);
|
306 |
|
307 |
|
308 | onNextPromise(function () {
|
309 | var nextInputStr = inputStr;
|
310 |
|
311 | if (!parser) {
|
312 | nextInputStr = inputStr.replace(/。/g, '.');
|
313 | }
|
314 |
|
315 | if (nextInputStr !== inputStr) {
|
316 | collectInputValue(nextInputStr);
|
317 | }
|
318 | });
|
319 | };
|
320 |
|
321 |
|
322 | var onCompositionStart = function onCompositionStart() {
|
323 | compositionRef.current = true;
|
324 | };
|
325 |
|
326 | var onCompositionEnd = function onCompositionEnd() {
|
327 | compositionRef.current = false;
|
328 | collectInputValue(inputRef.current.value);
|
329 | };
|
330 |
|
331 |
|
332 | var onInternalInput = function onInternalInput(e) {
|
333 | collectInputValue(e.target.value);
|
334 | };
|
335 |
|
336 |
|
337 | var onInternalStep = function onInternalStep(up) {
|
338 | var _inputRef$current;
|
339 |
|
340 |
|
341 | if (up && upDisabled || !up && downDisabled) {
|
342 | return;
|
343 | }
|
344 |
|
345 |
|
346 |
|
347 | userTypingRef.current = false;
|
348 | var stepDecimal = getMiniDecimal(step);
|
349 |
|
350 | if (!up) {
|
351 | stepDecimal = stepDecimal.negate();
|
352 | }
|
353 |
|
354 | var target = (decimalValue || getMiniDecimal(0)).add(stepDecimal.toString());
|
355 | var updatedValue = triggerValueUpdate(target, false);
|
356 | onStep === null || onStep === void 0 ? void 0 : onStep(getDecimalValue(stringMode, updatedValue), {
|
357 | offset: step,
|
358 | type: up ? 'up' : 'down'
|
359 | });
|
360 | (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
|
361 | };
|
362 |
|
363 | |
364 |
|
365 |
|
366 |
|
367 |
|
368 | var flushInputValue = function flushInputValue(userTyping) {
|
369 | var parsedValue = getMiniDecimal(mergedParser(inputValue));
|
370 | var formatValue = parsedValue;
|
371 |
|
372 | if (!parsedValue.isNaN()) {
|
373 |
|
374 |
|
375 | formatValue = triggerValueUpdate(parsedValue, userTyping);
|
376 | } else {
|
377 | formatValue = decimalValue;
|
378 | }
|
379 |
|
380 | if (value !== undefined) {
|
381 |
|
382 | setInputValue(decimalValue, false);
|
383 | } else if (!formatValue.isNaN()) {
|
384 |
|
385 | setInputValue(formatValue, false);
|
386 | }
|
387 | };
|
388 |
|
389 | var onKeyDown = function onKeyDown(event) {
|
390 | var which = event.which;
|
391 | userTypingRef.current = true;
|
392 |
|
393 | if (which === KeyCode.ENTER) {
|
394 | if (!compositionRef.current) {
|
395 | userTypingRef.current = false;
|
396 | }
|
397 |
|
398 | flushInputValue(false);
|
399 | onPressEnter === null || onPressEnter === void 0 ? void 0 : onPressEnter(event);
|
400 | }
|
401 |
|
402 | if (keyboard === false) {
|
403 | return;
|
404 | }
|
405 |
|
406 |
|
407 | if (!compositionRef.current && [KeyCode.UP, KeyCode.DOWN].includes(which)) {
|
408 | onInternalStep(KeyCode.UP === which);
|
409 | event.preventDefault();
|
410 | }
|
411 | };
|
412 |
|
413 | var onKeyUp = function onKeyUp() {
|
414 | userTypingRef.current = false;
|
415 | };
|
416 |
|
417 |
|
418 | var onBlur = function onBlur() {
|
419 | flushInputValue(false);
|
420 | setFocus(false);
|
421 | userTypingRef.current = false;
|
422 | };
|
423 |
|
424 |
|
425 |
|
426 | useUpdateEffect(function () {
|
427 | if (!decimalValue.isInvalidate()) {
|
428 | setInputValue(decimalValue, false);
|
429 | }
|
430 | }, [precision]);
|
431 |
|
432 | useUpdateEffect(function () {
|
433 | var newValue = getMiniDecimal(value);
|
434 | setDecimalValue(newValue);
|
435 | var currentParsedValue = getMiniDecimal(mergedParser(inputValue));
|
436 |
|
437 |
|
438 | if (!newValue.equals(currentParsedValue) || !userTypingRef.current || formatter) {
|
439 |
|
440 | setInputValue(newValue, userTypingRef.current);
|
441 | }
|
442 | }, [value]);
|
443 |
|
444 | useUpdateEffect(function () {
|
445 | if (formatter) {
|
446 | restoreCursor();
|
447 | }
|
448 | }, [inputValue]);
|
449 |
|
450 | return React.createElement("div", {
|
451 | className: classNames(prefixCls, className, (_classNames = {}, _defineProperty(_classNames, "".concat(prefixCls, "-focused"), focus), _defineProperty(_classNames, "".concat(prefixCls, "-disabled"), disabled), _defineProperty(_classNames, "".concat(prefixCls, "-readonly"), readOnly), _defineProperty(_classNames, "".concat(prefixCls, "-not-a-number"), decimalValue.isNaN()), _defineProperty(_classNames, "".concat(prefixCls, "-out-of-range"), !decimalValue.isInvalidate() && !isInRange(decimalValue)), _classNames)),
|
452 | style: style,
|
453 | onFocus: function onFocus() {
|
454 | setFocus(true);
|
455 | },
|
456 | onBlur: onBlur,
|
457 | onKeyDown: onKeyDown,
|
458 | onKeyUp: onKeyUp,
|
459 | onCompositionStart: onCompositionStart,
|
460 | onCompositionEnd: onCompositionEnd
|
461 | }, controls && React.createElement(StepHandler, {
|
462 | prefixCls: prefixCls,
|
463 | upNode: upHandler,
|
464 | downNode: downHandler,
|
465 | upDisabled: upDisabled,
|
466 | downDisabled: downDisabled,
|
467 | onStep: onInternalStep
|
468 | }), React.createElement("div", {
|
469 | className: "".concat(inputClassName, "-wrap")
|
470 | }, React.createElement("input", _extends({
|
471 | autoComplete: "off",
|
472 | role: "spinbutton",
|
473 | "aria-valuemin": min,
|
474 | "aria-valuemax": max,
|
475 | "aria-valuenow": decimalValue.isInvalidate() ? null : decimalValue.toString(),
|
476 | step: step
|
477 | }, inputProps, {
|
478 | ref: composeRef(inputRef, ref),
|
479 | className: inputClassName,
|
480 | value: inputValue,
|
481 | onChange: onInternalInput,
|
482 | disabled: disabled,
|
483 | readOnly: readOnly
|
484 | }))));
|
485 | });
|
486 | InputNumber.displayName = 'InputNumber';
|
487 | export default InputNumber; |
\ | No newline at end of file |