"use strict";

exports.__esModule = true;
exports.default = void 0;

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

var _immutable = _interopRequireDefault(require("immutable"));

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

var _styles = require("@mui/material/styles");

var _material = require("@mui/material");

var _draftJs = require("draft-js");

var _Toolbar = _interopRequireDefault(require("./components/Toolbar"));

var _Link = _interopRequireDefault(require("./components/Link"));

var _Media = _interopRequireDefault(require("./components/Media"));

var _Blockquote = _interopRequireDefault(require("./components/Blockquote"));

var _CodeBlock = _interopRequireDefault(require("./components/CodeBlock"));

var _UrlPopover = _interopRequireDefault(require("./components/UrlPopover"));

var _Autocomplete = _interopRequireDefault(require("./components/Autocomplete"));

var _utils = require("./utils");

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

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

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); }

const PREFIX = 'SCRichTextEditor';
const classes = {
  root: `${PREFIX}-root`,
  container: `${PREFIX}-container`,
  inheritFontSize: `${PREFIX}-inheritFontSize`,
  editor: `${PREFIX}-editor`,
  editorContainer: `${PREFIX}-editorContainer`,
  editorReadOnly: `${PREFIX}-editorReadOnly`,
  error: `${PREFIX}-error`,
  hidePlaceholder: `${PREFIX}-hidePlaceholder`,
  placeHolder: `${PREFIX}-placeHolder`,
  linkPopover: `${PREFIX}-linkPopover`,
  linkTextField: `${PREFIX}-linkTextField`,
  anchorLink: `${PREFIX}-anchorLink`,
  toolbar: `${PREFIX}-toolbar`,
  inlineToolbar: `${PREFIX}-inlineToolbar`
};
const Root = (0, _styles.styled)('div', {
  name: PREFIX,
  slot: 'Root',
  overridesResolver: (_, styles) => styles.root
})(({
  theme
}) => ({
  [`&.${classes.root}`]: {},
  [`& .${classes.container}`]: {
    margin: theme.spacing(1, 0, 0, 0),
    position: 'relative',
    fontFamily: theme.typography.body1.fontFamily,
    fontSize: theme.typography.body1.fontSize,
    '& figure': {
      margin: 0
    }
  },
  [`& .${classes.inheritFontSize}`]: {
    fontSize: 'inherit'
  },
  [`& .${classes.editor}`]: {},
  [`& .${classes.editorContainer}`]: {
    margin: theme.spacing(1, 0, 0, 0),
    cursor: 'text',
    width: '100%',
    padding: theme.spacing(0, 0, 1, 0)
  },
  [`& .${classes.editorReadOnly}`]: {
    borderBottom: 'none'
  },
  [`& .${classes.error}`]: {
    borderBottom: '2px solid red'
  },
  [`& .${classes.hidePlaceholder}`]: {
    display: 'none'
  },
  [`& .${classes.placeHolder}`]: {
    color: theme.palette.grey[600],
    outline: 'none'
  },
  [`& .${classes.linkPopover}`]: {
    padding: theme.spacing(2, 2, 2, 2)
  },
  [`& .${classes.linkTextField}`]: {
    width: '100%'
  },
  [`& .${classes.anchorLink}`]: {},
  [`& .${classes.toolbar}`]: {},
  [`& .${classes.inlineToolbar}`]: {
    maxWidth: '180px',
    position: 'absolute',
    padding: '5px',
    zIndex: 10
  }
}));

const blockRenderMap = _immutable.default.Map({
  blockquote: {
    element: 'blockquote',
    wrapper: /*#__PURE__*/_react.default.createElement(_Blockquote.default, null)
  },
  'code-block': {
    element: 'pre',
    wrapper: /*#__PURE__*/_react.default.createElement(_CodeBlock.default, null)
  }
});

const styleRenderMap = {
  STRIKETHROUGH: {
    textDecoration: 'line-through'
  },
  HIGHLIGHT: {
    backgroundColor: 'yellow'
  }
};
const {
  hasCommandModifier
} = _draftJs.KeyBindingUtil;
const autocompleteMinSearchCharCount = 2;
const lineHeight = 26;
const defaultInlineToolbarControls = ['bold', 'italic', 'underline', 'clear'];

const findLinkEntities = (contentBlock, callback, contentState) => {
  contentBlock.findEntityRanges(character => {
    const entityKey = character.getEntity();
    return entityKey !== null && contentState.getEntity(entityKey).getType() === 'LINK';
  }, callback);
};

const findDecoWithRegex = (regex, contentBlock, callback) => {
  const text = contentBlock.getText();
  let matchArr, start;

  while ((matchArr = regex.exec(text)) !== null) {
    start = matchArr.index;
    callback(start, start + matchArr[0].length);
  }
};

