text: "use strict";
  /*
   * Copyright 2017 Palantir Technologies, Inc. All rights reserved.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.TagInput = void 0;
  var tslib_1 = require("tslib");
  var classnames_1 = tslib_1.__importDefault(require("classnames"));
  var React = tslib_1.__importStar(require("react"));
  var react_lifecycles_compat_1 = require("react-lifecycles-compat");
  var common_1 = require("../../common");
  var props_1 = require("../../common/props");
  var icon_1 = require("../icon/icon");
  var tag_1 = require("../tag/tag");
  /** special value for absence of active tag */
  var NONE = -1;
  var TagInput = /** @class */ (function (_super) {
      tslib_1.__extends(TagInput, _super);
      function TagInput() {
          var _this = _super !== null && _super.apply(this, arguments) || this;
          _this.state = {
              activeIndex: NONE,
              inputValue: _this.props.inputValue || "",
              isInputFocused: false,
          };
          _this.refHandlers = {
              input: function (ref) {
                  _this.inputElement = ref;
                  common_1.Utils.safeInvoke(_this.props.inputRef, ref);
              },
          };
          _this.addTags = function (value, method) {
              if (method === void 0) { method = "default"; }
              var _a = _this.props, inputValue = _a.inputValue, onAdd = _a.onAdd, onChange = _a.onChange, values = _a.values;
              var newValues = _this.getValues(value);
              var shouldClearInput = common_1.Utils.safeInvoke(onAdd, newValues, method) !== false && inputValue === undefined;
              // avoid a potentially expensive computation if this prop is omitted
              if (common_1.Utils.isFunction(onChange)) {
                  shouldClearInput = onChange(tslib_1.__spreadArrays(values, newValues)) !== false && shouldClearInput;
              }
              // only explicit return false cancels text clearing
              if (shouldClearInput) {
                  _this.setState({ inputValue: "" });
              }
          };
          _this.maybeRenderTag = function (tag, index) {
              if (!tag) {
                  return null;
              }
              var _a = _this.props, large = _a.large, tagProps = _a.tagProps;
              var props = common_1.Utils.isFunction(tagProps) ? tagProps(tag, index) : tagProps;
              return (React.createElement(tag_1.Tag, tslib_1.__assign({ active: index === _this.state.activeIndex, "data-tag-index": index, key: tag + "__" + index, large: large, onRemove: _this.props.disabled ? null : _this.handleRemoveTag }, props), tag));
          };
          _this.handleContainerClick = function () {
              if (_this.inputElement != null) {
                  _this.inputElement.focus();
              }
          };
          _this.handleContainerBlur = function (_a) {
              var currentTarget = _a.currentTarget;
              requestAnimationFrame(function () {
                  // we only care if the blur event is leaving the container.
                  // defer this check using rAF so activeElement will have updated.
                  if (!currentTarget.contains(document.activeElement)) {
                      if (_this.props.addOnBlur && _this.state.inputValue !== undefined && _this.state.inputValue.length > 0) {
                          _this.addTags(_this.state.inputValue, "blur");
                      }
                      _this.setState({ activeIndex: NONE, isInputFocused: false });
                  }
              });
          };
          _this.handleInputFocus = function (event) {
              _this.setState({ isInputFocused: true });
              common_1.Utils.safeInvoke(_this.props.inputProps.onFocus, event);
          };
          _this.handleInputChange = function (event) {
              _this.setState({ activeIndex: NONE, inputValue: event.currentTarget.value });
              common_1.Utils.safeInvoke(_this.props.onInputChange, event);
              common_1.Utils.safeInvoke(_this.props.inputProps.onChange, event);
          };
          _this.handleInputKeyDown = function (event) {
              var _a = event.currentTarget, selectionEnd = _a.selectionEnd, value = _a.value;
              var activeIndex = _this.state.activeIndex;
              var activeIndexToEmit = activeIndex;
              if (event.which === common_1.Keys.ENTER && value.length > 0) {
                  _this.addTags(value, "default");
              }
              else if (selectionEnd === 0 && _this.props.values.length > 0) {
                  // cursor at beginning of input allows interaction with tags.
                  // use selectionEnd to verify cursor position and no text selection.
                  if (event.which === common_1.Keys.ARROW_LEFT || event.which === common_1.Keys.ARROW_RIGHT) {
                      var nextActiveIndex = _this.getNextActiveIndex(event.which === common_1.Keys.ARROW_RIGHT ? 1 : -1);
                      if (nextActiveIndex !== activeIndex) {
                          event.stopPropagation();
                          activeIndexToEmit = nextActiveIndex;
                          _this.setState({ activeIndex: nextActiveIndex });
                      }
                  }
                  else if (event.which === common_1.Keys.BACKSPACE) {
                      _this.handleBackspaceToRemove(event);
                  }
                  else if (event.which === common_1.Keys.DELETE) {
                      _this.handleDeleteToRemove(event);
                  }
              }
              _this.invokeKeyPressCallback("onKeyDown", event, activeIndexToEmit);
          };
          _this.handleInputKeyUp = function (event) {
              _this.invokeKeyPressCallback("onKeyUp", event, _this.state.activeIndex);
          };
          _this.handleInputPaste = function (event) {
              var separator = _this.props.separator;
              var value = event.clipboardData.getData("text");
              if (!_this.props.addOnPaste || value.length === 0) {
                  return;
              }
              // special case as a UX nicety: if the user pasted only one value with no delimiters in it, leave that value in
              // the input field so that the user can refine it before converting it to a tag manually.
              if (separator === false || value.split(separator).length === 1) {
                  return;
              }
              event.preventDefault();
              _this.addTags(value, "paste");
          };
          _this.handleRemoveTag = function (event) {
              // using data attribute to simplify callback logic -- one handler for all children
              var index = +event.currentTarget.parentElement.getAttribute("data-tag-index");
              _this.removeIndexFromValues(index);
          };
          return _this;
      }
      TagInput.getDerivedStateFromProps = function (props, state) {
          if (props.inputValue !== state.prevInputValueProp) {
              return {
                  inputValue: props.inputValue,
                  prevInputValueProp: props.inputValue,
              };
          }
          return null;
      };
      TagInput.prototype.render = function () {
          var _a;
          var _b = this.props, className = _b.className, disabled = _b.disabled, fill = _b.fill, inputProps = _b.inputProps, intent = _b.intent, large = _b.large, leftIcon = _b.leftIcon, placeholder = _b.placeholder, values = _b.values;
          var classes = classnames_1.default(common_1.Classes.INPUT, common_1.Classes.TAG_INPUT, (_a = {},
              _a[common_1.Classes.ACTIVE] = this.state.isInputFocused,
              _a[common_1.Classes.DISABLED] = disabled,
              _a[common_1.Classes.FILL] = fill,
              _a[common_1.Classes.LARGE] = large,
              _a), common_1.Classes.intentClass(intent), className);
          var isLarge = classes.indexOf(common_1.Classes.LARGE) > NONE;
          // use placeholder prop only if it's defined and values list is empty or contains only falsy values
          var isSomeValueDefined = values.some(function (val) { return !!val; });
          var resolvedPlaceholder = placeholder == null || isSomeValueDefined ? inputProps.placeholder : placeholder;
          return (React.createElement("div", { className: classes, onBlur: this.handleContainerBlur, onClick: this.handleContainerClick },
              React.createElement(icon_1.Icon, { className: common_1.Classes.TAG_INPUT_ICON, icon: leftIcon, iconSize: isLarge ? icon_1.Icon.SIZE_LARGE : icon_1.Icon.SIZE_STANDARD }),
              React.createElement("div", { className: common_1.Classes.TAG_INPUT_VALUES },
                  values.map(this.maybeRenderTag),
                  this.props.children,
                  React.createElement("input", tslib_1.__assign({ value: this.state.inputValue }, inputProps, { onFocus: this.handleInputFocus, onChange: this.handleInputChange, onKeyDown: this.handleInputKeyDown, onKeyUp: this.handleInputKeyUp, onPaste: this.handleInputPaste, placeholder: resolvedPlaceholder, ref: this.refHandlers.input, className: classnames_1.default(common_1.Classes.INPUT_GHOST, inputProps.className), disabled: disabled }))),
              this.props.rightElement));
      };
      TagInput.prototype.getNextActiveIndex = function (direction) {
          var activeIndex = this.state.activeIndex;
          if (activeIndex === NONE) {
              // nothing active & moving left: select last defined value. otherwise select nothing.
              return direction < 0 ? this.findNextIndex(this.props.values.length, -1) : NONE;
          }
          else {
              // otherwise, move in direction and clamp to bounds.
              // note that upper bound allows going one beyond last item
              // so focus can move off the right end, into the text input.
              return this.findNextIndex(activeIndex, direction);
          }
      };
      TagInput.prototype.findNextIndex = function (startIndex, direction) {
          var values = this.props.values;
          var index = startIndex + direction;
          while (index > 0 && index < values.length && !values[index]) {
              index += direction;
          }
          return common_1.Utils.clamp(index, 0, values.length);
      };
      /**
       * Splits inputValue on separator prop,
       * trims whitespace from each new value,
       * and ignores empty values.
       */
      TagInput.prototype.getValues = function (inputValue) {
          var separator = this.props.separator;
          // NOTE: split() typings define two overrides for string and RegExp.
          // this does not play well with our union prop type, so we'll just declare it as a valid type.
          return (separator === false ? [inputValue] : inputValue.split(separator))
              .map(function (val) { return val.trim(); })
              .filter(function (val) { return val.length > 0; });
      };
      TagInput.prototype.handleBackspaceToRemove = function (event) {
          var previousActiveIndex = this.state.activeIndex;
          // always move leftward one item (this will focus last item if nothing is focused)
          this.setState({ activeIndex: this.getNextActiveIndex(-1) });
          // delete item if there was a previous valid selection (ignore first backspace to focus last item)
          if (this.isValidIndex(previousActiveIndex)) {
              event.stopPropagation();
              this.removeIndexFromValues(previousActiveIndex);
          }
      };
      TagInput.prototype.handleDeleteToRemove = function (event) {
          var activeIndex = this.state.activeIndex;
          if (this.isValidIndex(activeIndex)) {
              event.stopPropagation();
              this.removeIndexFromValues(activeIndex);
          }
      };
      /** Remove the item at the given index by invoking `onRemove` and `onChange` accordingly. */
      TagInput.prototype.removeIndexFromValues = function (index) {
          var _a = this.props, onChange = _a.onChange, onRemove = _a.onRemove, values = _a.values;
          common_1.Utils.safeInvoke(onRemove, values[index], index);
          if (common_1.Utils.isFunction(onChange)) {
              onChange(values.filter(function (_, i) { return i !== index; }));
          }
      };
      TagInput.prototype.invokeKeyPressCallback = function (propCallbackName, event, activeIndex) {
          common_1.Utils.safeInvoke(this.props[propCallbackName], event, activeIndex === NONE ? undefined : activeIndex);
          common_1.Utils.safeInvoke(this.props.inputProps[propCallbackName], event);
      };
      /** Returns whether the given index represents a valid item in `this.props.values`. */
      TagInput.prototype.isValidIndex = function (index) {
          return index !== NONE && index < this.props.values.length;
      };
      TagInput.displayName = props_1.DISPLAYNAME_PREFIX + ".TagInput";
      TagInput.defaultProps = {
          addOnBlur: false,
          addOnPaste: true,
          inputProps: {},
          separator: /[,\n\r]/,
          tagProps: {},
      };
      TagInput = tslib_1.__decorate([
          react_lifecycles_compat_1.polyfill
      ], TagInput);
      return TagInput;
  }(common_1.AbstractPureComponent2));
  exports.TagInput = TagInput;
  //# sourceMappingURL=tagInput.js.map