import _objectSpread from "@babel/runtime/helpers/objectSpread2";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _get from "@babel/runtime/helpers/get";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
import _createSuper from "@babel/runtime/helpers/createSuper";
import { __decorate } from "tslib";
import React from 'react';
import { observer } from 'mobx-react';
import { action, observable, runInAction } from 'mobx';
import isNil from 'lodash/isNil';
import Spin from '../../../es/spin';
import KeyCode from '../../../es/_util/KeyCode';
import { FieldTrim } from '../data-set/enum';
import TextArea from '../text-area';
import autobind from '../_util/autobind';
import KeywordTrigger from './KeywordTrigger';
import { MentionsContextProvider } from './MentionsContext';
import Option from './Option';
import { filterOption as defaultFilterOption, getBeforeSelectionText, getLastMeasureIndex, replaceWithMeasure, setInputSelection, validateSearch as defaultValidateSearch, toArray } from './utils';

var Mentions = /*#__PURE__*/function (_TextArea) {
  _inherits(Mentions, _TextArea);

  var _super = _createSuper(Mentions);

  function Mentions(props, context) {
    var _this;

    _classCallCheck(this, Mentions);

    _this = _super.call(this, props, context);
    _this.focusId = undefined;
    _this.selectionLocation = -1;

    _this.initObservableObj();

    return _this;
  }

  _createClass(Mentions, [{
    key: "initObservableObj",
    value: function initObservableObj() {
      this.measuring = false;
      this.measureLocation = 0;
      this.measureText = null;
      this.measurePrefix = '';
      this.activeIndex = 0;
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate() {
      _get(_getPrototypeOf(Mentions.prototype), "componentDidUpdate", this).call(this); // Sync measure div top with textarea for trigger usage


      if (this.measuring && this.measure && this.element) {
        this.measure.scrollTop = this.element.scrollTop;
      } // 选择选项后设置输入框光标位置


      if (this.selectionLocation !== -1 && this.element) {
        setInputSelection(this.element, this.selectionLocation);
        this.selectionLocation = -1;
      }
    }
  }, {
    key: "getNotFoundContent",
    value: function getNotFoundContent() {
      if ('notFoundContent' in this.props) {
        return this.props.notFoundContent;
      }

      return this.getContextConfig('renderEmpty')('Select');
    }
  }, {
    key: "getOtherProps",
    value: function getOtherProps() {
      var otherProps = _get(_getPrototypeOf(Mentions.prototype), "getOtherProps", this).call(this);

      otherProps.onKeyUp = this.handleKeyUp;
      return otherProps;
    }
  }, {
    key: "getOmitPropsKeys",
    value: function getOmitPropsKeys() {
      return _get(_getPrototypeOf(Mentions.prototype), "getOmitPropsKeys", this).call(this).concat(['notFoundContent', 'split', 'transitionName', 'placement', 'prefix', 'validateSearch', 'filterOption', 'onSelect', 'onSearch', 'getPopupContainer', 'loading', 'mentionsKey']);
    }
  }, {
    key: "select",
    value: function select() {// noop
    } // Check if hit the measure keyword

  }, {
    key: "handleKeyDown",
    value: function handleKeyDown(event) {
      var _this2 = this;

      var which = event.which;
      var activeIndex = this.activeIndex,
          measuring = this.measuring; // Skip if not measuring

      if (!measuring) {
        _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event);

        return;
      }

      if (which === KeyCode.UP || which === KeyCode.DOWN) {
        // Control arrow function
        var optionLen = this.getOptions().length;
        var offset = which === KeyCode.UP ? -1 : 1;
        var newActiveIndex = (activeIndex + offset + optionLen) % optionLen;
        runInAction(function () {
          _this2.activeIndex = newActiveIndex;
        });
        event.preventDefault();
      } else if (which === KeyCode.ESC) {
        this.stopMeasure();
      } else if (which === KeyCode.ENTER) {
        // Measure hit
        event.preventDefault();
        var options = this.getOptions();

        if (!options.length) {
          this.stopMeasure();

          _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event);

          return;
        }

        var option = options[activeIndex];
        this.selectOption(option);
      }

      _get(_getPrototypeOf(Mentions.prototype), "handleKeyDown", this).call(this, event);
    }
    /**
     * When to start measure:
     * 1. When user press `mentionsKey`
     * 2. When measureText !== prevMeasureText
     *  - If measure hit
     *  - If measuring
     *
     * When to stop measure:
     * 1. Selection is out of range
     * 2. Contains `space`
     * 3. ESC or select one
     */

  }, {
    key: "handleKeyUp",
    value: function handleKeyUp(event) {
      var key = event.key,
          which = event.which;
      var prevMeasureText = this.measureText,
          measuring = this.measuring;
      var _this$props = this.props,
          _this$props$mentionsK = _this$props.mentionsKey,
          mentionsKey = _this$props$mentionsK === void 0 ? '' : _this$props$mentionsK,
          clientOnKeyUp = _this$props.onKeyUp,
          onSearch = _this$props.onSearch,
          validateSearch = _this$props.validateSearch;
      var target = event.target;
      var selectionStartText = getBeforeSelectionText(target);

      var _getLastMeasureIndex = getLastMeasureIndex(selectionStartText, mentionsKey),
          measureIndex = _getLastMeasureIndex.location,
          measurePrefix = _getLastMeasureIndex.mentionsKey; // If the client implements an onKeyUp handler, call it


      if (clientOnKeyUp) {
        clientOnKeyUp(event);
      } // Skip if match the white key list


      if ([KeyCode.ESC, KeyCode.UP, KeyCode.DOWN, KeyCode.ENTER].indexOf(which) !== -1) {
        return;
      }

      if (measureIndex !== -1) {
        var measureText = selectionStartText.slice(measureIndex + measurePrefix.length);
        var validateMeasure = validateSearch ? validateSearch(measureText, this.props) : false;
        var matchOption = !!this.getOptions(measureText).length;

        if (validateMeasure) {
          if (key === measurePrefix || key === 'Shift' || measuring || measureText !== prevMeasureText && matchOption) {
            this.startMeasure(measureText, measurePrefix, measureIndex);
          }
        } else if (measuring) {
          // Stop if measureText is invalidate
          this.stopMeasure();
        }
        /**
         * We will trigger `onSearch` to developer since they may use for async update.
         * If met `space` means user finished searching.
         */


        if (onSearch && validateMeasure) {
          onSearch(measureText, measurePrefix);
        }
      } else if (measuring) {
        this.stopMeasure();
      }
    }
  }, {
    key: "onDropdownFocus",
    value: function onDropdownFocus() {
      this.handleFocus();
    }
  }, {
    key: "onDropdownBlur",
    value: function onDropdownBlur() {
      this.handleBlur();
    }
  }, {
    key: "handleFocus",
    value: function handleFocus(event) {
      window.clearTimeout(this.focusId);

      if (event) {
        _get(_getPrototypeOf(Mentions.prototype), "handleFocus", this).call(this, event);
      }
    }
  }, {
    key: "handleBlur",
    value: function handleBlur(event) {
      var _this3 = this;

      this.focusId = window.setTimeout(function () {
        _this3.stopMeasure();
      }, 0);

      if (event) {
        _get(_getPrototypeOf(Mentions.prototype), "handleBlur", this).call(this, event);
      }
    }
  }, {
    key: "selectOption",
    value: function selectOption(option) {
      var measureLocation = this.measureLocation,
          measurePrefix = this.measurePrefix;
      var value = isNil(this.text) ? this.getValue() : this.text;
      value = isNil(value) ? '' : value;
      var _this$props2 = this.props,
          split = _this$props2.split,
          onSelect = _this$props2.onSelect;
      var _option$value = option.value,
          mentionValue = _option$value === void 0 ? '' : _option$value;

      var _replaceWithMeasure = replaceWithMeasure(value, {
        measureLocation: measureLocation,
        targetText: mentionValue,
        mentionsKey: measurePrefix,
        selectionStart: this.element ? this.element.selectionStart : -1,
        split: String(split || '')
      }),
          text = _replaceWithMeasure.text,
          selectionLocation = _replaceWithMeasure.selectionLocation;

      this.selectionLocation = selectionLocation;
      this.prepareSetValue(text);
      this.stopMeasure();

      if (onSelect) {
        onSelect(option, measurePrefix);
      }
    }
  }, {
    key: "setActiveIndex",
    value: function setActiveIndex(activeIndex) {
      this.activeIndex = activeIndex;
    }
  }, {
    key: "setMeasureRef",
    value: function setMeasureRef(element) {
      this.measure = element;
    }
  }, {
    key: "getOptions",
    value: function getOptions(measureText) {
      var targetMeasureText = measureText || this.measureText || '';
      var _this$props3 = this.props,
          children = _this$props3.children,
          filterOption = _this$props3.filterOption,
          loading = _this$props3.loading;

      if (loading) {
        return [{
          key: 'loading',
          children: /*#__PURE__*/React.createElement(Spin, null),
          disabled: true,
          style: {
            minWidth: '0.8rem',
            display: 'flex',
            justifyContent: 'center'
          }
        }];
      }

      var list = toArray(children).map(function (_ref) {
        var props = _ref.props,
            key = _ref.key;
        return _objectSpread(_objectSpread({}, props), {}, {
          key: key || props.value
        });
      }).filter(function (option) {
        /** Return all result if `filterOption` is false. */
        if (filterOption === false) {
          return true;
        }

        return filterOption ? filterOption(targetMeasureText, option) : true;
      });
      return list;
    }
  }, {
    key: "startMeasure",
    value: function startMeasure(measureText, measurePrefix, measureLocation) {
      this.measuring = true;
      this.measureText = measureText;
      this.measurePrefix = measurePrefix;
      this.measureLocation = measureLocation;
      this.activeIndex = 0;
    }
  }, {
    key: "stopMeasure",
    value: function stopMeasure() {
      this.measuring = false;
      this.measureLocation = 0;
      this.measureText = null;
    }
  }, {
    key: "wrapperInputNode",
    value: function wrapperInputNode() {
      var measureLocation = this.measureLocation,
          measurePrefix = this.measurePrefix,
          measuring = this.measuring,
          activeIndex = this.activeIndex,
          prefixCls = this.prefixCls;
      var value = isNil(this.text) ? this.getValue() : this.text;
      var _this$props4 = this.props,
          placement = _this$props4.placement,
          transitionName = _this$props4.transitionName,
          getPopupContainer = _this$props4.getPopupContainer;
      var options = measuring ? this.getOptions() : [];
      var renderedValue = this.renderRenderedValue(undefined, {});
      return /*#__PURE__*/React.createElement(React.Fragment, null, _get(_getPrototypeOf(Mentions.prototype), "wrapperInputNode", this).call(this, renderedValue), measuring && /*#__PURE__*/React.createElement("div", {
        ref: this.setMeasureRef,
        className: "".concat(prefixCls, "-measure")
      }, value.slice(0, measureLocation), /*#__PURE__*/React.createElement(MentionsContextProvider, {
        value: {
          notFoundContent: this.getNotFoundContent(),
          activeIndex: activeIndex,
          setActiveIndex: this.setActiveIndex,
          selectOption: this.selectOption,
          onFocus: this.onDropdownFocus,
          onBlur: this.onDropdownBlur
        }
      }, /*#__PURE__*/React.createElement(KeywordTrigger, {
        prefixCls: prefixCls,
        transitionName: transitionName,
        placement: placement,
        options: options,
        visible: true,
        getPopupContainer: getPopupContainer
      }, /*#__PURE__*/React.createElement("span", null, measurePrefix))), value.slice(measureLocation + measurePrefix.length)));
    }
  }]);

  return Mentions;
}(TextArea);

