'use strict';

exports.__esModule = true;

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _is = require('is');

var _is2 = _interopRequireDefault(_is);

var _Input = require('../Input');

var _Input2 = _interopRequireDefault(_Input);

var _error = require('../Input/error');

var _error2 = _interopRequireDefault(_error);

var _context = require('../Input/context');

var _validate = require('../Input/validate');

var _utility = require('../Input/utility');

var _componentPropTypeCheck = require('../../utilities/componentPropTypeCheck');

require('./style.css');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }

var NumberInput = function NumberInput(props) {
  var ref = _react2.default.createRef();
  var upRef = _react2.default.createRef();
  var downRef = _react2.default.createRef();
  return _react2.default.createElement(
    _context.InputContext.Consumer,
    null,
    function (context) {
      var hasValue = _is2.default.number(context.getValue());
      var inputClasses = (0, _classnames2.default)({
        'ma__input-number__control': true,
        'js-is-required': props.required,
        'ma__input-number__control--showButtons': props.showButtons || props.unit && hasValue
      });

      var unitClasses = (0, _classnames2.default)({
        'ma__input-number-unit': true,
        'ma__input-number-unit--disabled': props.disabled,
        'ma__input-number-unit--showButtons': props.showButtons
      });

      var displayErrorMessage = function displayErrorMessage(val) {
        var min = props.min,
            max = props.max,
            required = props.required;

        if (required && !_is2.default.number(val)) {
          var errorMsg = 'Please enter a value.';
          return {
            showError: true,
            errorMsg: errorMsg
          };
        } else if (_is2.default.number(val)) {
          var _validNumber = (0, _validate.validNumber)(val, min, max),
              showError = _validNumber.showError,
              _errorMsg = _validNumber.errorMsg;

          return {
            showError: showError, errorMsg: _errorMsg
          };
        }
        return {
          showError: false,
          errorMsg: ''
        };
      };

      var hasNumberProperty = function hasNumberProperty(obj, property) {
        return Object.prototype.hasOwnProperty.call(obj, property) && _is2.default.number(obj[property]);
      };

      var handleOnBlur = function handleOnBlur(e) {
        e.persist();
        var inputEl = ref.current;
        var newValue = inputEl.value ? Number(inputEl.value) : inputEl.value;
        if (hasNumberProperty(props, 'max') && newValue > props.max) {
          newValue = props.max;
        }
        if (hasNumberProperty(props, 'min') && newValue < props.min) {
          newValue = props.min;
        }
        if (_is2.default.number(newValue)) {
          // Since to Fixed returns a string, we have to cast it back to a Number
          newValue = Number(newValue.toFixed((0, _utility.countDecimals)(props.step)));
          var updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, updateError), function () {
            if (_is2.default.fn(props.onBlur)) {
              props.onBlur(e, newValue);
            }
          });
        }
      };

      var handleChange = function handleChange(e) {
        e.persist();
        var inputEl = ref.current;
        var newValue = inputEl.value ? Number(inputEl.value) : inputEl.value;
        var updateError = displayErrorMessage(newValue);
        context.updateState(_extends({ value: newValue }, updateError), function () {
          if (_is2.default.fn(props.onChange)) {
            props.onChange(e, newValue, props.id);
          }
        });
      };

      var handleAdjust = function handleAdjust(e) {
        e.persist();
        var direction = void 0;
        if (e.currentTarget === upRef.current) {
          direction = 'up';
        } else {
          direction = 'down';
        }
        var inputEl = ref.current;
        var newValue = inputEl.value ? Number(inputEl.value) : inputEl.value;
        if (direction === 'up' && (!hasNumberProperty(props, 'max') || newValue < props.max)) {
          // Since to Fixed returns a string, we have to cast it back to a Number
          newValue = newValue ? Number((newValue + props.step).toFixed((0, _utility.countDecimals)(props.step))) : props.step;
          var updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, updateError), function () {
            if (_is2.default.fn(props.onChange)) {
              props.onChange(e, newValue, props.id);
            }
          });
        } else if (direction === 'down' && (!hasNumberProperty(props, 'min') || newValue > props.min)) {
          // Since to Fixed returns a string, we have to cast it back to a Number
          newValue = newValue ? Number((newValue + props.step * -1).toFixed((0, _utility.countDecimals)(props.step))) : props.step * -1;
          var _updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, _updateError), function () {
            if (_is2.default.fn(props.onChange)) {
              props.onChange(e, newValue, props.id);
            }
          });
        }
      };

      var inputAttr = {
        className: inputClasses,
        name: props.name,
        id: props.id,
        type: 'number',
        placeholder: props.placeholder,
        maxLength: Number(props.maxlength),
        style: props.width ? { width: props.width + 'px' } : null,
        onChange: handleChange,
        onBlur: handleOnBlur,
        required: props.required,
        disabled: props.disabled,
        step: props.step,
        ref: ref
      };
      inputAttr.value = context.getValue();
      if (_is2.default.number(props.max)) {
        inputAttr.max = props.max;
      }
      if (_is2.default.number(props.min)) {
        inputAttr.min = props.min;
      }
      return _react2.default.createElement(
        'div',
        { className: 'ma__input-number' },
        _react2.default.createElement('input', inputAttr),
        props.unit && hasValue ? _react2.default.createElement(
          'span',
          { className: unitClasses },
          props.unit
        ) : null,
        props.showButtons && _react2.default.createElement(
          'div',
          { className: 'ma__input-number__control-buttons' },
          _react2.default.createElement('button', {
            type: 'button',
            'aria-label': 'increase value',
            className: 'ma__input-number__control-plus',
            'data-direction': 'up',
            onClick: handleAdjust,
            disabled: props.disabled,
            tabIndex: -1,
            ref: upRef
          }),
          _react2.default.createElement('button', {
            type: 'button',
            'aria-label': 'decrease value',
            className: 'ma__input-number__control-minus',
            'data-direction': 'down',
            onClick: handleAdjust,
            disabled: props.disabled,
            tabIndex: -1,
            ref: downRef
          })
        )
      );
    }
  );
};

