'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 _numbro = require('numbro');

var _numbro2 = _interopRequireDefault(_numbro);

var _reactCompoundSlider = require('react-compound-slider');

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

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

require('./style.css');

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

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Handle = function Handle(props) {
  var _props$handle = props.handle,
      id = _props$handle.id,
      value = _props$handle.value,
      percent = _props$handle.percent,
      getHandleProps = props.getHandleProps,
      axis = props.axis,
      min = props.min,
      max = props.max,
      step = props.step,
      displayValueFormat = props.displayValueFormat,
      disabled = props.disabled;

  var decimalPlaces = (0, _utility.countDecimals)(step);
  var roundedValue = Number.isInteger(step) ? value : Number(Number.parseFloat(value).toFixed(decimalPlaces));
  var divProps = _extends({
    'aria-valuemin': min,
    'aria-valuemax': max,
    'aria-valuenow': roundedValue,
    disabled: disabled,
    role: 'slider',
    onClick: function onClick(e) {
      e.preventDefault();
    }
  }, getHandleProps(id));
  if (axis === 'x') {
    divProps.style = {
      left: percent + '%'
    };
  } else if (axis === 'y') {
    divProps.style = {
      top: percent + '%'
    };
  }
  return _react2.default.createElement(
    'button',
    _extends({ className: 'ma__slider-handle' }, divProps),
    displayValueFormat && _react2.default.createElement(
      'div',
      { className: 'ma__slider-handle-value' },
      displayValueFormat === 'percentage' ? (0, _numbro2.default)(value).format({ output: 'percent', mantissa: 0 }) : roundedValue
    )
  );
};

Handle.propTypes = process.env.NODE_ENV !== "production" ? {
  handle: {
    id: _propTypes2.default.string,
    value: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number]),
    percent: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number])
  },
  getHandleProps: _propTypes2.default.func,
  axis: _propTypes2.default.string,
  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]),
  displayValueFormat: _propTypes2.default.string,
  disabled: _propTypes2.default.bool
} : {};

var Track = function Track(props) {
  var source = props.source,
      target = props.target,
      getTrackProps = props.getTrackProps,
      axis = props.axis;

  var divProps = _extends({}, getTrackProps());
  if (axis === 'x') {
    divProps.style = {
      left: source.percent + '%',
      width: target.percent - source.percent + '%'
    };
  } else if (axis === 'y') {
    divProps.style = {
      top: source.percent + '%',
      height: target.percent - source.percent + '%'
    };
  }
  return _react2.default.createElement('div', _extends({ className: 'ma__slider-track' }, divProps));
};

Track.propTypes = process.env.NODE_ENV !== "production" ? {
  source: {
    percent: _propTypes2.default.string
  },
  target: {
    percent: _propTypes2.default.string
  },
  getTrackProps: _propTypes2.default.func,
  axis: _propTypes2.default.string
} : {};

var Tick = function Tick(props) {
  var tick = props.tick,
      count = props.count,
      axis = props.axis,
      id = props.id;

  var top = {};
  var bottom = {};
  if (axis === 'x') {
    top.style = {
      left: tick.percent + '%'
    };
    bottom.style = {
      marginLeft: -(100 / count) / 2 + '%',
      width: 100 / count + '%',
      left: tick.percent + '%'
    };
  } else if (axis === 'y') {
    top.style = {
      top: tick.percent + '%'
    };
    bottom.style = {
      top: tick.percent + '%'
    };
  }
  return _react2.default.createElement(
    _react2.default.Fragment,
    null,
    _react2.default.createElement('div', _extends({ className: 'ma__slider-tick ma__slider-tick--top' }, top)),
    _react2.default.createElement(
      'div',
      _extends({ className: 'ma__slider-tick ma__slider-tick--bottom' }, bottom),
      _react2.default.createElement(
        'label',
        { htmlFor: id },
        tick.value
      )
    )
  );
};

Tick.propTypes = process.env.NODE_ENV !== "production" ? {
  tick: {
    percent: _propTypes2.default.string,
    value: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.number])
  },
  count: _propTypes2.default.number,
  getTrackProps: _propTypes2.default.func,
  id: _propTypes2.default.string,
  axis: _propTypes2.default.string
} : {};

