{"version":3,"file":"rich_text_editor.vue.cjs","sources":["../../../components/rich_text_editor/rich_text_editor.vue"],"sourcesContent":["<!-- eslint-disable vue/no-static-inline-styles -->\n<!-- eslint-disable vue/no-bare-strings-in-template -->\n<!-- eslint-disable vue/no-restricted-class -->\n<template>\n  <div>\n    <!-- why the hell is this visibility: hidden by default??? -->\n    <bubble-menu\n      v-if=\"editor && link && !hideLinkBubbleMenu\"\n      :editor=\"editor\"\n      :should-show=\"bubbleMenuShouldShow\"\n      :tippy-options=\"tippyOptions\"\n      style=\"visibility: visible;\"\n    >\n      <div class=\"d-popover__dialog\">\n        <dt-stack\n          direction=\"row\"\n          class=\"d-rich-text-editor-bubble-menu__button-stack\"\n          gap=\"0\"\n        >\n          <dt-button\n            kind=\"muted\"\n            importance=\"clear\"\n            @click=\"editLink\"\n          >\n            Edit\n          </dt-button>\n          <dt-button\n            kind=\"muted\"\n            importance=\"clear\"\n            @click=\"openLink\"\n          >\n            Open link\n          </dt-button>\n          <dt-button\n            kind=\"danger\"\n            importance=\"clear\"\n            @click=\"removeLink\"\n          >\n            Remove\n          </dt-button>\n        </dt-stack>\n      </div>\n    </bubble-menu>\n    <editor-content\n      ref=\"editor\"\n      :editor=\"editor\"\n      class=\"d-rich-text-editor\"\n      data-qa=\"dt-rich-text-editor\"\n      v-on=\"editorListeners\"\n    />\n  </div>\n</template>\n\n<script>\n/* eslint-disable max-lines */\nimport { Editor, EditorContent, BubbleMenu } from '@tiptap/vue-2';\nimport { Extension } from '@tiptap/core';\nimport { DtButton } from '../button';\nimport { DtStack } from '../stack';\nimport Blockquote from '@tiptap/extension-blockquote';\nimport CodeBlock from '@tiptap/extension-code-block';\nimport Code from '@tiptap/extension-code';\nimport Document from '@tiptap/extension-document';\nimport Paragraph from '@tiptap/extension-paragraph';\nimport Placeholder from '@tiptap/extension-placeholder';\nimport HardBreak from '@tiptap/extension-hard-break';\nimport Bold from '@tiptap/extension-bold';\nimport BulletList from '@tiptap/extension-bullet-list';\nimport Italic from '@tiptap/extension-italic';\nimport TipTapLink from '@tiptap/extension-link';\nimport ListItem from '@tiptap/extension-list-item';\nimport OrderedList from '@tiptap/extension-ordered-list';\nimport Strike from '@tiptap/extension-strike';\nimport Underline from '@tiptap/extension-underline';\nimport Text from '@tiptap/extension-text';\nimport TextAlign from '@tiptap/extension-text-align';\nimport History from '@tiptap/extension-history';\nimport Emoji from './extensions/emoji';\nimport CustomLink from './extensions/custom_link';\nimport ConfigurableImage from './extensions/image';\nimport DivParagraph from './extensions/div';\nimport { MentionPlugin } from './extensions/mentions/mention';\nimport { ChannelPlugin } from './extensions/channels/channel';\nimport { SlashCommandPlugin } from './extensions/slash_command/slash_command';\nimport {\n  RICH_TEXT_EDITOR_OUTPUT_FORMATS,\n  RICH_TEXT_EDITOR_AUTOFOCUS_TYPES,\n  RICH_TEXT_EDITOR_SUPPORTED_LINK_PROTOCOLS,\n} from './rich_text_editor_constants';\nimport { emojiPattern } from 'regex-combined-emojis';\n\nimport mentionSuggestion from './extensions/mentions/suggestion';\nimport channelSuggestion from './extensions/channels/suggestion';\nimport slashCommandSuggestion from './extensions/slash_command/suggestion';\nimport { warnIfUnmounted } from '@/common/utils';\nimport deepEqual from 'deep-equal';\n\nexport default {\n  name: 'DtRichTextEditor',\n\n  components: {\n    EditorContent,\n    BubbleMenu,\n    DtButton,\n    DtStack,\n  },\n\n  props: {\n    /**\n     * Value of the input. The object format should match TipTap's JSON\n     * document structure: https://tiptap.dev/guide/output#option-1-json\n     */\n    value: {\n      type: [Object, String],\n      default: '',\n    },\n\n    /**\n     * Whether the input is editable\n     */\n    editable: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Prevents the user from typing any further. Deleting text will still work.\n     */\n    preventTyping: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Whether the input allows for line breaks to be introduced in the text by pressing enter. If this is disabled,\n     * line breaks can still be entered by pressing shift+enter.\n     */\n    allowLineBreaks: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Descriptive label for the input element\n     */\n    inputAriaLabel: {\n      type: String,\n      required: true,\n    },\n\n    /**\n     * Additional class name for the input element. Only accepts a String value\n     * because this is passed to the editor via options. For multiple classes,\n     * join them into one string, e.g. \"d-p8 d-hmx96\"\n     */\n    inputClass: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * Whether the input should receive focus after the component has been\n     * mounted. Either one of `start`, `end`, `all` or a Boolean or a Number.\n     * - `start`  Sets the focus to the beginning of the input\n     * - `end`    Sets the focus to the end of the input\n     * - `all`    Selects the whole contents of the input\n     * - `Number` Sets the focus to a specific position in the input\n     * - `true`   Defaults to `start`\n     * - `false`  Disables autofocus\n     * @values true, false, start, end, all, number\n     */\n    autoFocus: {\n      type: [Boolean, String, Number],\n      default: false,\n      validator (autoFocus) {\n        if (typeof autoFocus === 'string') {\n          return RICH_TEXT_EDITOR_AUTOFOCUS_TYPES.includes(autoFocus);\n        }\n        return true;\n      },\n    },\n\n    /**\n     * The output format that the editor uses when emitting the \"@input\" event.\n     * One of `text`, `json`, `html`. See https://tiptap.dev/guide/output for\n     * examples.\n     * @values text, json, html\n     */\n    outputFormat: {\n      type: String,\n      default: 'html',\n      validator (outputFormat) {\n        return RICH_TEXT_EDITOR_OUTPUT_FORMATS.includes(outputFormat);\n      },\n    },\n\n    /**\n     * Placeholder text\n     */\n    placeholder: {\n      type: String,\n      default: '',\n    },\n\n    /**\n     * Enables the TipTap Link extension and optionally passes configurations to it\n     *\n     * It is not recommended to use this and the custom link extension at the same time.\n     */\n    link: {\n      type: [Boolean, Object],\n      default: false,\n    },\n\n    /**\n     * Enables the Custom Link extension and optionally passes configurations to it\n     *\n     * It is not recommended to use this and the built in TipTap link extension at the same time.\n     *\n     * The custom link does some additional things on top of the built in TipTap link\n     * extension such as styling phone numbers and IP adresses as links, and allows you\n     * to linkify text without having to type a space after the link. Currently it is missing some\n     * functionality such as editing links and will likely require more work to be fully usable,\n     * so it is recommended to use the built in TipTap link for now.\n     */\n    customLink: {\n      type: [Boolean, Object],\n      default: false,\n    },\n\n    /**\n     * suggestion object containing the items query function.\n     * The valid keys passed into this object can be found here: https://tiptap.dev/api/utilities/suggestion\n     *\n     * The only required key is the items function which is used to query the contacts for suggestion.\n     * items({ query }) => { return [ContactObject]; }\n     * ContactObject format:\n     * { name: string, avatarSrc: string, id: string }\n     *\n     * When null, it does not add the plugin.\n     */\n    mentionSuggestion: {\n      type: Object,\n      default: null,\n    },\n\n    /**\n     * suggestion object containing the items query function.\n     * The valid keys passed into this object can be found here: https://tiptap.dev/api/utilities/suggestion\n     *\n     * The only required key is the items function which is used to query the channels for suggestion.\n     * items({ query }) => { return [ChannelObject]; }\n     * ChannelObject format:\n     * { name: string, id: string, locked: boolean }\n     *\n     * When null, it does not add the plugin. Setting locked to true will display a lock rather than hash.\n     */\n    channelSuggestion: {\n      type: Object,\n      default: null,\n    },\n\n    /**\n     * suggestion object containing the items query function.\n     * The valid keys passed into this object can be found here: https://tiptap.dev/api/utilities/suggestion\n     *\n     * The only required key is the items function which is used to query the slash commands for suggestion.\n     * items({ query }) => { return [SlashCommandObject]; }\n     * SlashCommandObject format:\n     * { command: string, description: string, parametersExample?: string }\n     * The \"parametersExample\" parameter is optional, and describes an example\n     * of the parameters that command can take.\n     *\n     * When null, it does not add the plugin.\n     * Note that slash commands only work when they are the first word in the input.\n     */\n    slashCommandSuggestion: {\n      type: Object,\n      default: null,\n    },\n\n    /**\n     * Whether the input allows for block quote.\n     */\n    allowBlockquote: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows for bold to be introduced in the text.\n     */\n    allowBold: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows for bullet list to be introduced in the text.\n     */\n    allowBulletList: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows for italic to be introduced in the text.\n     */\n    allowItalic: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows for strike to be introduced in the text.\n     */\n    allowStrike: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows for underline to be introduced in the text.\n     */\n    allowUnderline: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows inline code (wrapped in backticks).\n     */\n    allowCode: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows codeblock to be introduced in the text.\n     */\n    allowCodeblock: {\n      type: Boolean,\n      default: true,\n    },\n\n    /**\n     * Whether the input allows inline images to be rendered.\n     */\n    allowInlineImages: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Additional TipTap extensions to be added to the editor.\n     */\n    additionalExtensions: {\n      type: Array,\n      default: () => [],\n    },\n\n    /**\n     * Manually hide the link bubble menu. The link bubble menu is shown when a link is selected via the cursor.\n     * There are some cases when you may want the link to remain selected but hide the bubble menu such as when You\n     * are showing a custom link editor popup.\n     */\n    hideLinkBubbleMenu: {\n      type: Boolean,\n      default: false,\n    },\n\n    /**\n     * Show text in HTML div tags instead of paragraph tags\n     */\n    useDivTags: {\n      type: Boolean,\n      default: false,\n    },\n  },\n\n  emits: [\n    /**\n     * Editor input event\n     * @event input\n     * @type {String|JSON}\n     */\n    'input',\n\n    /**\n     * Input event always in JSON format.\n     * @event input\n     * @type {JSON}\n     */\n    'json-input',\n\n    /**\n     * Input event always in HTML format.\n     * @event input\n     * @type {HTML}\n     */\n    'html-input',\n\n    /**\n     * Input event always in text format.\n     * @event input\n     * @type {String}\n     */\n    'text-input',\n\n    /**\n     * Event to sync the value with the parent\n     * @event update:value\n     * @type {String|JSON}\n     */\n    'update:value',\n\n    /**\n     * Editor blur event\n     * @event blur\n     * @type {FocusEvent}\n     */\n    'blur',\n\n    /**\n     * Editor focus event\n     * @event focus\n     * @type {FocusEvent}\n     */\n    'focus',\n\n    /**\n     * Enter was pressed. Note that shift enter must be pressed to line break the input.\n     * @event enter\n     * @type {String}\n     */\n    'enter',\n\n    /**\n     * \"Edit link\" button was clicked. Fires an event for the consuming component to handle the editing of the link.\n     * event contains the link object with two properties href and text.\n     * @event edit-link\n     * @type {Object}\n     */\n    'edit-link',\n\n    /**\n     * \"Selected\" event is fired when the user selects text in the editor. returns the currently selected text.\n     * If the selected text is partially a link, the full link text is returned.\n     * @event selected\n     * @type {String}\n     */\n    'selected',\n  ],\n\n  data () {\n    return {\n      editor: null,\n      tippyOptions: {\n        appendTo: () => this.$refs.editor.$el.getRootNode()?.querySelector('body'),\n        placement: 'top-start',\n      },\n    };\n  },\n\n  computed: {\n    editorListeners () {\n      return {\n        ...this.$listeners,\n        input: () => {},\n        focus: () => {},\n        blur: () => {},\n      };\n    },\n\n    // eslint-disable-next-line complexity\n    extensions () {\n      // These are the default extensions needed just for plain text.\n      const extensions = [Document, Text, History, HardBreak];\n      extensions.push(this.useDivTags ? DivParagraph : Paragraph);\n\n      if (this.allowBlockquote) {\n        extensions.push(Blockquote);\n      }\n      if (this.allowBold) {\n        extensions.push(Bold);\n      }\n      if (this.allowBulletList) {\n        extensions.push(BulletList);\n        extensions.push(ListItem.extend({\n          renderText ({ node }) {\n            return node.textContent;\n          },\n        }));\n        extensions.push(OrderedList);\n      }\n      if (this.allowItalic) {\n        extensions.push(Italic);\n      }\n      if (this.allowStrike) {\n        extensions.push(Strike);\n      }\n      if (this.allowUnderline) {\n        extensions.push(Underline);\n      }\n\n      // Enable placeholderText\n      if (this.placeholder) {\n        extensions.push(\n          Placeholder.configure({ placeholder: this.placeholder }),\n        );\n      }\n\n      const self = this;\n      const ShiftEnter = Extension.create({\n        addKeyboardShortcuts () {\n          return {\n            'Shift-Enter': ({ editor }) => {\n              if (self.allowLineBreaks) {\n                return false;\n              }\n              editor.commands.first(({ commands }) => [\n                () => commands.newlineInCode(),\n                () => self.allowBulletList && commands.splitListItem('listItem'),\n                () => commands.createParagraphNear(),\n                () => commands.liftEmptyBlock(),\n                () => commands.splitBlock(),\n              ]);\n              return true;\n            },\n            Enter: () => {\n              if (self.allowLineBreaks) {\n                return false;\n              }\n              self.$emit('enter');\n              return true;\n            },\n          };\n        },\n      });\n      extensions.push(ShiftEnter);\n\n      if (this.link) {\n        extensions.push(TipTapLink.extend({ inclusive: false }).configure({\n          HTMLAttributes: {\n            class: 'd-link d-wb-break-all',\n          },\n          openOnClick: false,\n          autolink: true,\n          protocols: RICH_TEXT_EDITOR_SUPPORTED_LINK_PROTOCOLS,\n        }));\n      }\n      if (this.customLink) {\n        extensions.push(this.getExtension(CustomLink, this.customLink));\n      }\n\n      if (this.mentionSuggestion) {\n        // Add both the suggestion plugin as well as means for user to add suggestion items to the plugin\n        const suggestionObject = { ...this.mentionSuggestion, ...mentionSuggestion };\n        extensions.push(MentionPlugin.configure({ suggestion: suggestionObject }));\n      }\n\n      if (this.channelSuggestion) {\n        // Add both the suggestion plugin as well as means for user to add suggestion items to the plugin\n        const suggestionObject = { ...this.channelSuggestion, ...channelSuggestion };\n        extensions.push(ChannelPlugin.configure({ suggestion: suggestionObject }));\n      }\n\n      if (this.slashCommandSuggestion) {\n        // Add both the suggestion plugin as well as means for user to add suggestion items to the plugin\n        const suggestionObject = { ...this.slashCommandSuggestion, ...slashCommandSuggestion };\n        extensions.push(SlashCommandPlugin.configure({ suggestion: suggestionObject }));\n      }\n\n      // Emoji has some interactions with Enter key\n      // hence this should be done last otherwise the enter wont add a emoji.\n      extensions.push(Emoji);\n\n      extensions.push(TextAlign.configure({\n        types: ['paragraph'],\n        defaultAlignment: 'left',\n      }));\n\n      if (this.allowCode) {\n        extensions.push(Code);\n      }\n\n      if (this.allowCodeblock) {\n        extensions.push(CodeBlock.extend({\n          renderText ({ node }) {\n            return `\\`\\`\\`\\n${node.textContent}\\n\\`\\`\\``;\n          },\n        }).configure({\n          HTMLAttributes: {\n            class: 'd-rich-text-editor__code-block',\n          },\n        }));\n      }\n\n      if (this.allowInlineImages) {\n        extensions.push(ConfigurableImage);\n      }\n\n      if (this.additionalExtensions.length) {\n        extensions.push(...this.additionalExtensions);\n      }\n\n      return extensions;\n    },\n\n    inputAttrs () {\n      const attrs = {\n        'aria-label': this.inputAriaLabel,\n        'aria-multiline': true,\n        role: 'textbox',\n      };\n      if (!this.editable) {\n        attrs['aria-readonly'] = true;\n      }\n      return attrs;\n    },\n  },\n\n  /**\n   * Because the Editor instance is initialized when mounted it does not get\n   * updated props automatically, so the ones that can change after mount have\n   * to be hooked up to the Editor's own API.\n   */\n  watch: {\n    editable (isEditable) {\n      this.editor.setEditable(isEditable);\n      this.updateEditorAttributes({ 'aria-readonly': !isEditable });\n    },\n\n    inputClass (newClass) {\n      this.updateEditorAttributes({ class: newClass });\n    },\n\n    inputAriaLabel (newLabel) {\n      this.updateEditorAttributes({ 'aria-label': newLabel });\n    },\n\n    extensions () {\n      // Extensions can't be registered on the fly, so just recreate the editor.\n      // https://github.com/ueberdosis/tiptap/issues/1044\n      this.destroyEditor();\n      this.createEditor();\n    },\n\n    value (newValue) {\n      this.processValue(newValue);\n    },\n  },\n\n  created () {\n    this.createEditor();\n  },\n\n  beforeUnmount () {\n    this.destroyEditor();\n  },\n\n  mounted () {\n    warnIfUnmounted(this.$el, this.$options.name);\n    this.processValue(this.value, false);\n  },\n\n  methods: {\n    createEditor () {\n      // For all available options, see https://tiptap.dev/api/editor#settings\n      this.editor = new Editor({\n        autofocus: this.autoFocus,\n        content: this.value,\n        editable: this.editable,\n        extensions: this.extensions,\n        editorProps: {\n          attributes: {\n            ...this.inputAttrs,\n            class: this.inputClass,\n          },\n\n          handlePaste: (_, event) => {\n            // When having link and customLink props we should maintain default paste behavior\n            if (!this.link && !this.customLink) {\n              const regex = /^https?:\\/\\//;\n\n              if (!event?.clipboardData) {\n                return false;\n              }\n              const pastedContent = event.clipboardData.getData('text');\n\n              // Check if the pasted content is a valid URL (starting with http:// or https://)\n              // If it's not a URL, allow the default paste behavior\n              if (!regex.test(pastedContent)) {\n                return false;\n              }\n\n              // If `text/html` is missing from clipboard data, it's a plain link\n              // In this case, allow the default paste behavior\n              if (!event.clipboardData.getData('text/html')) {\n                return false;\n              }\n\n              this.editor.chain().focus().insertContent(pastedContent).run();\n              return true; // Prevent the default paste behavior\n            }\n\n            return false; // Allow the default paste behavior\n          },\n\n          // Moves the <br /> tags inside the previous closing tag to avoid\n          // Prosemirror wrapping them within another </p> tag.\n          transformPastedHTML (html) {\n            return html.replace(/(<\\/\\w+>)((<br \\/>)+)/g, '$2$3$1');\n          },\n        },\n      });\n      this.addEditorListeners();\n    },\n\n    bubbleMenuShouldShow ({ editor, view, state, oldState, from, to }) {\n      return editor.isActive('link');\n    },\n\n    /**\n     * If the selection contains a link, return the existing link text.\n     * Otherwise, use just the selected text.\n     * @param editor the editor instance.\n     */\n    getSelectedLinkText (editor) {\n      const { view, state } = editor;\n      const { from, to } = view.state.selection;\n      const text = state.doc.textBetween(from, to, '');\n      const linkNode = this.editor.state.doc.nodeAt(from);\n      if (linkNode && linkNode.marks?.at(0)?.type?.name === 'link') {\n        return linkNode.textContent;\n      } else {\n        return text;\n      }\n    },\n\n    editLink () {\n      const linkText = this.getSelectedLinkText(this.editor);\n\n      const link = {\n        href: this.editor.getAttributes('link').href,\n        text: linkText,\n      };\n      this.$emit('edit-link', link);\n    },\n\n    removeLink () {\n      this.editor?.chain()?.focus()?.unsetLink()?.run();\n    },\n\n    openLink () {\n      this.editor?.chain()?.focus();\n      const link = this.editor.getAttributes('link').href;\n      window.open(link, '_blank');\n    },\n\n    // eslint-disable-next-line complexity\n    setLink (linkInput, linkText, linkOptions, linkProtocols = RICH_TEXT_EDITOR_SUPPORTED_LINK_PROTOCOLS,\n      defaultPrefix) {\n      if (!linkInput) {\n        // If link text is set to empty string,\n        // remove any existing links.\n        this.removeLink();\n        return;\n      }\n\n      // Check if input matches any of the supported link formats\n      const prefix = linkProtocols.find(prefixRegex => prefixRegex.test(linkInput));\n\n      if (!prefix) {\n        // If no matching pattern is found, prepend default prefix\n        linkInput = `${defaultPrefix}${linkInput}`;\n      }\n\n      this.editor\n        .chain()\n        .focus()\n        .extendMarkRange('link')\n        .run();\n\n      const selection = this.editor?.view?.state?.selection;\n\n      this.editor\n        .chain()\n        .focus()\n        .insertContent(linkText)\n        .setTextSelection({ from: selection.from, to: selection.from + linkText.length })\n        .setLink({ href: linkInput, class: linkOptions.class })\n        .run();\n    },\n\n    // eslint-disable-next-line complexity\n    processValue (newValue, returnIfEqual = true) {\n      const currentValue = this.getOutput();\n\n      if (returnIfEqual && deepEqual(newValue, currentValue)) {\n        // The new value came from this component and was passed back down\n        // through the parent, so don't do anything here.\n        return;\n      }\n\n      // If the text contains emoji characters convert them to emoji component tags\n      if (typeof newValue === 'string' && this.outputFormat === 'text') {\n        const inputUnicodeRegex = new RegExp(`(${emojiPattern})`, 'g');\n        newValue = newValue?.replace(inputUnicodeRegex, '<emoji-component code=\"$1\"></emoji-component>');\n      }\n\n      // Otherwise replace the content (resets the cursor position).\n      this.editor.commands.setContent(newValue, false);\n    },\n\n    destroyEditor () {\n      this.editor.destroy();\n    },\n\n    triggerInputChangeEvents () {\n      const value = this.getOutput();\n      this.$emit('input', value);\n      this.$emit('update:value', value);\n\n      // Always output JSON in a separate event\n      const jsonValue = this.editor.getJSON();\n      this.$emit('json-input', jsonValue);\n\n      // Always output HTML in a separate event\n      const htmlValue = this.editor.getHTML();\n      this.$emit('html-input', htmlValue);\n\n      // Always output HTML in a separate event\n      const textValue = this.editor.getText({ blockSeparator: '\\n' });\n      this.$emit('text-input', textValue);\n    },\n\n    /**\n     * The Editor exposes event hooks that we have to map our emits into. See\n     * https://tiptap.dev/api/events for all events.\n     */\n    addEditorListeners () {\n      this.editor.on('create', () => {\n        this.triggerInputChangeEvents();\n      });\n      // The content has changed.\n      this.editor.on('update', () => {\n        // When preventTyping is true and user wants to type, we revert to last value\n        // If Backspace (keyCode = 8) is pressed, we allow updating the text\n        if (this.preventTyping && this.editor.view?.input?.lastKeyCode !== 8) {\n          this.editor.commands.setContent(this.value, false);\n          return;\n        }\n        this.triggerInputChangeEvents();\n      });\n\n      this.editor.on('selectionUpdate', ({ editor }) => {\n        this.$emit('selected', this.getSelectedLinkText(editor));\n      });\n\n      // The editor is focused.\n      this.editor.on('focus', ({ event }) => {\n        this.$emit('focus', event);\n      });\n\n      // The editor isn’t focused anymore.\n      this.editor.on('blur', ({ event }) => {\n        this.$emit('blur', event);\n      });\n    },\n\n    getOutput () {\n      switch (this.outputFormat) {\n        case 'json':\n          return this.editor.getJSON();\n        case 'html':\n          return this.editor.getHTML();\n        case 'text':\n        default:\n          return this.editor.getText({ blockSeparator: '\\n' });\n      }\n    },\n\n    getExtension (extension, options) {\n      if (typeof options === 'boolean') {\n        return extension;\n      }\n      return extension.configure?.(options);\n    },\n\n    updateEditorAttributes (attributes) {\n      this.editor.setOptions({\n        editorProps: {\n          attributes: {\n            ...this.inputAttrs,\n            class: this.inputClass,\n            ...attributes,\n          },\n        },\n      });\n    },\n\n    focusEditor () {\n      this.editor.commands.focus();\n    },\n  },\n};\n</script>\n"],"names":["EditorContent","BubbleMenu","DtButton","DtStack","RICH_TEXT_EDITOR_AUTOFOCUS_TYPES","RICH_TEXT_EDITOR_OUTPUT_FORMATS","DivParagraph","Extension","RICH_TEXT_EDITOR_SUPPORTED_LINK_PROTOCOLS","CustomLink","mentionSuggestion","MentionPlugin","channelSuggestion","ChannelPlugin","slashCommandSuggestion","SlashCommandPlugin","Emoji","ConfigurableImage","warnIfUnmounted","Editor","emojiPattern"],"mappings":"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"}