"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = exports.TokensInput = void 0;

var _react = _interopRequireDefault(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _reactTagsinput = _interopRequireDefault(require("react-tagsinput"));

var _reactOuiIcons = _interopRequireDefault(require("react-oui-icons"));

var _classnames = _interopRequireDefault(require("classnames"));

var _Token = _interopRequireDefault(require("../Token"));

var _index = require("../../tokens/forimport/index.es");

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

function _extends() { _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; }; return _extends.apply(this, arguments); }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

/**
 * @typedef {Object} TokenWrapper
 * @property {String} name - The text display for the token.
 * @property {String=} style - The style to use for displaying via <Token>
 *            Indicates how to style the token.
 */

/**
 * Key codes which should be interpreted as an
 * indication to add the current text as a new token.
 */
var ADD_KEYS = [
/** TAB   */
{
  keyCode: 9,
  match: "\t"
},
/** ENTER */
{
  keyCode: 13,
  match: "\n"
},
/** COMMA */
{
  keyCode: 188,
  match: ","
}];
/**
 * Tokens Input Component
 * @param {Object} props - Properties passed to component
 * @returns {ReactElement}
 */

var TokensInput = function TokensInput(_ref) {
  var addOnBlur = _ref.addOnBlur,
      addOnPaste = _ref.addOnPaste,
      className = _ref.className,
      extraAddKeys = _ref.extraAddKeys,
      hasSearchIcon = _ref.hasSearchIcon,
      isDisabled = _ref.isDisabled,
      maxTags = _ref.maxTags,
      onChange = _ref.onChange,
      onInputBlur = _ref.onInputBlur,
      onInputChange = _ref.onInputChange,
      onInputFocus = _ref.onInputFocus,
      placeholder = _ref.placeholder,
      tokens = _ref.tokens,
      props = _objectWithoutProperties(_ref, ["addOnBlur", "addOnPaste", "className", "extraAddKeys", "hasSearchIcon", "isDisabled", "maxTags", "onChange", "onInputBlur", "onInputChange", "onInputFocus", "placeholder", "tokens"]);

  /**
   * Wrap the layout in a flexed <div>
   * https://github.com/olahol/react-tagsinput#renderlayout
   * @param {Array<ReactElement>} tokenComponents - Token components
   * @param {ReactElement} inputComponent - Input component
   * @returns {ReactElement}
   */
  function renderLayout(tokenComponents, inputComponent) {
    return _react["default"].createElement("div", {
      className: "flex flex-1 flex-wrap flex-align--center",
      style: {
        resize: "both"
      }
    }, hasSearchIcon && _react["default"].createElement("span", {
      className: "flex flex-align--center push-half--sides"
    }, _react["default"].createElement(_reactOuiIcons["default"], {
      name: "search",
      fill: _index.brandBlueDark
    })), tokenComponents, inputComponent);
  }
  /**
   * Render an OUI Token to display each token.
   * https://github.com/olahol/react-tagsinput#rendertag
   *
   * @param {Object} renderOptions - Values to render token
   * @returns {ReactElement}
   */
  // eslint-disable-next-line react/prop-types


  function renderToken(_ref2) {
    var tag = _ref2.tag,
        key = _ref2.key,
        onRemove = _ref2.onRemove;

    function onDismiss() {
      onRemove(key);
    }

    var name = tag.name,
        style = tag.style,
        backgroundColor = tag.backgroundColor;
    return _react["default"].createElement(_Token["default"], {
      key: key,
      hasSnugWrap: true,
      isDismissible: !isDisabled,
      onDismiss: onDismiss,
      name: name,
      style: style,
      backgroundColor: backgroundColor,
      showWell: false,
      testSection: "token-".concat(name)
    });
  }
  /**
   * Handler for when a string is pasted into the input.
   * Splits the string on all the addKeys and extraAddKeys.
   * https://github.com/olahol/react-tagsinput#pastesplit
   *
   * @param {string} str - The pasted string.
   * @returns {Array<string>}
   */


  function pasteSplit(str) {
    return ADD_KEYS.map(function (k) {
      return k.match;
    }).concat(extraAddKeys) // Split the string by all our addKeys by joining with a
    // \n, which we will use as the final split operator.
    .reduce(function (acc, value) {
      return acc.split(value).join("\n");
    }, str).split("\n").filter(function (k) {
      return !!k;
    });
  }
  /**
   * When the list of tokens changes, convert any string tokens
   * to object form and ensure there are no duplicates.
   * @param {Array.<TokenWrapper|String>} allTokens - All tokens
   */


  function __onChange(allTokens) {
    var updatedTokens = allTokens.reduce(function (acc, token) {
      // A newly typed token will be in string form
      if (typeof token === "string") {
        token = {
          name: token
        };
      }

      if (!acc.find(function (item) {
        return item.name === token.name;
      })) {
        acc.push(token);
      }

      return acc;
    }, []).filter(function (token) {
      return !!token.name;
    });
    onChange(updatedTokens);
  }

  var addKeys = ADD_KEYS.map(function (k) {
    return k.keyCode;
  }).concat(extraAddKeys);
  var isNumberOfTokensMoreThanOrEqualToMaxTags = tokens.length >= maxTags && maxTags !== -1;
  var minWidth = isNumberOfTokensMoreThanOrEqualToMaxTags ? "" : "min-width--150";
  return _react["default"].createElement("div", _extends({
    className: (0, _classnames["default"])("oui-text-input oui-pill-input text--left flush height--auto", className)
  }, props), _react["default"].createElement(_reactTagsinput["default"], {
    addKeys: addKeys,
    addOnBlur: addOnBlur,
    addOnPaste: addOnPaste,
    inputProps: {
      className: "flex flex--1 ".concat(minWidth, " no-border soft-half--ends soft--sides border-radius push-half--left"),
      onBlur: onInputBlur,
      onChange: onInputChange,
      onFocus: onInputFocus,
      placeholder: isNumberOfTokensMoreThanOrEqualToMaxTags ? "" : placeholder,
      readOnly: isNumberOfTokensMoreThanOrEqualToMaxTags,
      disabled: isDisabled
    },
    maxTags: maxTags,
    onChange: __onChange,
    onlyUnique: true,
    pasteSplit: pasteSplit,
    renderTag: renderToken,
    renderLayout: renderLayout,
    value: tokens
  }));
};

