"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

exports.__esModule = true;
exports.default = void 0;

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));

var _react = _interopRequireWildcard(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _isNil = _interopRequireDefault(require("lodash/isNil"));

var _AngleUp = _interopRequireDefault(require("@rsuite/icons/legacy/AngleUp"));

var _AngleDown = _interopRequireDefault(require("@rsuite/icons/legacy/AngleDown"));

var _DOMHelper = _interopRequireDefault(require("../DOMHelper"));

var _InputGroup = _interopRequireDefault(require("../InputGroup/InputGroup"));

var _InputGroupAddon = _interopRequireDefault(require("../InputGroup/InputGroupAddon"));

var _Input = _interopRequireDefault(require("../Input"));

var _Button = _interopRequireDefault(require("../Button"));

var _utils = require("../utils");

/**
 * Check if the value is a number.
 * @param value
 */
var isNumber = function isNumber(value) {
  return /(^-?|^\+?|^\d?)\d*\.\d+$/.test(value + '');
};
/**
 * Get the length of the decimal.
 * @param value
 */


function getDecimalLength(value) {
  if (isNumber(value)) {
    return value.toString().split('.')[1].length;
  }

  return 0;
}
/**
 * Get the value after the decimal point.
 * @param values
 */


function decimals() {
  for (var _len = arguments.length, values = new Array(_len), _key = 0; _key < _len; _key++) {
    values[_key] = arguments[_key];
  }

  var lengths = values.map(getDecimalLength);
  return Math.max.apply(Math, lengths);
}
/**
 * Disable the upper limit of the number.
 * @param value
 * @param max
 */


function disableMaxValue(value, max) {
  if (!(0, _isNil.default)(value)) {
    return +value >= max;
  }

  return false;
}
/**
 * Disable the lower limit of the number.
 * @param value
 * @param min
 */


function disableMinValue(value, min) {
  if (!(0, _isNil.default)(value)) {
    return +value <= min;
  }

  return false;
}

var defaultProps = {
  as: _InputGroup.default,
  classPrefix: 'input-number',
  min: -Infinity,
  max: Infinity,
  step: 1,
  buttonAppearance: 'subtle',
  scrollable: true
};

var InputNumber = /*#__PURE__*/_react.default.forwardRef(function (props, ref) {
  var Component = props.as,
      className = props.className,
      classPrefix = props.classPrefix,
      disabled = props.disabled,
      readOnly = props.readOnly,
      plaintext = props.plaintext,
      valueProp = props.value,
      defaultValue = props.defaultValue,
      size = props.size,
      prefixElement = props.prefix,
      postfix = props.postfix,
      step = props.step,
      buttonAppearance = props.buttonAppearance,
      min = props.min,
      max = props.max,
      scrollable = props.scrollable,
      onChange = props.onChange,
      onWheel = props.onWheel,
      restProps = (0, _objectWithoutPropertiesLoose2.default)(props, ["as", "className", "classPrefix", "disabled", "readOnly", "plaintext", "value", "defaultValue", "size", "prefix", "postfix", "step", "buttonAppearance", "min", "max", "scrollable", "onChange", "onWheel"]);

  var _useControlled = (0, _utils.useControlled)(valueProp, defaultValue),
      value = _useControlled[0],
      setValue = _useControlled[1];

  var _useState = (0, _react.useState)(disableMaxValue(value, max)),
      disabledUpButton = _useState[0],
      setDisabledUpButton = _useState[1];

  var _useState2 = (0, _react.useState)(disableMinValue(value, min)),
      disabledDownButton = _useState2[0],
      setDisabledDownButton = _useState2[1];

  var _useClassNames = (0, _utils.useClassNames)(classPrefix),
      withClassPrefix = _useClassNames.withClassPrefix,
      merge = _useClassNames.merge,
      prefix = _useClassNames.prefix;

  var classes = merge(className, withClassPrefix());

  var _partitionHTMLProps = (0, _utils.partitionHTMLProps)(restProps),
      htmlInputProps = _partitionHTMLProps[0],
      rest = _partitionHTMLProps[1];

  var inputRef = (0, _react.useRef)();
  var handleValue = (0, _react.useCallback)(function (currentValue, event) {
    if (currentValue !== value) {
      // Disable the up button when the value is greater than the maximum value.
      setDisabledUpButton(disableMaxValue(currentValue, max)); // Disable the down button when the value is greater than the minimum value.

      setDisabledDownButton(disableMinValue(currentValue, min));
      setValue(currentValue);
      onChange === null || onChange === void 0 ? void 0 : onChange(currentValue, event);
    }
  }, [max, min, onChange, setValue, value]);
  var getSafeValue = (0, _react.useCallback)(function (value) {
    if (!Number.isNaN(value)) {
      if (+value > max) {
        value = max;
      }

      if (+value < min) {
        value = min;
      }
    } else {
      value = '';
    }

    return value.toString();
  }, [max, min]);
  var handlePlus = (0, _react.useCallback)(function (event) {
    var val = +(value || 0);
    var bit = decimals(val, step);
    handleValue(getSafeValue((val + step).toFixed(bit)), event);
  }, [getSafeValue, handleValue, step, value]);
  var handleMinus = (0, _react.useCallback)(function (event) {
    var val = +(value || 0);
    var bit = decimals(val, step);
    handleValue(getSafeValue((val - step).toFixed(bit)), event);
  }, [getSafeValue, handleValue, step, value]);
  var handleWheel = (0, _react.useCallback)(function (event) {
    if (!disabled && !readOnly && event.target === document.activeElement) {
      event.preventDefault();
      var delta = event['wheelDelta'] || -event.deltaY || -(event === null || event === void 0 ? void 0 : event.detail);

      if (delta > 0) {
        handleMinus(event);
      }

      if (delta < 0) {
        handlePlus(event);
      }
    }

    onWheel === null || onWheel === void 0 ? void 0 : onWheel(event);
  }, [disabled, handleMinus, handlePlus, onWheel, readOnly]);
  var handleChange = (0, _react.useCallback)(function (value, event) {
    if (!/^-?(?:\d+)?(\.)?\d*$/.test(value) && value !== '') {
      return;
    }

    handleValue(value, event);
  }, [handleValue]);
  var handleBlur = (0, _react.useCallback)(function (event) {
    var _event$target;

    var targetValue = Number.parseFloat((_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.value);
    handleValue(getSafeValue(targetValue), event);
  }, [getSafeValue, handleValue]);
  (0, _react.useEffect)(function () {
    var wheelListener;

    if (inputRef.current && scrollable) {
      wheelListener = _DOMHelper.default.on(inputRef.current, 'wheel', handleWheel, {
        passive: false
      });
    }

    return function () {
      var _wheelListener;

      (_wheelListener = wheelListener) === null || _wheelListener === void 0 ? void 0 : _wheelListener.off();
    };
  }, [handleWheel, scrollable]);

  var input = /*#__PURE__*/_react.default.createElement(_Input.default, (0, _extends2.default)({}, htmlInputProps, {
    type: "text",
    autoComplete: "off",
    step: step,
    inputRef: inputRef,
    onChange: handleChange,
    onBlur: (0, _utils.createChainedFunction)(handleBlur, htmlInputProps === null || htmlInputProps === void 0 ? void 0 : htmlInputProps.onBlur),
    value: (0, _isNil.default)(value) ? '' : "" + value,
    disabled: disabled,
    readOnly: readOnly,
    plaintext: plaintext
  }));

  if (plaintext) {
    return input;
  }

  return /*#__PURE__*/_react.default.createElement(Component, (0, _extends2.default)({}, rest, {
    ref: ref,
    className: classes,
    disabled: disabled,
    size: size
  }), prefixElement && /*#__PURE__*/_react.default.createElement(_InputGroupAddon.default, null, prefixElement), input, /*#__PURE__*/_react.default.createElement("span", {
    className: prefix('btn-group-vertical')
  }, /*#__PURE__*/_react.default.createElement(_Button.default, {
    appearance: buttonAppearance,
    className: prefix('touchspin-up'),
    onClick: handlePlus,
    disabled: disabledUpButton || disabled || readOnly
  }, /*#__PURE__*/_react.default.createElement(_AngleUp.default, null)), /*#__PURE__*/_react.default.createElement(_Button.default, {
    appearance: buttonAppearance,
    className: prefix('touchspin-down'),
    onClick: handleMinus,
    disabled: disabledDownButton || disabled || readOnly
  }, /*#__PURE__*/_react.default.createElement(_AngleDown.default, null))), postfix && /*#__PURE__*/_react.default.createElement(_InputGroupAddon.default, null, postfix));
});

InputNumber.displayName = 'InputNumber';
InputNumber.defaultProps = defaultProps;
InputNumber.propTypes = {
  className: _propTypes.default.string,
  classPrefix: _propTypes.default.string,
  min: _propTypes.default.number,
  max: _propTypes.default.number,
  step: _propTypes.default.number,
  value: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
  defaultValue: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
  prefix: _propTypes.default.node,
  postfix: _propTypes.default.node,
  disabled: _propTypes.default.bool,
  readOnly: _propTypes.default.bool,
  plaintext: _propTypes.default.bool,
  scrollable: _propTypes.default.bool,
  size: _propTypes.default.oneOf(['lg', 'md', 'sm', 'xs']),
  buttonAppearance: _propTypes.default.oneOf(['default', 'primary', 'link', 'subtle', 'ghost']),
  onWheel: _propTypes.default.func,
  onChange: _propTypes.default.func
};
var _default = InputNumber;
exports.default = _default;