Mentions.displayName = 'Mentions';
Mentions.Option = Option;
Mentions.defaultProps = _objectSpread(_objectSpread({}, TextArea.defaultProps), {}, {
  suffixCls: 'mentions',
  rows: 1,
  trim: FieldTrim.left,
  mentionsKey: '@',
  split: ' ',
  validateSearch: defaultValidateSearch,
  filterOption: defaultFilterOption
});

__decorate([observable], Mentions.prototype, "measuring", void 0);

__decorate([observable], Mentions.prototype, "measureText", void 0);

__decorate([observable], Mentions.prototype, "measurePrefix", void 0);

__decorate([observable], Mentions.prototype, "measureLocation", void 0);

__decorate([observable], Mentions.prototype, "activeIndex", void 0);

__decorate([action], Mentions.prototype, "initObservableObj", null);

__decorate([autobind], Mentions.prototype, "handleKeyDown", null);

__decorate([autobind], Mentions.prototype, "handleKeyUp", null);

__decorate([autobind], Mentions.prototype, "onDropdownFocus", null);

__decorate([autobind], Mentions.prototype, "onDropdownBlur", null);

__decorate([autobind], Mentions.prototype, "handleFocus", null);

__decorate([autobind], Mentions.prototype, "handleBlur", null);

__decorate([autobind], Mentions.prototype, "selectOption", null);

