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

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import numbro from 'numbro';
import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider';
import { InputContext } from '../Input/context';
import { countDecimals } from '../Input/utility';
import './style.css';

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 = 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 React.createElement(
    'button',
    _extends({ className: 'ma__slider-handle' }, divProps),
    displayValueFormat && React.createElement(
      'div',
      { className: 'ma__slider-handle-value' },
      displayValueFormat === 'percentage' ? numbro(value).format({ output: 'percent', mantissa: 0 }) : roundedValue
    )
  );
};

Handle.propTypes = process.env.NODE_ENV !== "production" ? {
  handle: {
    id: PropTypes.string,
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    percent: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
  },
  getHandleProps: PropTypes.func,
  axis: PropTypes.string,
  min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  displayValueFormat: PropTypes.string,
  disabled: PropTypes.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 React.createElement('div', _extends({ className: 'ma__slider-track' }, divProps));
};

Track.propTypes = process.env.NODE_ENV !== "production" ? {
  source: {
    percent: PropTypes.string
  },
  target: {
    percent: PropTypes.string
  },
  getTrackProps: PropTypes.func,
  axis: PropTypes.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 React.createElement(
    React.Fragment,
    null,
    React.createElement('div', _extends({ className: 'ma__slider-tick ma__slider-tick--top' }, top)),
    React.createElement(
      'div',
      _extends({ className: 'ma__slider-tick ma__slider-tick--bottom' }, bottom),
      React.createElement(
        'label',
        { htmlFor: id },
        tick.value
      )
    )
  );
};

Tick.propTypes = process.env.NODE_ENV !== "production" ? {
  tick: {
    percent: PropTypes.string,
    value: PropTypes.oneOfType([PropTypes.string, PropTypes.number])
  },
  count: PropTypes.number,
  getTrackProps: PropTypes.func,
  id: PropTypes.string,
  axis: PropTypes.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 React.createElement(
      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 = 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 = classNames({
          '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 React.createElement(
          'div',
          { id: _this2.props.id, className: wrapperClasses },
          React.createElement(
            Slider,
            _extends({ className: 'ma__slider' }, sliderProps),
            React.createElement(
              Rail,
              null,
              function (_ref) {
                var getRailProps = _ref.getRailProps;
                return React.createElement('div', _extends({ className: 'ma__slider-rail' }, getRailProps()));
              }
            ),
            React.createElement(
              Handles,
              null,
              function (_ref2) {
                var handles = _ref2.handles,
                    activeHandleID = _ref2.activeHandleID,
                    getHandleProps = _ref2.getHandleProps;
                return React.createElement(
                  'div',
                  { className: 'slider-handles' },
                  handles.map(function (handle) {
                    return React.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
                    });
                  })
                );
              }
            ),
            React.createElement(
              Tracks,
              { right: false },
              function (_ref3) {
                var tracks = _ref3.tracks,
                    getTrackProps = _ref3.getTrackProps;
                return React.createElement(
                  'div',
                  { className: 'slider-tracks' },
                  tracks.map(function (_ref4) {
                    var id = _ref4.id,
                        source = _ref4.source,
                        target = _ref4.target;
                    return React.createElement(Track, {
                      key: id,
                      source: source,
                      target: target,
                      getTrackProps: getTrackProps,
                      axis: _this2.props.axis
                    });
                  })
                );
              }
            ),
            React.createElement(
              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 React.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 React.createElement(Tick, tickProps);
                    })
                  );
                }
                return null;
              }
            )
          )
        );
      }
    );
  };

  return CompoundSlider;
}(Component);

CompoundSlider.propTypes = process.env.NODE_ENV !== "production" ? {
  /** The unique ID for the input field */
  id: PropTypes.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: PropTypes.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: PropTypes.func,
  /** Default input text value */
  defaultValue: PropTypes.string,
  /** Max value for the field. */
  max: PropTypes.number.isRequired,
  /** Min value for the field. */
  min: PropTypes.number.isRequired,
  /** This controls how much sliding the handle increments/decrements the value of the slider. */
  step: PropTypes.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: PropTypes.instanceOf(Map),
  /** The direction for the slider, where x is horizontal and y is vertical. */
  axis: PropTypes.oneOf(['x', 'y']),
  /** Disables the slider if true. */
  disabled: PropTypes.bool,
  /** The range of numbers, inclusively, for the slider to fall between. First number is the min and second number is the max. */
  domain: PropTypes.arrayOf(PropTypes.number),
  /** Display the value of the slider based. If null, don't display. If equals percentage, format the value in percentage. */
  displayValueFormat: PropTypes.oneOf(['percentage', 'value', null])
} : {};

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

export default CompoundSlider;