exports.TokensInput = TokensInput;
TokensInput.propTypes = {
  /**
   * Adds a new tag on input blur
   */
  addOnBlur: _propTypes["default"].bool,

  /**
   * Adds a new tag on input paste
   */
  addOnPaste: _propTypes["default"].bool,

  /** CSS class names. */
  className: _propTypes["default"].string,

  /**
   * Additional keycodes which should be considered
   * an intent to enter the current string as a new Token.
   * See ADD_KEYS above.
   */
  extraAddKeys: _propTypes["default"].arrayOf(_propTypes["default"].oneOfType([_propTypes["default"].number, _propTypes["default"].string])),

  /**
   * Whether a search icon should be present
   */
  hasSearchIcon: _propTypes["default"].bool,

  /**
   * Whether the input is disabled or not
   */
  isDisabled: _propTypes["default"].bool,

  /**
   * Maximum number of allowed tokens (pass-through to <ReactTagsInput>)
   */
  maxTags: _propTypes["default"].number,

  /**
   * Handler to invoke when the token list changes.
   */
  onChange: _propTypes["default"].func.isRequired,

  /**
   * Handler to invoke when the token input is blurred
   */
  onInputBlur: _propTypes["default"].func,

  /**
   * Handler to invoke when the token input changes
   */
  onInputChange: _propTypes["default"].func,

  /**
   * Handler to invoke when the token input is focused
   */
  onInputFocus: _propTypes["default"].func,

  /**
   * Placeholder text for the input box.
   */
  placeholder: _propTypes["default"].string,

  /**
   * @type {Array.<TokenWrapper>}
   */
  tokens: _propTypes["default"].arrayOf(_propTypes["default"].object).isRequired
};
TokensInput.defaultProps = {
  addOnBlur: true,
  addOnPaste: true,
  extraAddKeys: [],
  maxTags: -1,
  onInputBlur: function onInputBlur() {
    return null;
  },
  onInputChange: function onInputChange() {
    return null;
  },
  onInputFocus: function onInputFocus() {
    return null;
  },
  placeholder: "enter tokens"
};
var _default = TokensInput;
exports["default"] = _default;