var CompoundSlider = function (_Component) {
  _inherits(CompoundSlider, _Component);

  function CompoundSlider() {
    _classCallCheck(this, CompoundSlider);

    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
  }

  CompoundSlider.prototype.render = function render() {
    var _this2 = this;

    return _react2.default.createElement(
      _context.InputContext.Consumer,
      null,
      function (context) {
        var _props = _this2.props,
            min = _props.min,
            max = _props.max,
            step = _props.step,
            disabled = _props.disabled,
            domain = _props.domain,
            onChange = _props.onChange,
            onUpdate = _props.onUpdate;

        var decimalPlaces = (0, _utility.countDecimals)(step);
        var handleChange = function handleChange(values) {
          var value = Number.isInteger(step) ? values[0] : Number(Number.parseFloat(values[0]).toFixed(decimalPlaces));
          context.updateState({ value: value }, function () {
            if (typeof onChange === 'function') {
              onChange(value, _this2.props.id);
            }
          });
        };
        var handleUpdate = function handleUpdate(values) {
          var value = Number.isInteger(step) ? values[0] : Number(Number.parseFloat(values[0]).toFixed(decimalPlaces));
          context.updateState({ value: value }, function () {
            if (typeof onUpdate === 'function') {
              onUpdate(value, _this2.props.id);
            }
          });
        };
        var domainCheck = function domainCheck(valToCheck) {
          var minCheck = Number(min);
          var maxCheck = Number(max);
          if (Number.isNaN(valToCheck)) {
            return Number.isInteger(step) ? minCheck : Number(Number.parseFloat(minCheck).toFixed(decimalPlaces));
          }
          var returnValue = valToCheck;
          var domainMin = domain[0],
              domainMax = domain[1];
          // If the min/max passed falls outside of the domain, set it to the respective domain min/max.

          if (Number.isNaN(minCheck) || Math.abs(minCheck - domainMax) > Math.abs(domainMin - domainMax)) {
            minCheck = domainMin;
          }
          if (Number.isNaN(maxCheck) || Math.abs(maxCheck - domainMin) > Math.abs(domainMin - domainMax)) {
            maxCheck = domainMax;
          }
          // Ensure the value is always between the min or max values, if any.
          if (valToCheck < minCheck) {
            returnValue = minCheck;
          }
          if (valToCheck > maxCheck) {
            returnValue = maxCheck;
          }
          return Number.isInteger(step) ? returnValue : Number(Number.parseFloat(returnValue).toFixed(decimalPlaces));
        };
        // Anything returned by mode when set to a function will become the value.
        // This can be used for min/max validation.
        // Next and current values are not numbers, but arrays of objects.
        var handleMode = function handleMode(current, next) {
          var nextValue = next[0].val;

          var checkValue = Number.isInteger(step) ? nextValue : Number(Number.parseFloat(nextValue).toFixed(decimalPlaces));
          if (checkValue === domainCheck(nextValue)) {
            return next;
          }
          return current;
        };
        var defaultValue = domainCheck(Number(context.getValue()));
        var sliderProps = {
          domain: domain,
          step: step,
          vertical: !(_this2.props.axis === 'x'),
          onChange: handleChange,
          values: [defaultValue],
          mode: handleMode,
          disabled: disabled
        };
        if (onUpdate) {
          sliderProps.onUpdate = handleUpdate;
        }
        var wrapperClasses = (0, _classnames2.default)({
          'ma__input-slider': true,
          'ma__input-slider--disabled': disabled,
          'ma__input-slider-x': _this2.props.axis === 'x',
          'ma__input-slider-y': _this2.props.axis === 'y'
        });
        return _react2.default.createElement(
          'div',
          { id: _this2.props.id, className: wrapperClasses },
          _react2.default.createElement(
            _reactCompoundSlider.Slider,
            _extends({ className: 'ma__slider' }, sliderProps),
            _react2.default.createElement(
              _reactCompoundSlider.Rail,
              null,
              function (_ref) {
                var getRailProps = _ref.getRailProps;
                return _react2.default.createElement('div', _extends({ className: 'ma__slider-rail' }, getRailProps()));
              }
            ),
            _react2.default.createElement(
              _reactCompoundSlider.Handles,
              null,
              function (_ref2) {
                var handles = _ref2.handles,
                    activeHandleID = _ref2.activeHandleID,
                    getHandleProps = _ref2.getHandleProps;
                return _react2.default.createElement(
                  'div',
                  { className: 'slider-handles' },
                  handles.map(function (handle) {
                    return _react2.default.createElement(Handle, {
                      key: handle.id,
                      handle: handle,
                      getHandleProps: getHandleProps,
                      isActive: handle.id === activeHandleID,
                      axis: _this2.props.axis,
                      min: min,
                      max: max,
                      step: step,
                      displayValueFormat: _this2.props.displayValueFormat,
                      disabled: disabled
                    });
                  })
                );
              }
            ),
            _react2.default.createElement(
              _reactCompoundSlider.Tracks,
              { right: false },
              function (_ref3) {
                var tracks = _ref3.tracks,
                    getTrackProps = _ref3.getTrackProps;
                return _react2.default.createElement(
                  'div',
                  { className: 'slider-tracks' },
                  tracks.map(function (_ref4) {
                    var id = _ref4.id,
                        source = _ref4.source,
                        target = _ref4.target;
                    return _react2.default.createElement(Track, {
                      key: id,
                      source: source,
                      target: target,
                      getTrackProps: getTrackProps,
                      axis: _this2.props.axis
                    });
                  })
                );
              }
            ),
            _react2.default.createElement(
              _reactCompoundSlider.Ticks,
              { values: Array.from(_this2.props.ticks.keys()) },
              function (_ref5) {
                var ticks = _ref5.ticks;

                var ticksLength = ticks.length;
                // Placing this check here because Slider can't handle null children but Ticks can.
                if (ticksLength > 0) {
                  return _react2.default.createElement(
                    'div',
                    { className: 'slider-ticks' },
                    ticks.map(function (oldTick) {
                      var tick = _extends({}, oldTick, {
                        value: _this2.props.ticks.get(oldTick.value)
                      });
                      var tickProps = {
                        key: 'CompoundSlider.tick.' + tick.value,
                        count: ticksLength,
                        tick: tick,
                        axis: _this2.props.axis,
                        id: _this2.props.id
                      };
                      return _react2.default.createElement(Tick, tickProps);
                    })
                  );
                }
                return null;
              }
            )
          )
        );
      }
    );
  };

  return CompoundSlider;
}(_react.Component);