__decorate([autobind, action], Mentions.prototype, "setActiveIndex", null);

__decorate([autobind], Mentions.prototype, "setMeasureRef", null);

__decorate([action], Mentions.prototype, "startMeasure", null);

__decorate([action], Mentions.prototype, "stopMeasure", null);

Mentions = __decorate([observer], Mentions);

Mentions.getMentions = function () {
  var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  var _config$mentionsKey = config.mentionsKey,
      mentionsKey = _config$mentionsKey === void 0 ? '@' : _config$mentionsKey,
      _config$split = config.split,
      split = _config$split === void 0 ? ' ' : _config$split;
  var prefixList = Array.isArray(mentionsKey) ? mentionsKey : [mentionsKey];
  return value.split(split).map(function () {
    var str = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
    var hitPrefix = null;
    prefixList.some(function (prefixStr) {
      var startStr = str.slice(0, prefixStr.length);

      if (startStr === prefixStr) {
        hitPrefix = prefixStr;
        return true;
      }

      return false;
    });

    if (hitPrefix !== null) {
      return {
        mentionsKey: hitPrefix,
        value: str.slice(hitPrefix.length)
      };
    }

    return null;
  }).filter(function (entity) {
    return !!entity && !!entity.value;
  });
};

export default Mentions;
//# sourceMappingURL=Mentions.js.map
