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