CompoundSlider.propTypes = process.env.NODE_ENV !== "production" ? {
  /** The unique ID for the input field */
  id: _propTypes2.default.string.isRequired,
  /** Custom update function, triggered with the values on drag (caution: high-volume updates when dragging). Only if a function is passed to onUpdate will form context get updated on drag. */
  onUpdate: _propTypes2.default.func,
  /** Custom on change function, triggered when the value of the slider has changed. This will recieve changes at the end of a slide as well as changes from clicks on rails and tracks. */
  onChange: _propTypes2.default.func,
  /** Default input text value */
  defaultValue: _propTypes2.default.string,
  /** Max value for the field. */
  max: _propTypes2.default.number.isRequired,
  /** Min value for the field. */
  min: _propTypes2.default.number.isRequired,
  /** This controls how much sliding the handle increments/decrements the value of the slider. */
  step: _propTypes2.default.number,
  /** A Map object where each entry is a key (number inclusively between min and max) and value (label to display at the key) pair for displaying tick marks. */
  ticks: _propTypes2.default.instanceOf(Map),
  /** The direction for the slider, where x is horizontal and y is vertical. */
  axis: _propTypes2.default.oneOf(['x', 'y']),
  /** Disables the slider if true. */
  disabled: _propTypes2.default.bool,
  /** The range of numbers, inclusively, for the slider to fall between. First number is the min and second number is the max. */
  domain: _propTypes2.default.arrayOf(_propTypes2.default.number),
  /** Display the value of the slider based. If null, don't display. If equals percentage, format the value in percentage. */
  displayValueFormat: _propTypes2.default.oneOf(['percentage', 'value', null])
} : {};

CompoundSlider.defaultProps = {
  ticks: new Map(),
  domain: [0, 1]
};

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