"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports["default"] = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _react = _interopRequireDefault(require("react"));
var _draftJs = require("draft-js");
var _EditorUtilities = _interopRequireDefault(require("./EditorUtilities"));
var _constants = require("./constants");
var _VariableInputSt = require("./VariableInput.st.css.js");
var _StatusIndicator = _interopRequireDefault(require("../StatusIndicator"));
var _StatusContext = require("../FormField/StatusContext");
var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/VariableInput/VariableInput.jsx";
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
/**
 * Error Boundary to catch Draft.js crashes on mobile devices with IME/autocorrect
 *
 * Known Issue: Draft.js has a fundamental incompatibility with Android's Input Method Editor (IME).
 * When Android autocorrect modifies the DOM directly (e.g., on SPACE key press), Draft.js attempts
 * to reconcile its virtual state with DOM nodes that have already been removed/modified by the IME,
 * resulting in "Failed to execute 'removeChild' on 'Node'" errors.
 *
 * This Error Boundary prevents the entire component from crashing and allows it to auto-recover.
 * While console warnings will still appear, the user experience remains functional.
 *
 * TODO: After Draft-JS migration, make sure this error is no longer thrown and then remove this error boundary.
 */
var EditorErrorBoundary = /*#__PURE__*/function (_React$Component) {
  function EditorErrorBoundary(props) {
    var _this;
    (0, _classCallCheck2["default"])(this, EditorErrorBoundary);
    _this = _callSuper(this, EditorErrorBoundary, [props]);
    _this.state = {
      hasError: false,
      errorCount: 0
    };
    return _this;
  }
  (0, _inherits2["default"])(EditorErrorBoundary, _React$Component);
  return (0, _createClass2["default"])(EditorErrorBoundary, [{
    key: "componentDidCatch",
    value: function componentDidCatch(error, errorInfo) {
      console.warn('VariableInput: Draft.js error caught (likely mobile IME conflict):', error.message);
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps, prevState) {
      // Auto-recover with max retry limit to prevent infinite loops
      if (this.state.hasError && this.state.errorCount < 5) {
        this.setState({
          hasError: false,
          errorCount: this.state.errorCount + 1
        });
      }
    }
  }, {
    key: "render",
    value: function render() {
      return this.props.children;
    }
  }], [{
    key: "getDerivedStateFromError",
    value: function getDerivedStateFromError() {
      return {
        hasError: true
      };
    }
  }]);
}(_react["default"].Component);
/** Input with variables as tags */
var VariableInput = /*#__PURE__*/function (_React$PureComponent) {
  function VariableInput(props) {
    var _this2;
    (0, _classCallCheck2["default"])(this, VariableInput);
    _this2 = _callSuper(this, VariableInput, [props]);
    _this2._handleCompositionStart = function () {
      _this2.isComposing = true;
    };
    _this2._handleCompositionUpdate = function (e) {
      // During IME composition, manually trigger onChange with current DOM text
      // This fixes Android autosuggestion issue where draft-js doesn't fire onChange
      if (_this2.props.onChange && e.target) {
        var text = e.target.textContent || '';
        _this2.props.onChange(text);
      }
    };
    _this2._handleCompositionEnd = function () {
      _this2.isComposing = false;
    };
    _this2._handleInput = function (e) {
      if (_this2.isComposing && _this2.props.onChange && e.target) {
        var text = e.target.textContent || '';
        _this2.props.onChange(text);
      }
    };
    _this2._handlePastedText = function (text, html, editorState) {
      /** We need to prevent new line when `multilne` is false,
       * here we are removing any new lines while pasting text   */
      if (/\r|\n/.exec(text)) {
        text = text.replace(/(\r\n|\n|\r)/gm, '');
        _this2._onEditorChange(_EditorUtilities["default"].insertText(editorState, text));
        return true;
      }
      return false;
    };
    _this2._isEmpty = function () {
      return _this2.state.editorState.getCurrentContent().getPlainText().length === 0;
    };
    _this2._inputToTagSize = function (inputSize) {
      return _constants.inputToTagsSize[inputSize] || VariableInput.defaultProps.size;
    };
    _this2._toString = function () {
      var _this2$props$variable = _this2.props.variableTemplate,
        prefix = _this2$props$variable.prefix,
        suffix = _this2$props$variable.suffix;
      var editorState = _this2.state.editorState;
      return _EditorUtilities["default"].convertToString({
        editorState: editorState,
        prefix: prefix,
        suffix: suffix
      });
    };
    _this2._onBlur = function () {
      var _this2$props$onBlur = _this2.props.onBlur,
        onBlur = _this2$props$onBlur === void 0 ? function () {} : _this2$props$onBlur;
      onBlur(_this2._toString());
    };
    _this2._onMouseDown = function () {
      _this2._isMouseDown = true;
    };
    _this2._onMouseUp = function () {
      _this2._isMouseDown = false;
    };
    _this2._onFocus = function () {
      var _this2$props$onFocus = _this2.props.onFocus,
        onFocus = _this2$props$onFocus === void 0 ? function () {} : _this2$props$onFocus;
      onFocus(_this2._toString());
    };
    _this2._onSubmit = function () {
      var _this2$props$onSubmit = _this2.props.onSubmit,
        onSubmit = _this2$props$onSubmit === void 0 ? function () {} : _this2$props$onSubmit;
      onSubmit(_this2._toString());
    };
    _this2._onChange = function () {
      var _this2$props$onChange = _this2.props.onChange,
        onChange = _this2$props$onChange === void 0 ? function () {} : _this2$props$onChange;

      // Only call onChange if not composing (during composition, manual handlers will call it)
      if (!_this2.isComposing) {
        onChange(_this2._toString());
      }
    };
    _this2._onEditorChange = function (editorState) {
      var prevHasFocus = _this2.state.editorState.getSelection().getHasFocus();
      var newHasFocus = editorState.getSelection().getHasFocus();
      var becomesFocused = !prevHasFocus && newHasFocus;
      var isKeyboard = !_this2._isMouseDown;
      if (becomesFocused && isKeyboard) {
        var selectionAtEnd = _draftJs.EditorState.moveSelectionToEnd(editorState).getSelection();
        editorState = _draftJs.EditorState.forceSelection(editorState, selectionAtEnd);
      }
      _this2._setEditorState(editorState);
    };
    _this2._setEditorState = function (editorState) {
      var onStateChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
      var editorStateBefore = _this2.state.editorState;
      var _this2$props$variable2 = _this2.props.variableTemplate,
        prefix = _this2$props$variable2.prefix,
        suffix = _this2$props$variable2.suffix;
      var updateEditorState = _EditorUtilities["default"].moveToEdge(editorState);
      var triggerCallback = function triggerCallback() {};
      if (_EditorUtilities["default"].isBlured(editorStateBefore, updateEditorState)) {
        // onChange is called after the editor blur handler
        // and we can't reflect the changes there, we moved the logic here.
        triggerCallback = _this2._onBlur;
        if (_EditorUtilities["default"].hasUnparsedEntity(updateEditorState, prefix, suffix)) {
          updateEditorState = _this2._stringToContentState(_EditorUtilities["default"].convertToString({
            editorState: updateEditorState,
            prefix: prefix,
            suffix: suffix
          }));
        }
      } else if (_EditorUtilities["default"].isContentChanged(editorStateBefore, updateEditorState)) {
        triggerCallback = _this2._onChange;
      }
      _this2.setState({
        editorState: updateEditorState
      }, function () {
        triggerCallback();
        onStateChanged();
      });
    };
    _this2._stringToContentState = function (str) {
      var _this2$props = _this2.props,
        _this2$props$variable3 = _this2$props.variableParser,
        variableParser = _this2$props$variable3 === void 0 ? function () {} : _this2$props$variable3,
        variableTagPropsParser = _this2$props.variableTagPropsParser,
        _this2$props$variable4 = _this2$props.variableTemplate,
        prefix = _this2$props$variable4.prefix,
        suffix = _this2$props$variable4.suffix;
      var editorState = _this2.state.editorState;
      var content = _EditorUtilities["default"].stringToContentState({
        str: str,
        variableParser: variableParser,
        variableTagPropsParser: variableTagPropsParser,
        prefix: prefix,
        suffix: suffix
      });
      return _EditorUtilities["default"].pushAndKeepSelection({
        editorState: editorState,
        content: content
      });
    };
    _this2._setStringValue = function (str) {
      var afterUpdated = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
      var updatedEditorState = _draftJs.EditorState.moveSelectionToEnd(_this2._stringToContentState(str));
      _this2._setEditorState(updatedEditorState, function () {
        afterUpdated(updatedEditorState);
      });
    };
    /** Set value to display in the input */
    _this2.setValue = function (value) {
      _this2._setStringValue(value, function () {
        _this2._onSubmit();
      });
    };
    /** Insert variable at the input cursor position */
    _this2.insertVariable = function (value) {
      var _this2$props2 = _this2.props,
        variableParser = _this2$props2.variableParser,
        variableTagPropsParser = _this2$props2.variableTagPropsParser,
        _this2$props2$variabl = _this2$props2.variableTemplate,
        prefix = _this2$props2$variabl.prefix,
        suffix = _this2$props2$variabl.suffix;
      var editorState = _this2.state.editorState;
      var text = variableParser(value);
      var tagProps = variableTagPropsParser(value);
      var newState = text ? _EditorUtilities["default"].insertEntity(editorState, {
        text: text,
        value: value,
        tagProps: tagProps
      }) : _EditorUtilities["default"].insertText(editorState, "".concat(prefix).concat(value).concat(suffix, " "));
      _this2._setEditorState(newState, function () {
        _this2._onSubmit();
      });
    };
    /** Insert Text at the input cursor position */
    _this2.insertText = function (value) {
      var editorState = _this2.state.editorState;
      var newState = _EditorUtilities["default"].insertText(editorState, value);
      _this2._setEditorState(newState, function () {
        _this2._onSubmit();
      });
    };
    /**
     * Focus the input at the end of the content.
     * Optionally, if variableKey is provided, focus after that specific variable.
     */
    _this2.focus = function () {
      var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
        variableKey = _ref.variableKey;
      var editorState = _this2.state.editorState;
      var selectionToFocus;
      if (variableKey) {
        var targetRange = _EditorUtilities["default"].findEntityRangeByKey(editorState, variableKey);
        if (targetRange) {
          var blockKey = targetRange.blockKey,
            end = targetRange.end;
          selectionToFocus = new _draftJs.SelectionState({
            anchorKey: blockKey,
            anchorOffset: end,
            focusKey: blockKey,
            focusOffset: end
          });
        }
      }
      if (!selectionToFocus) {
        selectionToFocus = _draftJs.EditorState.moveSelectionToEnd(editorState).getSelection();
      }
      var newEditorState = _draftJs.EditorState.forceSelection(editorState, selectionToFocus.merge({
        hasFocus: true
      }));
      _this2.setState({
        editorState: newEditorState
      }, function () {
        _this2._onFocus();
      });
    };
    var size = props.size,
      disabled = props.disabled;
    var decorator = _EditorUtilities["default"].decoratorFactory({
      tag: {
        size: _this2._inputToTagSize(size),
        disabled: disabled
      }
    });
    _this2.state = {
      editorState: _draftJs.EditorState.createEmpty(decorator)
    };
    _this2.editorRef = /*#__PURE__*/_react["default"].createRef();
    // IME composition tracking for Android autosuggestions
    _this2.isComposing = false;
    // Track mouse-initiated focus to avoid overriding click cursor position
    _this2._isMouseDown = false;
    return _this2;
  }
  (0, _inherits2["default"])(VariableInput, _React$PureComponent);
  return (0, _createClass2["default"])(VariableInput, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      var initialValue = this.props.initialValue;
      this._setStringValue(initialValue);

      // Add IME composition event listeners to handle Android autosuggestions
      if (this.editorRef.current) {
        var editorNode = this.editorRef.current.editor;
        if (editorNode) {
          editorNode.addEventListener('compositionstart', this._handleCompositionStart);
          editorNode.addEventListener('compositionupdate', this._handleCompositionUpdate);
          editorNode.addEventListener('compositionend', this._handleCompositionEnd);
          editorNode.addEventListener('input', this._handleInput);
        }
      }
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      if (this.editorRef.current) {
        var editorNode = this.editorRef.current.editor;
        if (editorNode) {
          editorNode.removeEventListener('compositionstart', this._handleCompositionStart);
          editorNode.removeEventListener('compositionupdate', this._handleCompositionUpdate);
          editorNode.removeEventListener('compositionend', this._handleCompositionEnd);
          editorNode.removeEventListener('input', this._handleInput);
        }
      }
    }
  }, {
    key: "render",
    value: function render() {
      var _this$props = this.props,
        dataHook = _this$props.dataHook,
        multiline = _this$props.multiline,
        rows = _this$props.rows,
        size = _this$props.size,
        disabled = _this$props.disabled,
        readOnly = _this$props.readOnly,
        placeholder = _this$props.placeholder,
        status = _this$props.status,
        statusMessage = _this$props.statusMessage,
        className = _this$props.className;
      var singleLineProps = {
        handlePastedText: this._handlePastedText,
        handleReturn: function handleReturn() {
          return 'handled';
        }
      };
      var finalStatus = (0, _StatusContext.getStatusFromContext)(this.context, status);
      return /*#__PURE__*/_react["default"].createElement("div", {
        "data-hook": dataHook,
        onMouseDown: this._onMouseDown,
        onMouseUp: this._onMouseUp,
        className: (0, _VariableInputSt.st)(_VariableInputSt.classes.root, {
          disabled: disabled,
          readOnly: readOnly,
          size: size,
          status: finalStatus,
          singleLine: !multiline
        }, className),
        style: (0, _defineProperty2["default"])({}, _VariableInputSt.vars.rows, rows),
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 165,
          columnNumber: 7
        }
      }, /*#__PURE__*/_react["default"].createElement(EditorErrorBoundary, {
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 182,
          columnNumber: 9
        }
      }, /*#__PURE__*/_react["default"].createElement(_draftJs.Editor, (0, _extends2["default"])({
        ref: this.editorRef,
        spellCheck: this.props.spellCheck,
        editorState: this.state.editorState,
        onChange: this._onEditorChange,
        onFocus: this._onFocus,
        placeholder: placeholder,
        readOnly: disabled || readOnly
      }, readOnly && {
        tabIndex: 0
      }, !multiline && singleLineProps, {
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 183,
          columnNumber: 11
        }
      }))), (status || finalStatus === 'loading') && /*#__PURE__*/_react["default"].createElement("span", {
        className: _VariableInputSt.classes.indicatorWrapper,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 198,
          columnNumber: 11
        }
      }, /*#__PURE__*/_react["default"].createElement(_StatusIndicator["default"], {
        dataHook: _constants.dataHooks.indicator,
        status: finalStatus,
        message: statusMessage,
        __self: this,
        __source: {
          fileName: _jsxFileName,
          lineNumber: 199,
          columnNumber: 13
        }
      })));
    }
  }]);
}(_react["default"].PureComponent);
VariableInput.contextType = _StatusContext.StatusContext;
VariableInput.displayName = 'VariableInput';
VariableInput.defaultProps = {
  initialValue: '',
  multiline: true,
  rows: 1,
  spellCheck: false,
  size: _constants.sizeTypes.medium,
  variableParser: function variableParser() {},
  variableTagPropsParser: function variableTagPropsParser() {
    return {};
  },
  variableTemplate: {
    prefix: '{{',
    suffix: '}}'
  }
};
var _default = exports["default"] = VariableInput;