text: "use strict";
  
  var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
  
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  exports.default = void 0;
  
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  
  var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  
  var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
  
  var React = _interopRequireWildcard(require("react"));
  
  var _classnames = _interopRequireDefault(require("classnames"));
  
  var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode"));
  
  var _ref = require("rc-util/lib/ref");
  
  var _MiniDecimal = _interopRequireWildcard(require("./utils/MiniDecimal"));
  
  var _StepHandler = _interopRequireDefault(require("./StepHandler"));
  
  var _numberUtil = require("./utils/numberUtil");
  
  var _useCursor3 = _interopRequireDefault(require("./hooks/useCursor"));
  
  var _useUpdateEffect = _interopRequireDefault(require("./hooks/useUpdateEffect"));
  
  /**
   * We support `stringMode` which need handle correct type when user call in onChange
   */
  var getDecimalValue = function getDecimalValue(stringMode, decimalValue) {
    if (stringMode || decimalValue.isEmpty()) {
      return decimalValue.toString();
    }
  
    return decimalValue.toNumber();
  };
  
  var getDecimalIfValidate = function getDecimalIfValidate(value) {
    var decimal = (0, _MiniDecimal.default)(value);
    return decimal.isInvalidate() ? null : decimal;
  };
  
  var InputNumber = /*#__PURE__*/React.forwardRef(function (props, ref) {
    var _classNames;
  
    var _props$prefixCls = props.prefixCls,
        prefixCls = _props$prefixCls === void 0 ? 'rc-input-number' : _props$prefixCls,
        className = props.className,
        style = props.style,
        min = props.min,
        max = props.max,
        _props$step = props.step,
        step = _props$step === void 0 ? 1 : _props$step,
        defaultValue = props.defaultValue,
        value = props.value,
        disabled = props.disabled,
        readOnly = props.readOnly,
        upHandler = props.upHandler,
        downHandler = props.downHandler,
        keyboard = props.keyboard,
        stringMode = props.stringMode,
        parser = props.parser,
        formatter = props.formatter,
        precision = props.precision,
        decimalSeparator = props.decimalSeparator,
        onChange = props.onChange,
        onInput = props.onInput,
        onPressEnter = props.onPressEnter,
        onStep = props.onStep,
        inputProps = (0, _objectWithoutProperties2.default)(props, ["prefixCls", "className", "style", "min", "max", "step", "defaultValue", "value", "disabled", "readOnly", "upHandler", "downHandler", "keyboard", "stringMode", "parser", "formatter", "precision", "decimalSeparator", "onChange", "onInput", "onPressEnter", "onStep"]);
    var inputClassName = "".concat(prefixCls, "-input");
    var inputRef = React.useRef(null);
  
    var _React$useState = React.useState(false),
        _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
        focus = _React$useState2[0],
        setFocus = _React$useState2[1];
  
    var userTypingRef = React.useRef(false);
    var compositionRef = React.useRef(false); // ============================ Value =============================
    // Real value control
  
    var _React$useState3 = React.useState(function () {
      return (0, _MiniDecimal.default)(defaultValue !== null && defaultValue !== void 0 ? defaultValue : value);
    }),
        _React$useState4 = (0, _slicedToArray2.default)(_React$useState3, 2),
        decimalValue = _React$useState4[0],
        setDecimalValue = _React$useState4[1];
  
    function setUncontrolledDecimalValue(newDecimal) {
      if (value === undefined) {
        setDecimalValue(newDecimal);
      }
    } // ====================== Parser & Formatter ======================
  
    /**
     * `precision` is used for formatter & onChange.
     * It will auto generate by `value` & `step`.
     * But it will not block user typing when auto generated.
     *
     * Note: Auto generate `precision` is used for legacy logic.
     * We should remove this since we already support high precision with BigInt.
     *
     * @param number  Provide which number should calculate precision
     * @param userTyping  Change by user typing
     */
  
  
    var getPrecision = React.useCallback(function (numStr, userTyping) {
      if (precision >= 0) {
        return precision;
      }
  
      if (userTyping) {
        return undefined;
      }
  
      return Math.max((0, _numberUtil.getNumberPrecision)(numStr), (0, _numberUtil.getNumberPrecision)(step));
    }, [precision, step]); // >>> Parser
  
    var mergedParser = React.useCallback(function (num) {
      var numStr = String(num);
  
      if (parser) {
        return parser(numStr);
      }
  
      var parsedStr = numStr;
  
      if (decimalSeparator) {
        parsedStr = parsedStr.replace(decimalSeparator, '.');
      } // [Legacy] We still support auto convert `$ 123,456` to `123456`
  
  
      return parsedStr.replace(/[^\w.-]+/g, '');
    }, [parser, decimalSeparator]); // >>> Formatter
  
    var mergedFormatter = React.useCallback(function (number, userTyping) {
      if (formatter) {
        return formatter(number);
      }
  
      var str = typeof number === 'number' ? (0, _numberUtil.num2str)(number) : number;
      var mergedPrecision = getPrecision(str, userTyping);
  
      if ((0, _numberUtil.validateNumber)(str) && (decimalSeparator || mergedPrecision >= 0)) {
        // Separator
        var separatorStr = decimalSeparator || '.';
        str = (0, _MiniDecimal.toFixed)(str, separatorStr, mergedPrecision);
      }
  
      return str;
    }, [formatter, getPrecision, decimalSeparator]); // ========================== InputValue ==========================
  
    /**
     * Input text value control
     *
     * User can not update input content directly. It update with follow rules by priority:
     *  1. controlled `value` changed
     *    * [SPECIAL] Typing like `1.` should not immediately convert to `1`
     *  2. User typing
     *  3. Blur or Enter trigger revalidate
     */
  
    var _React$useState5 = React.useState(function () {
      var initValue = defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
  
      if (decimalValue.isInvalidate() && ['string', 'number'].includes((0, _typeof2.default)(initValue))) {
        return Number.isNaN(initValue) ? '' : initValue;
      }
  
      return mergedFormatter(decimalValue.toString(), false);
    }),
        _React$useState6 = (0, _slicedToArray2.default)(_React$useState5, 2),
        inputValue = _React$useState6[0],
        setInternalInputValue = _React$useState6[1]; // Should always be string
  
  
    function setInputValue(newValue, userTyping) {
      setInternalInputValue(mergedFormatter(newValue.toString(false), userTyping));
    } // >>> Max & Min limit
  
  
    var maxDecimal = React.useMemo(function () {
      return getDecimalIfValidate(max);
    }, [max]);
    var minDecimal = React.useMemo(function () {
      return getDecimalIfValidate(min);
    }, [min]);
    var upDisabled = React.useMemo(function () {
      if (!maxDecimal || !decimalValue || decimalValue.isInvalidate()) {
        return false;
      }
  
      return maxDecimal.lessEquals(decimalValue);
    }, [maxDecimal, decimalValue]);
    var downDisabled = React.useMemo(function () {
      if (!minDecimal || !decimalValue || decimalValue.isInvalidate()) {
        return false;
      }
  
      return decimalValue.lessEquals(minDecimal);
    }, [minDecimal, decimalValue]); // Cursor controller
  
    var _useCursor = (0, _useCursor3.default)(inputRef.current, focus),
        _useCursor2 = (0, _slicedToArray2.default)(_useCursor, 2),
        recordCursor = _useCursor2[0],
        restoreCursor = _useCursor2[1]; // ============================= Data =============================
  
    /**
     * Find target value closet within range.
     * e.g. [11, 28]:
     *    3  => 11
     *    23 => 23
     *    99 => 28
     */
  
  
    var getRangeValue = function getRangeValue(target) {
      // target > max
      if (maxDecimal && !target.lessEquals(maxDecimal)) {
        return maxDecimal;
      } // target < min
  
  
      if (minDecimal && !minDecimal.lessEquals(target)) {
        return minDecimal;
      }
  
      return null;
    };
    /**
     * Check value is in [min, max] range
     */
  
  
    var isInRange = function isInRange(target) {
      return !getRangeValue(target);
    };
    /**
     * Trigger `onChange` if value validated and not equals of origin.
     * Return the value that re-align in range.
     */
  
  
    var triggerValueUpdate = function triggerValueUpdate(newValue, userTyping) {
      var updateValue = newValue; // Skip align value when trigger value is empty.
      // We just trigger onChange(null)
  
      if (!updateValue.isEmpty()) {
        // Revert value in range if needed
        updateValue = getRangeValue(updateValue) || updateValue;
      }
  
      if (!readOnly && !disabled) {
        var numStr = updateValue.toString();
        var mergedPrecision = getPrecision(numStr, userTyping);
  
        if (mergedPrecision) {
          updateValue = (0, _MiniDecimal.default)((0, _MiniDecimal.toFixed)(numStr, '.', mergedPrecision));
        } // Trigger event
  
  
        if (!updateValue.equals(decimalValue)) {
          setUncontrolledDecimalValue(updateValue);
          onChange === null || onChange === void 0 ? void 0 : onChange(updateValue.isEmpty() ? null : getDecimalValue(stringMode, updateValue)); // Reformat input if value is not controlled
  
          if (value === undefined) {
            setInputValue(updateValue, userTyping);
          }
        }
  
        return updateValue;
      }
  
      return decimalValue;
    }; // ========================== User Input ==========================
    // >>> Collect input value
  
  
    var collectInputValue = function collectInputValue(inputStr) {
      recordCursor(); // Update inputValue incase input can not parse as number
  
      setInternalInputValue(inputStr); // Parse number
  
      if (!compositionRef.current) {
        var finalValue = mergedParser(inputStr);
        var finalDecimal = (0, _MiniDecimal.default)(finalValue);
  
        if (!finalDecimal.isInvalidate()) {
          triggerValueUpdate(finalDecimal, true);
        }
      }
    }; // >>> Composition
  
  
    var onCompositionStart = function onCompositionStart() {
      compositionRef.current = true;
    };
  
    var onCompositionEnd = function onCompositionEnd() {
      compositionRef.current = false;
      collectInputValue(inputRef.current.value);
    }; // >>> Input
  
  
    var onInternalInput = function onInternalInput(e) {
      var inputStr = e.target.value; // optimize for chinese input experience
      // https://github.com/ant-design/ant-design/issues/8196
  
      if (!parser) {
        inputStr = inputStr.replace(/。/g, '.');
      }
  
      collectInputValue(inputStr); // Trigger onInput later to let user customize value if they want do handle something after onChange
  
      onInput === null || onInput === void 0 ? void 0 : onInput(inputStr);
    }; // ============================= Step =============================
  
  
    var onInternalStep = function onInternalStep(up) {
      var _inputRef$current;
  
      // Ignore step since out of range
      if (up && upDisabled || !up && downDisabled) {
        return;
      } // Clear typing status since it may caused by up & down key.
      // We should sync with input value.
  
  
      userTypingRef.current = false;
      var stepDecimal = (0, _MiniDecimal.default)(step);
  
      if (!up) {
        stepDecimal = stepDecimal.negate();
      }
  
      var target = (decimalValue || (0, _MiniDecimal.default)(0)).add(stepDecimal.toString());
      var updatedValue = triggerValueUpdate(target, false);
      onStep === null || onStep === void 0 ? void 0 : onStep(getDecimalValue(stringMode, updatedValue), {
        offset: step,
        type: up ? 'up' : 'down'
      });
      (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.focus();
    }; // ============================ Flush =============================
  
    /**
     * Flush current input content to trigger value change & re-formatter input if needed
     */
  
  
    var flushInputValue = function flushInputValue() {
      var parsedValue = (0, _MiniDecimal.default)(mergedParser(inputValue));
      var formatValue = parsedValue;
  
      if (!parsedValue.isNaN()) {
        // Only validate value or empty value can be re-fill to inputValue
        // Reassign the formatValue within ranged of trigger control
        formatValue = triggerValueUpdate(parsedValue, true);
      } else {
        formatValue = decimalValue;
      }
  
      if (value !== undefined) {
        // Reset back with controlled value first
        setInputValue(decimalValue, false);
      } else if (!formatValue.isNaN()) {
        // Reset input back since no validate value
        setInputValue(formatValue, false);
      }
    };
  
    var onKeyDown = function onKeyDown(event) {
      var which = event.which;
      userTypingRef.current = true;
  
      if (which === _KeyCode.default.ENTER) {
        flushInputValue();
        onPressEnter === null || onPressEnter === void 0 ? void 0 : onPressEnter(event);
      }
  
      if (keyboard === false) {
        return;
      } // Do step
  
  
      if (!compositionRef.current && [_KeyCode.default.UP, _KeyCode.default.DOWN].includes(which)) {
        onInternalStep(_KeyCode.default.UP === which);
        event.preventDefault();
      }
    };
  
    var onKeyUp = function onKeyUp() {
      userTypingRef.current = false;
    }; // >>> Focus & Blur
  
  
    var onBlur = function onBlur() {
      flushInputValue();
      setFocus(false);
    }; // ========================== Controlled ==========================
    // Input by precision
  
  
    (0, _useUpdateEffect.default)(function () {
      if (!decimalValue.isInvalidate()) {
        setInputValue(decimalValue, false);
      }
    }, [precision]); // Input by value
  
    (0, _useUpdateEffect.default)(function () {
      var newValue = (0, _MiniDecimal.default)(value);
      setDecimalValue(newValue); // When user typing from `1.2` to `1.`, we should not convert to `1` immediately.
      // But let it go if user set `formatter`
  
      if (newValue.isNaN() || !userTypingRef.current || formatter) {
        // Update value as effect
        setInputValue(newValue, false);
      }
    }, [value]); // ============================ Cursor ============================
  
    (0, _useUpdateEffect.default)(function () {
      if (formatter) {
        restoreCursor();
      }
    }, [inputValue]); // ============================ Render ============================
  
    return /*#__PURE__*/React.createElement("div", {
      className: (0, _classnames.default)(prefixCls, className, (_classNames = {}, (0, _defineProperty2.default)(_classNames, "".concat(prefixCls, "-focused"), focus), (0, _defineProperty2.default)(_classNames, "".concat(prefixCls, "-disabled"), disabled), (0, _defineProperty2.default)(_classNames, "".concat(prefixCls, "-readonly"), readOnly), (0, _defineProperty2.default)(_classNames, "".concat(prefixCls, "-not-a-number"), decimalValue.isNaN()), (0, _defineProperty2.default)(_classNames, "".concat(prefixCls, "-out-of-range"), !decimalValue.isInvalidate() && !isInRange(decimalValue)), _classNames)),
      style: style,
      onFocus: function onFocus() {
        setFocus(true);
      },
      onBlur: onBlur,
      onKeyDown: onKeyDown,
      onKeyUp: onKeyUp,
      onCompositionStart: onCompositionStart,
      onCompositionEnd: onCompositionEnd
    }, /*#__PURE__*/React.createElement(_StepHandler.default, {
      prefixCls: prefixCls,
      upNode: upHandler,
      downNode: downHandler,
      upDisabled: upDisabled,
      downDisabled: downDisabled,
      onStep: onInternalStep
    }), /*#__PURE__*/React.createElement("div", {
      className: "".concat(inputClassName, "-wrap")
    }, /*#__PURE__*/React.createElement("input", (0, _extends2.default)({
      autoComplete: "off",
      role: "spinbutton",
      "aria-valuemin": min,
      "aria-valuemax": max,
      "aria-valuenow": decimalValue.isInvalidate() ? null : decimalValue.toString(),
      step: step
    }, inputProps, {
      ref: (0, _ref.composeRef)(inputRef, ref),
      className: inputClassName,
      value: inputValue,
      onChange: onInternalInput,
      disabled: disabled,
      readOnly: readOnly
    }))));
  });
  InputNumber.displayName = 'InputNumber';
  var _default = InputNumber;
  exports.default = _default;