'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 _reactAutosuggest = require('react-autosuggest');

var _reactAutosuggest2 = _interopRequireDefault(_reactAutosuggest);

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

var _propTypes2 = _interopRequireDefault(_propTypes);

var _fuse = require('fuse.js');

var _fuse2 = _interopRequireDefault(_fuse);

var _parse = require('autosuggest-highlight/parse');

var _parse2 = _interopRequireDefault(_parse);

var _classnames = require('classnames');

var _classnames2 = _interopRequireDefault(_classnames);

var _is = require('is');

var _is2 = _interopRequireDefault(_is);

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 InputTextFuzzy = function (_React$Component) {
  _inherits(InputTextFuzzy, _React$Component);

  function InputTextFuzzy(props) {
    _classCallCheck(this, InputTextFuzzy);

    var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));

    _this.onSuggestionsFetchRequested = function (_ref) {
      var value = _ref.value;

      var suggestions = _is2.default.empty(value) ? _this.optionsToSuggestions(_this.props.options) : _this.fuse.search(value);
      _this.setState({
        suggestions: suggestions
      });
    };

    _this.onSuggestionsClearRequested = function () {
      _this.setState({
        suggestions: []
      });
    };

    _this.onSuggestionSelected = function (event, _ref2) {
      var suggestion = _ref2.suggestion,
          method = _ref2.method;

      // invokes custom function if passed in the component
      if (_is2.default.fn(_this.props.onSuggestionClick)) {
        event.persist();
        // Suggestion is an object that can contain info on score, matches, etc.
        _this.props.onSuggestionClick(event, { suggestion: suggestion, method: method });
      }
    };

    _this.getSuggestionValue = function (suggestion) {
      return suggestion.item.text;
    };

    _this.handleChange = function (event, _ref3) {
      var newValue = _ref3.newValue,
          method = _ref3.method;

      if (event && event.persist()) {
        event.persist();
      }

      var value = newValue;
      _this.setState({
        value: value
      }, function () {
        if (_is2.default.fn(_this.props.onChange)) {
          _this.props.onChange({
            event: event, method: method, value: value, suggestions: _this.state.suggestions
          });
        }
      });
    };

    _this.handleBlur = function (event) {
      if (_is2.default.fn(_this.props.onBlur)) {
        if (event && event.persist()) {
          event.persist();
        }
        _this.props.onBlur({ event: event, value: _this.state.value, suggestions: _this.state.suggestions });
      }
    };

    _this.handleKeyPress = function (event) {
      var value = _this.state.value;

      if (event.key === 'Enter') {
        event.persist();
        event.preventDefault();
        if (_is2.default.fn(_this.props.onSuggestionClick)) {
          _this.props.onSuggestionClick(event, { method: 'enter', suggestion: { item: { text: value } } });
        }
      }
    };

    _this.handleFocus = function (event) {
      if (_is2.default.fn(_this.props.onFocus)) {
        event.persist();
        _this.props.onFocus({ event: event, value: _this.state.value, suggestions: _this.state.suggestions });
      }
    };

    _this.optionsToSuggestions = function (options) {
      var suggestions = options.map(function (item) {
        return {
          item: {
            text: item.text,
            value: item.value
          },
          matches: [{
            indices: [],
            value: item.text,
            key: 'text',
            arrayIndex: 0
          }]
        };
      });
      return suggestions;
    };

    _this.shouldRenderSuggestions = function (value) {
      return _this.props.renderDefaultSuggestion === true ? value.trim().length >= 0 : value.trim().length > 0;
    };

    _this.renderItem = function (suggestion) {
      var item = suggestion.item,
          matches = suggestion.matches;

      var renderItems = [];
      if (_is2.default.empty(_this.state.value)) {
        renderItems = _this.props.keys.map(function (key) {
          return _react2.default.createElement(
            'span',
            { key: key + '.suggestion_' + item.optionIndex },
            item[key]
          );
        });
      } else {
        matches.forEach(function (match) {
          if (_this.props.keys.indexOf(match.key) > -1) {
            // Add one to each range to get a proper highlight match.
            var ranges = match.indices.map(function (range) {
              var start = range[0],
                  end = range[1];

              return [start, Number(end) + 1];
            });
            var parts = (0, _parse2.default)(match.value, ranges);
            renderItems = parts.filter(function (part) {
              return part.text.length > 0;
            }).map(function (part, index) {
              var className = part.highlight === true ? 'highlight' : null;
              var key = match.key + '.suggestion_' + index;
              return _react2.default.createElement(
                'span',
                { className: className, key: key },
                part.text
              );
            });
          }
        });
      }
      return _react2.default.createElement(
        'span',
        { className: 'ma__suggestion-content' },
        _react2.default.createElement(
          'span',
          { className: 'ma__suggestion-content-name' },
          renderItems
        )
      );
    };

    _this.renderItemsContainer = function (_ref4) {
      var children = _ref4.children,
          containerProps = _ref4.containerProps;
      return _react2.default.createElement(
        'div',
        _extends({ className: 'ma__input-fuzzy' }, containerProps),
        children
      );
    };

    _this.state = {
      value: _this.props.selected || '',
      suggestions: []
    };
    var fuseOptions = _this.props.fuseOptions;
    fuseOptions.keys = _this.props.keys;
    _this.fuse = new _fuse2.default(_this.props.options, fuseOptions);
    return _this;
  }
  // handleChange and onSuggestionSelected both do not fire when enter is hit.
  // This is a workaround for that. Use handleChange for keyboard presses.


  InputTextFuzzy.prototype.render = function render() {
    var autoProps = {
      suggestions: this.state.suggestions,
      renderSuggestionsContainer: this.renderItemsContainer,
      renderSuggestion: this.renderItem,
      onSuggestionsFetchRequested: this.onSuggestionsFetchRequested,
      onSuggestionsClearRequested: this.onSuggestionsClearRequested,
      getSuggestionValue: this.getSuggestionValue,
      shouldRenderSuggestions: this.shouldRenderSuggestions,
      onSuggestionSelected: this.onSuggestionSelected,
      focusInputOnSuggestionClick: false,
      inputProps: {
        type: 'search',
        placeholder: this.props.placeholder,
        onChange: this.handleChange,
        value: this.state.value,
        disabled: this.props.disabled,
        id: this.props.inputId,
        onFocus: this.handleFocus,
        autoFocus: this.props.autoFocusInput,
        onBlur: this.handleBlur,
        onKeyPress: this.handleKeyPress
      },
      id: this.props.id
    };

    var inputTextTypeAheadClasses = (0, _classnames2.default)({
      'ma__input-typeahead': true,
      'ma__input-typeahead--disabled': this.props.disabled,
      'ma__input-typeahead--boxed': this.props.boxed
    });
    return _react2.default.createElement(
      _react2.default.Fragment,
      null,
      this.props.label && _react2.default.createElement(
        'label',
        { htmlFor: this.props.inputId, className: 'ma__label' },
        this.props.label
      ),
      _react2.default.createElement(
        'div',
        { className: inputTextTypeAheadClasses },
        _react2.default.createElement(_reactAutosuggest2.default, autoProps)
      )
    );
  };

  return InputTextFuzzy;
}(_react2.default.Component);