NumberInput.propTypes = process.env.NODE_ENV !== "production" ? {
  required: _propTypes2.default.bool,
  showButtons: _propTypes2.default.bool,
  unit: _propTypes2.default.string,
  disabled: _propTypes2.default.bool,
  min: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
  max: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
  step: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
  onBlur: _propTypes2.default.func,
  onChange: _propTypes2.default.func,
  name: _propTypes2.default.string,
  id: _propTypes2.default.string,
  maxlength: _propTypes2.default.number,
  placeholder: _propTypes2.default.string,
  width: _propTypes2.default.number
} : {};

var InputNumber = function InputNumber(props) {
  var max = props.max,
      min = props.min,
      step = props.step,
      name = props.name,
      onChange = props.onChange,
      onBlur = props.onBlur,
      placeholder = props.placeholder,
      width = props.width,
      maxlength = props.maxlength,
      showButtons = props.showButtons,
      inputProps = _objectWithoutProperties(props, ['max', 'min', 'step', 'name', 'onChange', 'onBlur', 'placeholder', 'width', 'maxlength', 'showButtons']);
  // Input and Number share the props.required, props.id and props.disabled values.


  var numberProps = {
    max: max,
    min: min,
    step: step,
    name: name,
    placeholder: placeholder,
    width: width,
    maxlength: maxlength,
    required: props.required,
    id: props.id,
    onChange: onChange,
    onBlur: onBlur,
    disabled: props.disabled,
    unit: props.unit,
    showButtons: showButtons
  };
  return _react2.default.createElement(
    _Input2.default,
    inputProps,
    _react2.default.createElement(NumberInput, numberProps),
    _react2.default.createElement(_error2.default, { id: props.id })
  );
};

InputNumber.propTypes = process.env.NODE_ENV !== "production" ? {
  /** Whether the label should be hidden or not */
  hiddenLabel: _propTypes2.default.bool,
  /** The label text for the input field, can be a string or a component */
  labelText: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]).isRequired,
  /** Whether the field is required or not */
  required: _propTypes2.default.bool,
  /** Whether the field is disabled or not */
  disabled: _propTypes2.default.bool,
  /** The unique ID for the input field */
  id: _propTypes2.default.string.isRequired,
  /** The name for the input field */
  name: _propTypes2.default.string.isRequired,
  /** The max acceptable input length */
  maxlength: _propTypes2.default.number,
  /** The pattern to filter input against, e.g. "[0-9]" for numbers only */
  pattern: _propTypes2.default.string,
  /** The number of characters wide to make the input field */
  width: _propTypes2.default.number,
  /** The placeholder text for the input field */
  placeholder: _propTypes2.default.string,
  /** The message to be displayed in the event of an error. */
  errorMsg: _propTypes2.default.string,
  /** Custom change function */
  onChange: _propTypes2.default.func,
  /** Custom onBlur function */
  onBlur: _propTypes2.default.func,
  /** Default input value */
  defaultValue: _propTypes2.default.number,
  /** Max value for the field. */
  max: _propTypes2.default.number,
  /** Min value for the field. */
  min: _propTypes2.default.number,
  /** Using the up/down arrow keys will increment/decrement the input value by this number. */
  step: _propTypes2.default.number,
  /** Inline label and input field */
  inline: _propTypes2.default.bool,
  /** A unit that is a string of no more than 2 characters renders in the input after the value, e.g. %  */
  unit: function unit(props, propName) {
    return (0, _componentPropTypeCheck.numberCharacterPropTypeCheck)(props, propName, 2);
  },
  /** Whether to render up/down buttons */
  showButtons: _propTypes2.default.bool
} : {};

InputNumber.defaultProps = {
  hiddenLabel: false,
  required: false,
  onChange: null,
  step: 1,
  showButtons: true,
  unit: ''
};

exports.default = InputNumber;
module.exports = exports['default'];