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; };

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; }

import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import is from 'is';

import Input from '../Input';
import Error from '../Input/error';
import { InputContext } from '../Input/context';
import { validNumber } from '../Input/validate';
import { countDecimals } from '../Input/utility';
import { numberCharacterPropTypeCheck } from '../../utilities/componentPropTypeCheck';
import './style.css';

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

      var unitClasses = classNames({
        '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 && !is.number(val)) {
          var errorMsg = 'Please enter a value.';
          return {
            showError: true,
            errorMsg: errorMsg
          };
        } else if (is.number(val)) {
          var _validNumber = 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) && is.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 (is.number(newValue)) {
          // Since to Fixed returns a string, we have to cast it back to a Number
          newValue = Number(newValue.toFixed(countDecimals(props.step)));
          var updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, updateError), function () {
            if (is.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 (is.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(countDecimals(props.step))) : props.step;
          var updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, updateError), function () {
            if (is.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(countDecimals(props.step))) : props.step * -1;
          var _updateError = displayErrorMessage(newValue);
          context.updateState(_extends({ value: newValue }, _updateError), function () {
            if (is.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 (is.number(props.max)) {
        inputAttr.max = props.max;
      }
      if (is.number(props.min)) {
        inputAttr.min = props.min;
      }
      return React.createElement(
        'div',
        { className: 'ma__input-number' },
        React.createElement('input', inputAttr),
        props.unit && hasValue ? React.createElement(
          'span',
          { className: unitClasses },
          props.unit
        ) : null,
        props.showButtons && React.createElement(
          'div',
          { className: 'ma__input-number__control-buttons' },
          React.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
          }),
          React.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: PropTypes.bool,
  showButtons: PropTypes.bool,
  unit: PropTypes.string,
  disabled: PropTypes.bool,
  min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  onBlur: PropTypes.func,
  onChange: PropTypes.func,
  name: PropTypes.string,
  id: PropTypes.string,
  maxlength: PropTypes.number,
  placeholder: PropTypes.string,
  width: PropTypes.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 React.createElement(
    Input,
    inputProps,
    React.createElement(NumberInput, numberProps),
    React.createElement(Error, { id: props.id })
  );
};

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

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

export default InputNumber;