const getEditorState = props => {
  const decorators = [{
    strategy: findLinkEntities,
    component: _Link.default
  }];

  if (props.decorators) {
    props.decorators.forEach(deco => decorators.push({
      strategy: (contentBlock, callback) => {
        findDecoWithRegex(deco.regex, contentBlock, callback);
      },
      component: deco.component
    }));
  }

  const decorator = new _draftJs.CompositeDecorator(decorators);
  const defaultValue = props.defaultValue || props.value;
  return defaultValue ? _draftJs.EditorState.createWithContent((0, _draftJs.convertFromRaw)(JSON.parse(defaultValue)), decorator) : _draftJs.EditorState.createEmpty(decorator);
};

const RichTextEditor = (props, ref) => {
  const {
    controls,
    customControls
  } = props;
  const [state, setState] = (0, _react.useState)({});
  const [focus, setFocus] = (0, _react.useState)(false);
  const [searchTerm, setSearchTerm] = (0, _react.useState)('');
  const [selectedIndex, setSelectedIndex] = (0, _react.useState)(0);
  const [autocompleteItems, setAutocompleteItems] = (0, _react.useState)([]);
  const [editorState, setEditorState] = (0, _react.useState)(() => getEditorState(props));
  const [focusMediaKey, setFocusMediaKey] = (0, _react.useState)('');
  const editorRef = (0, _react.useRef)(null);
  const editorId = props.id || 'rte';
  const toolbarPositionRef = (0, _react.useRef)(undefined);
  const editorStateRef = (0, _react.useRef)(editorState);
  const autocompleteRef = (0, _react.useRef)(undefined);
  const autocompleteSelectionStateRef = (0, _react.useRef)(undefined);
  const autocompletePositionRef = (0, _react.useRef)(undefined);
  const autocompleteLimit = props.autocomplete ? props.autocomplete.suggestLimit || 5 : 5;
  const isFirstFocus = (0, _react.useRef)(true);
  const customBlockMapRef = (0, _react.useRef)(undefined);
  const customStyleMapRef = (0, _react.useRef)(undefined);
  const isFocusedWithMouse = (0, _react.useRef)(false);
  const selectionRef = (0, _react.useRef)({
    start: 0,
    end: 0
  });
  /**
   * Exposed methods
   */

  (0, _react.useImperativeHandle)(ref, () => ({
    focus: () => {
      handleFocus();
    },
    save: () => {
      handleSave();
    },
    insertText: text => {
      handleInsertText(text);
    },
    insertAtomicBlock: (name, data) => {
      handleInsertAtomicBlockSync(name, data);
    },
    insertAtomicBlockSync: (name, data) => {
      handleInsertAtomicBlockSync(name, data);
    },
    insertAtomicBlockAsync: (name, promise, placeholder) => {
      handleInsertAtomicBlockAsync(name, promise, placeholder);
    }
  }));
  (0, _react.useEffect)(() => {
    const editorState = getEditorState(props);
    setEditorState(editorState);
    toggleMouseUpListener(true);
    return () => {
      toggleMouseUpListener();
    };
  }, [props.value, props.defaultValue]);
  (0, _react.useEffect)(() => {
    if (props.onChange) {
      props.onChange(editorState);
    }

    editorStateRef.current = editorState;
  }, [editorState]);
  (0, _react.useEffect)(() => {
    toolbarPositionRef.current = state.toolbarPosition;
  }, [state.toolbarPosition]);
  (0, _react.useEffect)(() => {
    var _autocompleteRef$curr;

    if (searchTerm.length < autocompleteMinSearchCharCount) {
      setSelectedIndex(0);
    } else if (((_autocompleteRef$curr = autocompleteRef.current) == null ? void 0 : _autocompleteRef$curr.asyncItems) !== undefined) {
      var _autocompleteRef$curr2;

      (_autocompleteRef$curr2 = autocompleteRef.current) == null ? void 0 : _autocompleteRef$curr2.asyncItems(searchTerm).then(items => setAutocompleteItems(items));
    }
  }, [searchTerm]);

  const clearSearch = () => {
    setSearchTerm('');
    autocompletePositionRef.current = undefined;
    autocompleteSelectionStateRef.current = undefined;
  };

  const handleMouseUp = event => {
    const nodeName = event.target.nodeName;
    clearSearch();

    if (nodeName === 'IMG' || nodeName === 'VIDEO') {
      return;
    }

    setTimeout(() => {
      var _editorRef$current;

      const selection = editorStateRef.current.getSelection();

      if (selection.isCollapsed() || toolbarPositionRef !== undefined && selectionRef.current.start === selection.getStartOffset() && selectionRef.current.end === selection.getEndOffset()) {
        const selectionInfo = (0, _utils.getSelectionInfo)(editorStateRef.current);

        if (selectionInfo.entityType === 'IMAGE') {
          focusMedia(selectionInfo.block);
          return;
        }

        setState(Object.assign({}, state, {
          toolbarPosition: undefined
        }));
        return;
      }

      selectionRef.current = {
        start: selection.getStartOffset(),
        end: selection.getEndOffset()
      };
      const editor = (_editorRef$current = editorRef.current) == null ? void 0 : _editorRef$current.editor;

      if (!editor) {
        return;
      }

      const {
        editorRect,
        selectionRect
      } = (0, _utils.getEditorBounds)(editor);

      if (!selectionRect) {
        return;
      }

      const position = {
        top: editor.offsetTop - 48 + (selectionRect.top - editorRect.top),
        left: editor.offsetLeft + (selectionRect.left - editorRect.left)
      };
      setState(Object.assign({}, state, {
        toolbarPosition: position
      }));
    }, 1);
  };

  const findAutocompleteStrategy = chars => {
    if (!props.autocomplete) {
      return undefined;
    }

    const acArray = props.autocomplete.strategies.filter(ac => ac.triggerChar === chars);

    if (acArray.length) {
      return acArray[0];
    }

    return undefined;
  };

  const updateAutocompletePosition = () => {
    var _editorRef$current2;

    const editor = (_editorRef$current2 = editorRef.current) == null ? void 0 : _editorRef$current2.editor;

    if (!editor) {
      return;
    }

    const {
      editorRect,
      selectionRect
    } = (0, _utils.getEditorBounds)(editor);
    const line = (0, _utils.getLineNumber)(editorState);
    const top = selectionRect ? selectionRect.top : editorRect.top + lineHeight * line;
    const left = selectionRect ? selectionRect.left : editorRect.left;
    const position = {
      top: editor.offsetTop + (top - editorRect.top) + lineHeight,
      left: editor.offsetLeft + (left - editorRect.left)
    };

    if (!autocompleteSelectionStateRef.current) {
      autocompleteSelectionStateRef.current = editorStateRef.current.getSelection();
    }

    autocompletePositionRef.current = position;
  };

  const insertAutocompleteSuggestionAsAtomicBlock = (name, selection, value) => {
    const block = (0, _utils.atomicBlockExists)(name, props.customControls);

    if (!block) {
      return;
    }

    const contentState = _draftJs.Modifier.removeRange(editorStateRef.current.getCurrentContent(), selection, 'forward');

    const newEditorState = _draftJs.EditorState.push(editorStateRef.current, contentState, 'remove-range');

    const withAtomicBlock = insertAtomicBlock(newEditorState, name.toUpperCase(), {
      value: value
    }, {
      selection: newEditorState.getCurrentContent().getSelectionAfter()
    });
    handleChange(withAtomicBlock);
  };

  const insertAutocompleteSuggestionAsText = (selection, value) => {
    const currentContentState = editorState.getCurrentContent();
    const entityKey = currentContentState.createEntity('AC_ITEM', 'IMMUTABLE').getLastCreatedEntityKey();

    const contentState = _draftJs.Modifier.replaceText(editorStateRef.current.getCurrentContent(), selection, value, editorStateRef.current.getCurrentInlineStyle(), entityKey);

    const newEditorState = _draftJs.EditorState.push(editorStateRef.current, contentState, 'insert-characters');

    if (autocompleteRef.current.insertSpaceAfter === false) {
      handleChange(newEditorState);
    } else {
      const addSpaceState = _draftJs.Modifier.insertText(newEditorState.getCurrentContent(), newEditorState.getSelection(), ' ', newEditorState.getCurrentInlineStyle());

      handleChange(_draftJs.EditorState.push(newEditorState, addSpaceState, 'insert-characters'));
    }
  };

  const handleAutocompleteSelected = index => {
    const itemIndex = index || selectedIndex;
    const items = getAutocompleteItems();

    if (items.length > itemIndex) {
      const item = items[itemIndex];
      const currentSelection = autocompleteSelectionStateRef.current;
      const offset = currentSelection.getFocusOffset() + searchTerm.length + 1;
      const newSelection = currentSelection.merge({
        focusOffset: offset
      });

      if (autocompleteRef.current.atomicBlockName) {
        const name = autocompleteRef.current.atomicBlockName;
        insertAutocompleteSuggestionAsAtomicBlock(name, newSelection, item.value);
      } else {
        insertAutocompleteSuggestionAsText(newSelection, item.value);
      }
    }

    handleAutocompleteClosed();
  };

  const handleAutocompleteClosed = () => {
    clearSearch();
    setSelectedIndex(0);
    refocus();
  };

  const getAutocompleteItems = () => {
    var _autocompleteRef$curr3;

    if (searchTerm.length < autocompleteMinSearchCharCount) {
      return [];
    }

    if (((_autocompleteRef$curr3 = autocompleteRef.current) == null ? void 0 : _autocompleteRef$curr3.items) !== undefined) {
      return autocompleteRef.current.items.filter(item => item.keys.filter(key => key.includes(searchTerm)).length > 0).splice(0, autocompleteLimit);
    } else {
      return autocompleteItems;
    }
  };

  const handleChange = state => {
    setEditorState(state);
  };

  const handleBeforeInput = (chars, editorState) => {
    if (chars === ' ' && searchTerm.length) {
      clearSearch();
    } else if (autocompleteSelectionStateRef.current) {
      setSearchTerm(searchTerm + chars);
    } else {
      const strategy = findAutocompleteStrategy(chars);

      if (strategy) {
        autocompleteRef.current = strategy;
        updateAutocompletePosition();
      }
    }

    return isMaxLengthHandled(editorState, 1);
  };

  const handleEditorFocus = () => {
    handleFocus();

    if (isFocusedWithMouse.current === true) {
      isFocusedWithMouse.current = false;
      return;
    }

    const nextEditorState = _draftJs.EditorState.forceSelection(editorState, editorState.getSelection());

    setTimeout(() => setEditorState(_draftJs.EditorState.moveFocusToEnd(nextEditorState)), 0);
  };

  const handlePlaceholderFocus = () => {
    if (isFirstFocus.current === false) {
      focusEditor();
      return;
    }

    handleFocus();
    isFirstFocus.current = false;
  };

  const handleFocus = () => {
    focusEditor();

    if (props.onFocus) {
      props.onFocus();
    }
  };

  const focusEditor = () => {
    setFocus(true);
    setTimeout(() => {
      var _editorRef$current3;

      return (_editorRef$current3 = editorRef.current) == null ? void 0 : _editorRef$current3.focus();
    }, 0);
  };

  const handleBlur = () => {
    isFocusedWithMouse.current = false;
    setFocus(false);

    if (props.onBlur) {
      props.onBlur();
    }

    if (!state.anchorUrlPopover) {
      setState(Object.assign({}, state, {
        toolbarPosition: undefined
      }));
    }
  };

  const handleMouseDown = () => {
    isFocusedWithMouse.current = true;
  };

  const handleClearFormat = () => {
    if (customStyleMapRef.current === undefined) {
      return;
    }

    const withoutStyles = (0, _utils.clearInlineStyles)(editorState, customStyleMapRef.current);
    const selectionInfo = (0, _utils.getSelectionInfo)(editorState);

    const newEditorState = _draftJs.EditorState.push(editorState, withoutStyles, 'change-inline-style');

    setEditorState(_draftJs.RichUtils.toggleBlockType(newEditorState, selectionInfo.blockType));
  };

  const handleSave = () => {
    if (props.onSave) {
      props.onSave(JSON.stringify((0, _draftJs.convertToRaw)(editorState.getCurrentContent())));
    }
  };

  const handleInsertText = text => {
    const currentContent = editorStateRef.current.getCurrentContent();
    const currentSelection = editorStateRef.current.getSelection();

    const newContent = _draftJs.Modifier.replaceText(currentContent, currentSelection, text);

    const newEditorState = _draftJs.EditorState.push(editorState, newContent, 'insert-characters');

    handleChange(_draftJs.EditorState.forceSelection(newEditorState, newContent.getSelectionAfter()));
  };

  const handleInsertAtomicBlockSync = (name, data) => {
    const block = (0, _utils.atomicBlockExists)(name, props.customControls);

    if (!block) {
      return;
    }

    const newEditorState = insertAtomicBlock(editorState, block.name.toUpperCase(), data, {
      selection: editorState.getCurrentContent().getSelectionAfter()
    });
    updateStateForPopover(newEditorState);
  };

  const handleInsertAtomicBlockAsync = (name, promise, placeholder) => {
    const selection = insertAsyncAtomicBlockPlaceholder(name, placeholder);
    const offset = selection.getFocusOffset() + 1;
    const newSelection = selection.merge({
      focusOffset: offset
    });
    promise.then(response => {
      const newEditorState = insertAtomicBlock(editorStateRef.current, name, response.data, {
        selection: newSelection
      });
      handleChange(newEditorState);
    }).catch(error => {
      if (error) {
        return;
      }

      const newContentState = _draftJs.Modifier.removeRange(editorStateRef.current.getCurrentContent(), newSelection, 'forward');

      handleChange(_draftJs.EditorState.push(editorStateRef.current, newContentState, 'remove-range'));
    });
  };

  const insertAsyncAtomicBlockPlaceholder = (name, placeholder) => {
    const placeholderName = placeholder || name + '...';
    const currentContentState = editorStateRef.current.getCurrentContent();
    const entityKey = currentContentState.createEntity('ASYNC_ATOMICBLOCK', 'IMMUTABLE').getLastCreatedEntityKey();

    const contentState = _draftJs.Modifier.insertText(editorStateRef.current.getCurrentContent(), currentContentState.getSelectionAfter(), placeholderName, undefined, entityKey);

    const selection = currentContentState.getSelectionAfter();

    const newEditorState = _draftJs.EditorState.push(editorStateRef.current, contentState, 'insert-characters');

    handleChange(newEditorState);
    return selection;
  };

  const handleKeyCommand = (command, editorState) => {
    const newState = _draftJs.RichUtils.handleKeyCommand(editorState, command);

    if (newState) {
      handleChange(newState);
      return 'handled';
    } else {
      if (command.includes('mui-autocomplete')) {
        if (command === 'mui-autocomplete-insert') {
          handleAutocompleteSelected();
        }

        if (command === 'mui-autocomplete-end') {
          handleAutocompleteClosed();
        }

        return 'handled';
      }

      if (props.keyCommands) {
        const keyCommand = props.keyCommands.find(comm => comm.name === command);

        if (keyCommand) {
          const _newState = keyCommand.callback(editorState);

          handleChange(_newState);
          return 'handled';
        }
      }
    }

    return 'not-handled';
  };

  const handleCustomClick = (style, id) => {
    if (!props.customControls) {
      return;
    }

    for (let control of props.customControls) {
      if (control.name.toUpperCase() === style) {
        if (control.onClick) {
          setTimeout(() => {
            var _editorRef$current4;

            return (_editorRef$current4 = editorRef.current) == null ? void 0 : _editorRef$current4.blur();
          }, 0);
          const newState = control.onClick(editorState, control.name, document.getElementById(id));

          if (newState) {
            if (newState.getSelection().isCollapsed()) {
              setEditorState(newState);
            } else {
              updateStateForPopover(newState);
            }
          } else {
            if (!editorState.getSelection().isCollapsed()) {
              refocus();
            }
          }
        }

        break;
      }
    }
  };

  const handleUndo = () => {
    setEditorState(_draftJs.EditorState.undo(editorState));
  };

  const handleRedo = () => {
    setEditorState(_draftJs.EditorState.redo(editorState));
  };

  const handlePrompt = (lastState, type, inlineMode) => {
    const selectionInfo = (0, _utils.getSelectionInfo)(lastState);
    const contentState = lastState.getCurrentContent();
    const linkKey = selectionInfo.linkKey;
    let data = undefined;

    if (linkKey) {
      const linkInstance = contentState.getEntity(linkKey);
      data = linkInstance.getData();
    }

    setState({
      urlData: data,
      urlKey: linkKey,
      toolbarPosition: !inlineMode ? undefined : state.toolbarPosition,
      anchorUrlPopover: !inlineMode ? document.getElementById(`${editorId}-${type}-control-button`) : document.getElementById(`${editorId}-${type}-control-button-toolbar`),
      urlIsMedia: type === 'media' ? true : undefined
    });
  };

  const handlePromptForLink = inlineMode => {
    const selection = editorState.getSelection();

    if (!selection.isCollapsed()) {
      handlePrompt(editorState, 'link', inlineMode);
    }
  };

  const handlePromptForMedia = (inlineMode, newState) => {
    const lastState = newState || editorState;
    handlePrompt(lastState, 'media', inlineMode);
  };

  const handleConfirmPrompt = (isMedia, ...args) => {
    if (isMedia) {
      confirmMedia(...args);
      return;
    }

    confirmLink(...args);
  };

  const handleToolbarClick = (style, type, id, inlineMode) => {
    if (type === 'inline') {
      return toggleInlineStyle(style);
    }

    if (type === 'block') {
      return toggleBlockType(style);
    }

    switch (style) {
      case 'UNDO':
        handleUndo();
        break;

      case 'REDO':
        handleRedo();
        break;

      case 'LINK':
        handlePromptForLink(inlineMode);
        break;

      case 'IMAGE':
        handlePromptForMedia(inlineMode);
        break;

      case 'clear':
        handleClearFormat();
        break;

      case 'save':
        handleSave();
        break;

      default:
        handleCustomClick(style, id);
    }
  };

  const handlePastedText = (text, _html, editorState) => {
    return isMaxLengthHandled(editorState, text.length);
  };

  const handleReturn = (_e, editorState) => {
    return isMaxLengthHandled(editorState, 1);
  };

  const isMaxLengthHandled = (editorState, nextLength) => {
    const currentLength = editorState.getCurrentContent().getPlainText('').length;
    return (0, _utils.isGreaterThan)(currentLength + nextLength, props.maxLength) ? 'handled' : 'not-handled';
  };

  const toggleMouseUpListener = (addAfter = false) => {
    var _editorRef$current5;

    const editor = (_editorRef$current5 = editorRef.current) == null ? void 0 : _editorRef$current5.editor;

    if (!editor) {
      return;
    }

    editor.removeEventListener('mouseup', handleMouseUp);

    if (addAfter) {
      editor.addEventListener('mouseup', handleMouseUp);
    }
  };

  const removeLink = () => {
    const selection = editorState.getSelection();
    setEditorState(_draftJs.RichUtils.toggleLink(editorState, selection, null));
  };

  const confirmLink = url => {
    const {
      urlKey
    } = state;

    if (!url) {
      if (urlKey) {
        removeLink();
      }

      dismissPopover();
      return;
    }

    const contentState = editorState.getCurrentContent();
    let replaceEditorState = editorState;
    const data = {
      url: url,
      className: classes.anchorLink
    };

    if (urlKey) {
      contentState.replaceEntityData(urlKey, data);
      replaceEditorState = _draftJs.EditorState.push(editorState, contentState, 'apply-entity');
    } else {
      const contentStateWithEntity = contentState.createEntity('LINK', 'MUTABLE', data);
      const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

      const newEditorState = _draftJs.EditorState.set(editorState, {
        currentContent: contentStateWithEntity
      });

      replaceEditorState = _draftJs.RichUtils.toggleLink(newEditorState, newEditorState.getSelection(), entityKey);
    }

    updateStateForPopover(replaceEditorState);
  };

  const removeMedia = () => {
    const blockKey = editorState.getSelection().getStartKey();
    const contentState = editorState.getCurrentContent();
    const mediaBlock = contentState.getBlockForKey(blockKey);
    const newContentState = (0, _utils.removeBlockFromMap)(editorState, mediaBlock);

    const newEditorState = _draftJs.EditorState.push(editorState, newContentState, 'remove-range');

    setEditorState(newEditorState);
  };

  const confirmMedia = (url, width, height, alignment, type) => {
    const {
      urlKey
    } = state;

    if (!url) {
      if (urlKey) {
        removeMedia();
      }

      dismissPopover();
      return;
    }

    const contentState = editorState.getCurrentContent();
    const data = {
      url: url,
      width: width,
      height: height,
      alignment: alignment,
      type: type
    };

    if (urlKey) {
      contentState.replaceEntityData(urlKey, data);

      const newEditorState = _draftJs.EditorState.push(editorState, contentState, 'apply-entity');

      updateStateForPopover(_draftJs.EditorState.forceSelection(newEditorState, newEditorState.getCurrentContent().getSelectionAfter()));
    } else {
      const newEditorState = insertAtomicBlock(editorState, 'IMAGE', data);
      updateStateForPopover(_draftJs.EditorState.forceSelection(newEditorState, newEditorState.getCurrentContent().getSelectionAfter()));
    }

    setFocusMediaKey('');
  };

  const updateStateForPopover = editorState => {
    setEditorState(editorState);
    dismissPopover();
  };

  const dismissPopover = () => {
    refocus();
    setState(Object.assign({}, state, {
      anchorUrlPopover: undefined,
      urlKey: undefined,
      urlIsMedia: undefined,
      urlData: undefined
    }));
  };

  const refocus = () => {
    setTimeout(() => {
      var _editorRef$current6;

      return (_editorRef$current6 = editorRef.current) == null ? void 0 : _editorRef$current6.blur();
    }, 0);
    setTimeout(() => {
      var _editorRef$current7;

      return (_editorRef$current7 = editorRef.current) == null ? void 0 : _editorRef$current7.focus();
    }, 1);
  };

  const toggleBlockType = blockType => {
    setEditorState(_draftJs.RichUtils.toggleBlockType(editorState, blockType));
  };

  const toggleInlineStyle = inlineStyle => {
    setEditorState(_draftJs.RichUtils.toggleInlineStyle(editorState, inlineStyle));
  };

  const focusMedia = block => {
    const newSeletion = _draftJs.SelectionState.createEmpty(block.getKey());

    const newEditorState = _draftJs.EditorState.forceSelection(editorStateRef.current, newSeletion);

    editorStateRef.current = newEditorState;
    setFocusMediaKey(block.getKey());
    setEditorState(newEditorState);
    handlePromptForMedia(false, newEditorState);
  };

  const getStyleMap = () => {
    if (customStyleMapRef.current === undefined) {
      setupStyleMap();
    }

    return customStyleMapRef.current;
  };

  const setupStyleMap = () => {
    var _props$customControls;

    const customStyleMap = JSON.parse(JSON.stringify(styleRenderMap));
    (_props$customControls = props.customControls) == null ? void 0 : _props$customControls.filter(control => control.type === 'inline' && control.inlineStyle).forEach(control => {
      customStyleMap[control.name.toUpperCase()] = control.inlineStyle;
    });
    customStyleMapRef.current = customStyleMap;
  };

  const getBlockMap = () => {
    if (customBlockMapRef.current === undefined) {
      setupBlockMap();
    }

    return customBlockMapRef.current;
  };

  const setupBlockMap = () => {
    var _props$customControls2;

    const customBlockMap = {};
    (_props$customControls2 = props.customControls) == null ? void 0 : _props$customControls2.filter(control => control.type === 'block' && control.blockWrapper).forEach(control => {
      customBlockMap[control.name.toUpperCase()] = {
        element: 'div',
        wrapper: control.blockWrapper
      };
    });
    customBlockMapRef.current = _draftJs.DefaultDraftBlockRenderMap.merge(blockRenderMap, _immutable.default.Map(customBlockMap));
  };

  const blockRenderer = contentBlock => {
    const blockType = contentBlock.getType();

    if (blockType === 'atomic') {
      const contentState = editorState.getCurrentContent();
      const entity = contentBlock.getEntityAt(0);

      if (entity) {
        const type = contentState.getEntity(entity).getType();

        if (type === 'IMAGE') {
          return {
            component: _Media.default,
            editable: false,
            props: {
              onClick: focusMedia,
              readOnly: props.readOnly,
              focusKey: focusMediaKey
            }
          };
        } else {
          const block = (0, _utils.atomicBlockExists)(type.toLowerCase(), props.customControls);

          if (block) {
            return {
              component: block.atomicComponent,
              editable: false,
              props: contentState.getEntity(contentBlock.getEntityAt(0)).getData()
            };
          }
        }
      }
    }

    return null;
  };

  const styleRenderer = style => {
    const customStyleMap = getStyleMap();
    const styleNames = style.toJS();
    return styleNames.reduce((styles, styleName) => {
      styles = customStyleMap[styleName];
      return styles;
    }, {});
  };

  const insertAtomicBlock = (editorState, type, data, options) => {
    const contentState = editorState.getCurrentContent();
    const contentStateWithEntity = contentState.createEntity(type, 'IMMUTABLE', data);
    const entityKey = contentStateWithEntity.getLastCreatedEntityKey();

    const newEditorStateRaw = _draftJs.EditorState.set(editorState, Object.assign({
      currentContent: contentStateWithEntity
    }, options));

    return _draftJs.AtomicBlockUtils.insertAtomicBlock(newEditorStateRaw, entityKey, ' ');
  };

  const getAutocompleteKeyEvent = keyboardEvent => {
    const itemsLength = getAutocompleteItems().length;
    const limit = autocompleteLimit > itemsLength ? itemsLength : autocompleteLimit;

    switch (keyboardEvent.key) {
      case 'ArrowDown':
        if (selectedIndex === 0 && itemsLength === 1 || selectedIndex + 1 === limit) {
          setSelectedIndex(0);
        } else {
          setSelectedIndex(selectedIndex + 1 < limit ? selectedIndex + 1 : selectedIndex);
        }

        return 'mui-autocomplete-navigate';

      case 'ArrowUp':
        if (selectedIndex) {
          setSelectedIndex(selectedIndex - 1);
        } else {
          setSelectedIndex(limit - 1);
        }

        return 'mui-autocomplete-navigate';

      case 'Enter':
        return 'mui-autocomplete-insert';

      case 'Escape':
        return 'mui-autocomplete-end';

      default:
        return null;
    }
  };

  const updateSearchTermForKeyBinding = keyBinding => {
    const text = editorStateRef.current.getCurrentContent().getLastBlock().getText();

    if (keyBinding === 'backspace' && autocompleteRef.current && text.substr(text.length - 1) === autocompleteRef.current.triggerChar) {
      clearSearch();
    } else if (autocompletePositionRef.current && keyBinding === 'backspace' && searchTerm.length) {
      setSearchTerm(searchTerm.substr(0, searchTerm.length - 1));
    } else if (!autocompletePositionRef.current && (keyBinding === 'backspace' || keyBinding === 'split-block')) {
      clearSearch();
    }
  };

  const keyBindingFn = e => {
    if (hasCommandModifier(e) && props.keyCommands) {
      const comm = props.keyCommands.find(comm => comm.key === e.keyCode);

      if (comm) {
        return comm.name;
      }
    }

    if (searchTerm) {
      const autocompleteEvent = getAutocompleteKeyEvent(e);

      if (autocompleteEvent) {
        return autocompleteEvent;
      }
    }

    const keyBinding = (0, _draftJs.getDefaultKeyBinding)(e);
    updateSearchTermForKeyBinding(keyBinding);
    return keyBinding;
  };

  const renderToolbar = props.toolbar === undefined || props.toolbar;
  const inlineToolbarControls = props.inlineToolbarControls || defaultInlineToolbarControls;
  const editable = props.readOnly === undefined || !props.readOnly;
  let className = '';
  let placeholder = null;

  if (!focus) {
    const contentState = editorState.getCurrentContent();

    if (!contentState.hasText()) {
      placeholder = /*#__PURE__*/_react.default.createElement("div", {
        className: (0, _classnames.default)(classes.editorContainer, classes.placeHolder, {
          [classes.error]: props.error
        }),
        tabIndex: 0,
        onFocus: handlePlaceholderFocus
      }, props.label || '');
      className = classes.hidePlaceholder;
    }
  }

  return /*#__PURE__*/_react.default.createElement(Root, {
    id: `${editorId}-root`,
    className: classes.root
  }, /*#__PURE__*/_react.default.createElement("div", {
    id: `${editorId}-container`,
    className: (0, _classnames.default)(classes.container, {
      [classes.inheritFontSize]: props.inheritFontSize
    })
  }, props.autocomplete && autocompletePositionRef.current ? /*#__PURE__*/_react.default.createElement(_Autocomplete.default, {
    items: getAutocompleteItems(),
    top: autocompletePositionRef.current.top,
    left: autocompletePositionRef.current.left,
    onClick: handleAutocompleteSelected,
    selectedIndex: selectedIndex
  }) : null, props.inlineToolbar && editable && state.toolbarPosition ? /*#__PURE__*/_react.default.createElement(_material.Paper, {
    className: classes.inlineToolbar,
    style: {
      top: state.toolbarPosition.top,
      left: state.toolbarPosition.left
    }
  }, /*#__PURE__*/_react.default.createElement(_Toolbar.default, {
    id: editorId,
    editorState: editorState,
    onClick: handleToolbarClick,
    controls: inlineToolbarControls,
    customControls: customControls,
    inlineMode: true,
    isActive: true
  })) : null, renderToolbar ? /*#__PURE__*/_react.default.createElement(_Toolbar.default, {
    id: editorId,
    editorState: editorState,
    onClick: handleToolbarClick,
    controls: controls,
    customControls: customControls,
    className: classes.toolbar,
    disabled: !editable,
    size: props.toolbarButtonSize,
    isActive: focus
  }) : null, placeholder, /*#__PURE__*/_react.default.createElement("div", {
    id: `${editorId}-editor`,
    className: classes.editor
  }, /*#__PURE__*/_react.default.createElement("div", {
    id: `${editorId}-editor-container`,
    className: (0, _classnames.default)(className, classes.editorContainer, {
      [classes.editorReadOnly]: !editable,
      [classes.error]: props.error
    }),
    onMouseDown: handleMouseDown,
    onBlur: handleBlur
  }, /*#__PURE__*/_react.default.createElement(_draftJs.Editor, _extends({
    blockRenderMap: getBlockMap(),
    blockRendererFn: blockRenderer,
    customStyleFn: styleRenderer,
    editorState: editorState,
    onChange: handleChange,
    onFocus: handleEditorFocus,
    readOnly: props.readOnly,
    handleKeyCommand: handleKeyCommand,
    handleBeforeInput: handleBeforeInput,
    handlePastedText: handlePastedText,
    handleReturn: handleReturn,
    keyBindingFn: keyBindingFn,
    ref: editorRef
  }, props.draftEditorProps)))), state.anchorUrlPopover ? /*#__PURE__*/_react.default.createElement(_UrlPopover.default, {
    data: state.urlData,
    anchor: state.anchorUrlPopover,
    onConfirm: handleConfirmPrompt,
    isMedia: state.urlIsMedia
  }) : null));
};

var _default = /*#__PURE__*/(0, _react.forwardRef)(RichTextEditor);

exports.default = _default;