InputTextFuzzy.propTypes = process.env.NODE_ENV !== "production" ? {
  /** The id of the typeahead element. */
  id: _propTypes2.default.string.isRequired,
  /** The label text above the input text box. */
  label: _propTypes2.default.string,
  /** The placeholder text to appear in the input text box. */
  placeholder: _propTypes2.default.string,
  /** Style the input with a box outline. */
  boxed: _propTypes2.default.bool,
  /** The keys within options to use with search. */
  keys: _propTypes2.default.arrayOf(_propTypes2.default.string).isRequired,
  /** An array of objects representing all searchable values. */
  options: _propTypes2.default.arrayOf(_propTypes2.default.object).isRequired,
  /** Any Fusejs options to override the default options set in this component. */
  /* eslint-disable-next-line  react/forbid-prop-types */
  fuseOptions: _propTypes2.default.object,
  /** Disables input. */
  disabled: _propTypes2.default.bool,
  /** Function that runs after changes to the input happen. */
  onChange: _propTypes2.default.func,
  onFocus: _propTypes2.default.func,
  onBlur: _propTypes2.default.func,
  /** Function that runs after a suggestion has been clicked. */
  onSuggestionClick: _propTypes2.default.func,
  /** The default value for the select box. */
  selected: _propTypes2.default.string,
  /** The id of the the input tag */
  inputId: _propTypes2.default.string,
  /** By default all options will be rendered as suggestions on input focus */
  renderDefaultSuggestion: _propTypes2.default.bool,
  /** Focus on typeahead input */
  autoFocusInput: _propTypes2.default.bool
} : {};

InputTextFuzzy.defaultProps = {
  fuseOptions: {
    /** Set the result list to sort by score. */
    shouldSort: true,
    /** Prevents matching from stopping at the first match found. */
    findAllMatches: true,
    /** Lets the matches found be included in the result set. */
    includeMatches: true,
    /** Match sensitivity. 0 means what's been typed must be a perfect match, 1 means anything typed matches. */
    threshold: 0.3,
    /** Prevents matches against empty strings. */
    minMatchCharLength: 1,
    /** Allows more characters for long queries. */
    maxPatternLength: 300
  },
  autoFocusInput: false,
  disabled: false,
  boxed: false,
  renderDefaultSuggestion: true
};

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