From 220359b1c9b01ac1c499395b0a69cd46d68b87c5 Mon Sep 17 00:00:00 2001
From: Davide Silvestri <davide@baserow.io>
Date: Thu, 22 Feb 2024 12:27:49 +0000
Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9A1=EF=B8=8F=E2=83=A3=20Rich=20text:?=
 =?UTF-8?q?=20Grid=20view=20and=20Row=20edit=20modal=20editor=20components?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../contrib/database/fields/field_types.py    |   2 +
 .../baserow/contrib/database/fields/models.py |   4 +-
 ...ngtextfield_enable_rich_text_formatting.py |  21 ++
 .../scss/components/rich_text_editor.scss     |  32 +-
 .../components/row_comments/RowComment.vue    |   4 +-
 .../RowCommentMentionNotification.vue         |   6 +-
 .../row_comments/RowCommentNotification.vue   |   6 +-
 .../row_comments/RowCommentsSidebar.vue       |   5 +-
 web-frontend/config/nuxt.config.base.js       |   7 +-
 .../core/assets/scss/components/all.scss      |   1 +
 .../scss/components/fields/rich_text.scss     |  13 +
 .../scss/components/views/grid/long_text.scss |  27 ++
 .../core/components/editor/RichTextEditor.vue | 224 +++++++++----
 .../components/field/FieldLongTextSubForm.vue |  35 ++
 .../components/row/RowEditFieldRichText.vue   |  44 +++
 .../components/view/grid/GridViewCell.vue     |   2 +-
 .../view/grid/fields/GridViewFieldFormula.vue |   2 +-
 .../grid/fields/GridViewFieldRichText.vue     |  64 ++++
 web-frontend/modules/database/fieldTypes.js   |  25 +-
 web-frontend/modules/database/locales/en.json |   3 +
 web-frontend/package.json                     |  37 +-
 web-frontend/yarn.lock                        | 317 +++++++++++++-----
 22 files changed, 705 insertions(+), 176 deletions(-)
 create mode 100644 backend/src/baserow/contrib/database/migrations/0152_longtextfield_enable_rich_text_formatting.py
 create mode 100644 web-frontend/modules/core/assets/scss/components/fields/rich_text.scss
 create mode 100644 web-frontend/modules/database/components/field/FieldLongTextSubForm.vue
 create mode 100644 web-frontend/modules/database/components/row/RowEditFieldRichText.vue
 create mode 100644 web-frontend/modules/database/components/view/grid/fields/GridViewFieldRichText.vue

diff --git a/backend/src/baserow/contrib/database/fields/field_types.py b/backend/src/baserow/contrib/database/fields/field_types.py
index e6a713ba3..011242a15 100755
--- a/backend/src/baserow/contrib/database/fields/field_types.py
+++ b/backend/src/baserow/contrib/database/fields/field_types.py
@@ -402,6 +402,8 @@ class TextFieldType(CollationSortMixin, FieldType):
 class LongTextFieldType(CollationSortMixin, FieldType):
     type = "long_text"
     model_class = LongTextField
+    allowed_fields = ["long_text_enable_rich_text"]
+    serializer_field_names = ["long_text_enable_rich_text"]
     _can_group_by = True
 
     def get_serializer_field(self, instance, **kwargs):
diff --git a/backend/src/baserow/contrib/database/fields/models.py b/backend/src/baserow/contrib/database/fields/models.py
index e512815bc..e84ccc877 100644
--- a/backend/src/baserow/contrib/database/fields/models.py
+++ b/backend/src/baserow/contrib/database/fields/models.py
@@ -257,7 +257,9 @@ class TextField(Field):
 
 
 class LongTextField(Field):
-    pass
+    long_text_enable_rich_text = models.BooleanField(
+        default=False, null=True, help_text="Enable rich text formatting for the field."
+    )  # TODO: Remove null=True in a future release.
 
 
 class URLField(Field):
diff --git a/backend/src/baserow/contrib/database/migrations/0152_longtextfield_enable_rich_text_formatting.py b/backend/src/baserow/contrib/database/migrations/0152_longtextfield_enable_rich_text_formatting.py
new file mode 100644
index 000000000..75539ceed
--- /dev/null
+++ b/backend/src/baserow/contrib/database/migrations/0152_longtextfield_enable_rich_text_formatting.py
@@ -0,0 +1,21 @@
+# Generated by Django 4.1.13 on 2024-02-09 15:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("database", "0151_tableusageupdate_tableusage"),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name="longtextfield",
+            name="long_text_enable_rich_text",
+            field=models.BooleanField(
+                default=False,
+                help_text="Enable rich text formatting for the field.",
+                null=True,
+            ),
+        ),
+    ]
diff --git a/premium/web-frontend/modules/baserow_premium/assets/scss/components/rich_text_editor.scss b/premium/web-frontend/modules/baserow_premium/assets/scss/components/rich_text_editor.scss
index 553e35563..bbd667f5c 100644
--- a/premium/web-frontend/modules/baserow_premium/assets/scss/components/rich_text_editor.scss
+++ b/premium/web-frontend/modules/baserow_premium/assets/scss/components/rich_text_editor.scss
@@ -1,13 +1,39 @@
 .rich-text-editor {
   width: 100%;
-  background-color: white;
-  max-height: 60vh;
-  overflow-y: auto;
+  height: 100%;
   text-align: left;
 
+  .tiptap.ProseMirror {
+    height: 100%;
+  }
+
   p {
+    margin: 0;
     color: revert;
   }
+
+  ul {
+    list-style-type: disc;
+  }
+
+  blockquote {
+    margin: 1rem;
+    padding-left: 1rem;
+    color: $color-neutral-700;
+    border-left: 4px solid $color-neutral-300;
+  }
+
+  pre {
+    padding: 1rem;
+    background-color: $color-neutral-100;
+    border-radius: $rounded;
+  }
+}
+
+.rich-text-editor__comment {
+  max-height: 60vh;
+  overflow-y: auto;
+  background-color: white;
 }
 
 .rich-text-editor__mention {
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowComment.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowComment.vue
index d645c0c1a..f1acb48da 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowComment.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowComment.vue
@@ -60,7 +60,9 @@
         ref="editor"
         v-model="message"
         :editable="editing"
-        @entered="stopEdit(true)"
+        :enable-mentions="true"
+        :enter-stop-edit="true"
+        @stop-edit="stopEdit(true)"
       />
     </div>
     <div v-if="editing" class="row_comments__comment-text-actions">
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
index d691f4989..b0cf19bcd 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentMentionNotification.vue
@@ -24,7 +24,11 @@
         </template>
       </i18n>
     </div>
-    <RichTextEditor :editable="false" :value="notification.data.message" />
+    <RichTextEditor
+      :editable="false"
+      :enable-mentions="true"
+      :value="notification.data.message"
+    />
   </nuxt-link>
 </template>
 
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
index 4cc88006f..2e2363e01 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentNotification.vue
@@ -22,7 +22,11 @@
         </template>
       </i18n>
     </div>
-    <RichTextEditor :editable="false" :value="notification.data.message" />
+    <RichTextEditor
+      :editable="false"
+      :enable-mentions="true"
+      :value="notification.data.message"
+    />
   </nuxt-link>
 </template>
 
diff --git a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentsSidebar.vue b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentsSidebar.vue
index ba6a0b79f..49f9d05b9 100644
--- a/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentsSidebar.vue
+++ b/premium/web-frontend/modules/baserow_premium/components/row_comments/RowCommentsSidebar.vue
@@ -85,8 +85,11 @@
           >
             <RichTextEditor
               v-model="comment"
+              editor-class="rich-text-editor__comment"
+              :enable-mentions="true"
               :placeholder="$t('rowCommentSidebar.comment')"
-              @entered="postComment()"
+              :enter-stop-edit="true"
+              @stop-edit="postComment()"
             />
           </div>
         </div>
diff --git a/web-frontend/config/nuxt.config.base.js b/web-frontend/config/nuxt.config.base.js
index bd70fdca5..753abf3e1 100644
--- a/web-frontend/config/nuxt.config.base.js
+++ b/web-frontend/config/nuxt.config.base.js
@@ -48,9 +48,14 @@ export default function (
     build: {
       extend(config, ctx) {
         config.node = { fs: 'empty' }
+        config.module.rules.push({
+          test: /\.(m|c)js$/,
+          include: /node_modules/,
+          type: 'javascript/auto',
+        })
       },
       babel: { compact: true },
-      transpile: ['axios'],
+      transpile: ['axios', 'tiptap-markdown'],
     },
   }
 }
diff --git a/web-frontend/modules/core/assets/scss/components/all.scss b/web-frontend/modules/core/assets/scss/components/all.scss
index a00836251..c8b95ac63 100644
--- a/web-frontend/modules/core/assets/scss/components/all.scss
+++ b/web-frontend/modules/core/assets/scss/components/all.scss
@@ -25,6 +25,7 @@
 @import 'fields/number';
 @import 'fields/rating';
 @import 'fields/long_text';
+@import 'fields/rich_text';
 @import 'fields/date';
 @import 'fields/link_row';
 @import 'fields/file';
diff --git a/web-frontend/modules/core/assets/scss/components/fields/rich_text.scss b/web-frontend/modules/core/assets/scss/components/fields/rich_text.scss
new file mode 100644
index 000000000..40d738161
--- /dev/null
+++ b/web-frontend/modules/core/assets/scss/components/fields/rich_text.scss
@@ -0,0 +1,13 @@
+.field-rich-text {
+  @extend .field-long-text;
+
+  overflow-y: auto;
+
+  &.active {
+    border-color: $palette-blue-500;
+  }
+
+  & .rich-text-editor[conteteditable='false'] {
+    background-color: $palette-neutral-700;
+  }
+}
diff --git a/web-frontend/modules/core/assets/scss/components/views/grid/long_text.scss b/web-frontend/modules/core/assets/scss/components/views/grid/long_text.scss
index 1c1b6b78c..9fe1010b6 100644
--- a/web-frontend/modules/core/assets/scss/components/views/grid/long_text.scss
+++ b/web-frontend/modules/core/assets/scss/components/views/grid/long_text.scss
@@ -32,3 +32,30 @@
     background-color: $color-primary-100;
   }
 }
+
+.grid-field-long-text--uniform {
+  & h1,
+  h2,
+  h3,
+  p,
+  a,
+  ul,
+  ol,
+  li,
+  blockquote,
+  pre,
+  code {
+    @extend %ellipsis;
+
+    @include fixed-height(32px, 13px);
+
+    padding: 0;
+    margin-top: 0;
+    margin-bottom: 0;
+    color: revert;
+  }
+
+  li::marker {
+    content: initial;
+  }
+}
diff --git a/web-frontend/modules/core/components/editor/RichTextEditor.vue b/web-frontend/modules/core/components/editor/RichTextEditor.vue
index 119f227af..73be2a127 100644
--- a/web-frontend/modules/core/components/editor/RichTextEditor.vue
+++ b/web-frontend/modules/core/components/editor/RichTextEditor.vue
@@ -1,11 +1,16 @@
 <template>
   <div>
     <RichTextEditorMentionsList
+      v-if="editable && enableMentions"
       ref="mentionsList"
       :show-search="false"
       :add-empty-item="false"
     />
-    <EditorContent :editor="editor" />
+    <EditorContent
+      class="rich-text-editor"
+      :class="[editorClass]"
+      :editor="editor"
+    />
   </div>
 </template>
 
@@ -18,22 +23,62 @@ import { Mention } from '@tiptap/extension-mention'
 import { Document } from '@tiptap/extension-document'
 import { Paragraph } from '@tiptap/extension-paragraph'
 import { HardBreak } from '@tiptap/extension-hard-break'
+import { Heading } from '@tiptap/extension-heading'
+import { ListItem } from '@tiptap/extension-list-item'
+import { BulletList } from '@tiptap/extension-bullet-list'
+import { OrderedList } from '@tiptap/extension-ordered-list'
+import { Bold } from '@tiptap/extension-bold'
+import { Italic } from '@tiptap/extension-italic'
+import { Strike } from '@tiptap/extension-strike'
+import { Underline } from '@tiptap/extension-underline'
+import { Subscript } from '@tiptap/extension-subscript'
+import { Superscript } from '@tiptap/extension-superscript'
+import { Blockquote } from '@tiptap/extension-blockquote'
+import { CodeBlock } from '@tiptap/extension-code-block'
+import { HorizontalRule } from '@tiptap/extension-horizontal-rule'
 import { Text } from '@tiptap/extension-text'
 import { Extension, mergeAttributes } from '@tiptap/core'
 import { Plugin, PluginKey } from '@tiptap/pm/state'
+import { Markdown } from 'tiptap-markdown'
 
 import RichTextEditorMentionsList from '@baserow/modules/core/components/editor/RichTextEditorMentionsList'
 import suggestion from '@baserow/modules/core/editor/suggestion'
 
+const richTextEditorExtensions = [
+  // Nodes
+  Heading.configure({ levels: [1, 2, 3] }),
+  ListItem,
+  OrderedList,
+  BulletList,
+  CodeBlock,
+  Blockquote,
+  HorizontalRule,
+  // Marks
+  Bold,
+  Italic,
+  Strike,
+  Underline,
+  Subscript,
+  Superscript,
+  // Extensions
+  Markdown,
+]
+
 // Please, note that we need to remap Enter to Shift-Enter for every extension
 // relying on it in order to emit an event when the user presses Enter.
-const EnterKeyExtension = Extension.create({
-  name: 'enterKeyEventHandler',
+const EnterStopEditExtension = Extension.create({
+  name: 'enterStopEditHandler',
+
+  addOptions() {
+    return {
+      shiftKey: false,
+    }
+  },
 
   addProseMirrorPlugins() {
     return [
       new Plugin({
-        key: new PluginKey('enterKeyEventHandler'),
+        key: new PluginKey('enterStopEditHandler'),
         props: {
           handleKeyDown: (view, event) => {
             const { doc } = view.state
@@ -41,17 +86,23 @@ const EnterKeyExtension = Extension.create({
             function isDocEmpty() {
               let isEmpty = true
               doc.descendants((node) => {
-                const textNodes = ['text', 'paragraph', 'hardBreak']
-                if (!textNodes.includes(node.type.name) || node.text?.trim()) {
+                const isContent =
+                  node.type.name !== 'hardBreak' &&
+                  !node.isText &&
+                  !node.isBlock
+                if (isContent || node.text?.trim()) {
                   isEmpty = false
                 }
               })
               return isEmpty
             }
 
-            if (event.key === 'Enter' && !event.shiftKey) {
+            if (
+              event.key === 'Enter' &&
+              event.shiftKey === this.options.shiftKey
+            ) {
               if (!isDocEmpty()) {
-                this.options.vueComponent.$emit('entered')
+                this.options.vueComponent.$emit('stop-edit')
               }
               return true
             }
@@ -81,6 +132,26 @@ export default {
       type: Boolean,
       default: true,
     },
+    editorClass: {
+      type: String,
+      default: '',
+    },
+    enableMentions: {
+      type: Boolean,
+      default: false,
+    },
+    enterStopEdit: {
+      type: Boolean,
+      default: false,
+    },
+    shiftEnterStopEdit: {
+      type: Boolean,
+      default: false,
+    },
+    enableRichTextFormatting: {
+      type: Boolean,
+      default: false,
+    },
   },
   data() {
     return {
@@ -91,8 +162,6 @@ export default {
     ...mapGetters({
       loggedUserId: 'auth/getUserId',
       workspace: 'workspace/getSelected',
-      isUserIdMemberOfSelectedWorkspace:
-        'workspace/isUserIdMemberOfSelectedWorkspace',
     }),
   },
   watch: {
@@ -103,70 +172,97 @@ export default {
       this.editor.commands.focus('end')
     },
     value(value) {
-      const jsonContent = this.editor.getJSON()
-
-      if (_.isEqual(jsonContent, value)) {
-        return
+      if (!_.isEqual(value, this.editor.getJSON())) {
+        this.editor.commands.setContent(value, false)
       }
-
-      this.editor.commands.setContent(value, false)
     },
   },
   mounted() {
-    const loggedUserId = this.loggedUserId
-    const originalRenderHTML = Mention.config.renderHTML
-    const isUserInWorkspace =
-      this.$store.getters['workspace/isUserIdMemberOfSelectedWorkspace']
-    const mentionsExt = Mention.extend({
-      renderHTML({ node, HTMLAttributes }) {
+    const extensions = this.getConfiguredExtensions()
+    this.initTiptapEditor(extensions)
+  },
+  unmounted() {
+    this.editor.destroy()
+  },
+  methods: {
+    getConfiguredExtensions() {
+      const extensions = [Document, Paragraph, Text, HardBreak]
+
+      if (this.enableRichTextFormatting) {
+        extensions.push(...richTextEditorExtensions)
+      }
+
+      if (this.enterStopEdit || this.shiftEnterStopEdit) {
+        const enterKeyExt = EnterStopEditExtension.configure({
+          vueComponent: this,
+          shiftKey: this.shiftEnterStopEdit,
+        })
+        extensions.push(enterKeyExt)
+      }
+      if (this.enableMentions) {
+        const renderHTML = this.customRenderHTMLForMentions()
+        const mentionsExt = Mention.configure({
+          renderHTML,
+          suggestion: suggestion({
+            component: this.$refs.mentionsList,
+          }),
+        })
+        extensions.push(mentionsExt)
+      }
+
+      if (this.placeholder) {
+        extensions.push(
+          Placeholder.configure({
+            placeholder: this.placeholder,
+          })
+        )
+      }
+      return extensions
+    },
+    initTiptapEditor(extensions) {
+      this.editor = new Editor({
+        content: this.value,
+        editable: this.editable,
+        extensions,
+        onUpdate: () => {
+          this.$emit('input', this.editor.getJSON())
+        },
+        onFocus: () => {
+          this.$emit('focus')
+        },
+        onBlur: () => {
+          this.$emit('blur')
+        },
+      })
+
+      if (this.editable && this.enableRichTextFormatting) {
+        this.editor.commands.unsetAllMarks()
+      }
+    },
+    customRenderHTMLForMentions() {
+      const loggedUserId = this.loggedUserId
+      const isUserInWorkspace =
+        this.$store.getters['workspace/isUserIdMemberOfSelectedWorkspace']
+      return ({ node, options }) => {
         let className = 'rich-text-editor__mention'
         if (node.attrs.id === loggedUserId) {
           className += ' rich-text-editor__mention--current-user'
         } else if (!isUserInWorkspace(node.attrs.id)) {
           className += ' rich-text-editor__mention--user-gone'
         }
-        return originalRenderHTML.call(this, {
-          node,
-          HTMLAttributes: mergeAttributes(HTMLAttributes, { class: className }),
-        })
-      },
-    }).configure({
-      suggestion: suggestion({
-        component: this.$refs.mentionsList,
-      }),
-    })
-    const enterKeyExt = EnterKeyExtension.configure({ vueComponent: this })
-    const extensions = [
-      Document,
-      Paragraph,
-      Text,
-      HardBreak,
-      enterKeyExt,
-      mentionsExt,
-    ]
-    if (this.placeholder) {
-      extensions.push(
-        Placeholder.configure({
-          placeholder: this.placeholder,
-        })
-      )
-    }
-    this.editor = new Editor({
-      content: this.value,
-      editable: this.editable,
-      editorProps: {
-        attributes: {
-          class: this.editable ? 'rich-text-editor' : null,
-        },
-      },
-      extensions,
-      onUpdate: () => {
-        this.$emit('input', this.editor.getJSON())
-      },
-    })
-  },
-  beforeDestroy() {
-    this.editor.destroy()
+        return [
+          'span',
+          mergeAttributes({ class: className }, this.HTMLAttributes),
+          `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`,
+        ]
+      }
+    },
+    focus() {
+      this.editor.commands.focus('end')
+    },
+    serializeToMarkdown() {
+      return this.editor.storage.markdown.getMarkdown()
+    },
   },
 }
 </script>
diff --git a/web-frontend/modules/database/components/field/FieldLongTextSubForm.vue b/web-frontend/modules/database/components/field/FieldLongTextSubForm.vue
new file mode 100644
index 000000000..78c39473d
--- /dev/null
+++ b/web-frontend/modules/database/components/field/FieldLongTextSubForm.vue
@@ -0,0 +1,35 @@
+<template>
+  <div>
+    <div v-if="$featureFlagIsEnabled('rich-text-field')" class="control">
+      <div class="control__elements">
+        <Checkbox v-model="values.long_text_enable_rich_text">{{
+          $t('fieldLongTextSubForm.enableRichTextFormatting')
+        }}</Checkbox>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import form from '@baserow/modules/core/mixins/form'
+
+import fieldSubForm from '@baserow/modules/database/mixins/fieldSubForm'
+
+export default {
+  name: 'FieldTextSubForm',
+  mixins: [form, fieldSubForm],
+  data() {
+    return {
+      allowedValues: ['long_text_enable_rich_text'],
+      values: {
+        long_text_enable_rich_text: false,
+      },
+    }
+  },
+  methods: {
+    isFormValid() {
+      return true
+    },
+  },
+}
+</script>
diff --git a/web-frontend/modules/database/components/row/RowEditFieldRichText.vue b/web-frontend/modules/database/components/row/RowEditFieldRichText.vue
new file mode 100644
index 000000000..118be7741
--- /dev/null
+++ b/web-frontend/modules/database/components/row/RowEditFieldRichText.vue
@@ -0,0 +1,44 @@
+<template>
+  <div class="control__elements">
+    <RichTextEditor
+      ref="input"
+      v-model="richCopy"
+      class="input field-rich-text"
+      :class="{ 'input--error': touched && !valid, active: editing }"
+      :disabled="readOnly"
+      :editable="!readOnly"
+      :enable-rich-text-formatting="true"
+      @focus="select()"
+      @blur="unselect()"
+    ></RichTextEditor>
+
+    <div v-show="touched && !valid" class="error">
+      {{ error }}
+    </div>
+  </div>
+</template>
+
+<script>
+import RichTextEditor from '@baserow/modules/core/components/editor/RichTextEditor.vue'
+import rowEditField from '@baserow/modules/database/mixins/rowEditField'
+import rowEditFieldInput from '@baserow/modules/database/mixins/rowEditFieldInput'
+
+export default {
+  components: { RichTextEditor },
+  mixins: [rowEditField, rowEditFieldInput],
+  data() {
+    return {
+      // local copy of the value storing the JSON representation of the rich text editor
+      richCopy: '',
+    }
+  },
+  created() {
+    this.richCopy = this.value || ''
+  },
+  methods: {
+    beforeSave() {
+      return this.$refs.input.serializeToMarkdown()
+    },
+  },
+}
+</script>
diff --git a/web-frontend/modules/database/components/view/grid/GridViewCell.vue b/web-frontend/modules/database/components/view/grid/GridViewCell.vue
index 3e1ea2f41..da5818810 100644
--- a/web-frontend/modules/database/components/view/grid/GridViewCell.vue
+++ b/web-frontend/modules/database/components/view/grid/GridViewCell.vue
@@ -102,7 +102,7 @@ export default {
     getComponent(parent, props) {
       return parent.$registry
         .get('field', props.field.type)
-        .getGridViewFieldComponent()
+        .getGridViewFieldComponent(props.field)
     },
     /**
      * If the grid field component emits an update event then this method will be
diff --git a/web-frontend/modules/database/components/view/grid/fields/GridViewFieldFormula.vue b/web-frontend/modules/database/components/view/grid/fields/GridViewFieldFormula.vue
index bb8d7c8f0..d6596bd13 100644
--- a/web-frontend/modules/database/components/view/grid/fields/GridViewFieldFormula.vue
+++ b/web-frontend/modules/database/components/view/grid/fields/GridViewFieldFormula.vue
@@ -15,7 +15,7 @@ export default {
     getComponent(field, registry) {
       return registry
         .get('formula_type', field.formula_type)
-        .getGridViewFieldComponent()
+        .getGridViewFieldComponent(field)
     },
   },
 }
diff --git a/web-frontend/modules/database/components/view/grid/fields/GridViewFieldRichText.vue b/web-frontend/modules/database/components/view/grid/fields/GridViewFieldRichText.vue
new file mode 100644
index 000000000..6549d13fe
--- /dev/null
+++ b/web-frontend/modules/database/components/view/grid/fields/GridViewFieldRichText.vue
@@ -0,0 +1,64 @@
+<template>
+  <div
+    ref="cell"
+    class="grid-view__cell grid-field-long-text__cell active"
+    :class="{ editing: opened }"
+    @contextmenu="stopContextIfEditing($event)"
+  >
+    <div v-if="!opened" class="grid-field-long-text">
+      {{ value }}
+    </div>
+    <div
+      v-else-if="editing"
+      v-prevent-parent-scroll
+      class="grid-field-long-text__textarea"
+    >
+      <RichTextEditor
+        ref="input"
+        v-model="richCopy"
+        :enable-rich-text-formatting="true"
+      ></RichTextEditor>
+    </div>
+    <div v-else class="grid-field-long-text__textarea">
+      {{ richCopy }}
+    </div>
+  </div>
+</template>
+
+<script>
+import RichTextEditor from '@baserow/modules/core/components/editor/RichTextEditor.vue'
+import gridField from '@baserow/modules/database/mixins/gridField'
+import gridFieldInput from '@baserow/modules/database/mixins/gridFieldInput'
+
+export default {
+  components: { RichTextEditor },
+  mixins: [gridField, gridFieldInput],
+  data() {
+    return {
+      // local copy of the value storing the JSON representation of the rich text editor
+      richCopy: '',
+    }
+  },
+  watch: {
+    value: {
+      handler(value) {
+        this.richCopy = value || ''
+      },
+      immediate: true,
+    },
+  },
+  methods: {
+    beforeSave() {
+      return this.$refs.input.serializeToMarkdown()
+    },
+    afterEdit() {
+      this.$nextTick(() => {
+        this.$refs.input.focus()
+      })
+    },
+    canSaveByPressingEnter(event) {
+      return false
+    },
+  },
+}
+</script>
diff --git a/web-frontend/modules/database/fieldTypes.js b/web-frontend/modules/database/fieldTypes.js
index 8f6a4d250..7ee5addaa 100644
--- a/web-frontend/modules/database/fieldTypes.js
+++ b/web-frontend/modules/database/fieldTypes.js
@@ -24,6 +24,7 @@ import FieldAutonumberSubForm from '@baserow/modules/database/components/field/F
 import FieldDurationSubForm from '@baserow/modules/database/components/field/FieldDurationSubForm'
 import FieldRatingSubForm from '@baserow/modules/database/components/field/FieldRatingSubForm'
 import FieldTextSubForm from '@baserow/modules/database/components/field/FieldTextSubForm'
+import FieldLongTextSubForm from '@baserow/modules/database/components/field/FieldLongTextSubForm'
 import FieldDateSubForm from '@baserow/modules/database/components/field/FieldDateSubForm'
 import FieldLinkRowSubForm from '@baserow/modules/database/components/field/FieldLinkRowSubForm'
 import FieldSelectOptionsSubForm from '@baserow/modules/database/components/field/FieldSelectOptionsSubForm'
@@ -31,6 +32,7 @@ import FieldCollaboratorSubForm from '@baserow/modules/database/components/field
 
 import GridViewFieldText from '@baserow/modules/database/components/view/grid/fields/GridViewFieldText'
 import GridViewFieldLongText from '@baserow/modules/database/components/view/grid/fields/GridViewFieldLongText'
+import GridViewFieldRichText from '@baserow/modules/database/components/view/grid/fields/GridViewFieldRichText'
 import GridViewFieldURL from '@baserow/modules/database/components/view/grid/fields/GridViewFieldURL'
 import GridViewFieldEmail from '@baserow/modules/database/components/view/grid/fields/GridViewFieldEmail'
 import GridViewFieldLinkRow from '@baserow/modules/database/components/view/grid/fields/GridViewFieldLinkRow'
@@ -69,6 +71,7 @@ import FunctionalGridViewFieldLastModifiedBy from '@baserow/modules/database/com
 
 import RowEditFieldText from '@baserow/modules/database/components/row/RowEditFieldText'
 import RowEditFieldLongText from '@baserow/modules/database/components/row/RowEditFieldLongText'
+import RowEditFieldRichText from '@baserow/modules/database/components/row/RowEditFieldRichText'
 import RowEditFieldURL from '@baserow/modules/database/components/row/RowEditFieldURL'
 import RowEditFieldEmail from '@baserow/modules/database/components/row/RowEditFieldEmail'
 import RowEditFieldLinkRow from '@baserow/modules/database/components/row/RowEditFieldLinkRow'
@@ -170,7 +173,7 @@ export class FieldType extends Registerable {
    * example if we are creating a number fields this component should contain
    * the inputs to choose of it is an integer of decimal.
    */
-  getFormComponent() {
+  getFormComponent(field) {
     return null
   }
 
@@ -179,7 +182,7 @@ export class FieldType extends Registerable {
    * type. It will only be used in the grid view and it also responsible for editing
    * the value.
    */
-  getGridViewFieldComponent() {
+  getGridViewFieldComponent(field) {
     throw new Error(
       'Not implement error. This method should return a component.'
     )
@@ -847,8 +850,16 @@ export class LongTextFieldType extends FieldType {
     return i18n.t('fieldType.longText')
   }
 
-  getGridViewFieldComponent() {
-    return GridViewFieldLongText
+  getFormComponent() {
+    return FieldLongTextSubForm
+  }
+
+  getGridViewFieldComponent(field) {
+    if (field?.long_text_enable_rich_text) {
+      return GridViewFieldRichText
+    } else {
+      return GridViewFieldLongText
+    }
   }
 
   getFunctionalGridViewFieldComponent() {
@@ -856,7 +867,11 @@ export class LongTextFieldType extends FieldType {
   }
 
   getRowEditFieldComponent(field) {
-    return RowEditFieldLongText
+    if (field?.long_text_enable_rich_text) {
+      return RowEditFieldRichText
+    } else {
+      return RowEditFieldLongText
+    }
   }
 
   getCardComponent() {
diff --git a/web-frontend/modules/database/locales/en.json b/web-frontend/modules/database/locales/en.json
index 12ea9a011..4227afdb5 100644
--- a/web-frontend/modules/database/locales/en.json
+++ b/web-frontend/modules/database/locales/en.json
@@ -425,6 +425,9 @@
     "formulaInputPlaceholder": "Click to edit the formula",
     "refreshFormulaOptions": "Refresh formula options"
   },
+  "fieldLongTextSubForm": {
+    "enableRichTextFormatting": "Enable rich text formatting"
+  },
   "formulaFieldItemDescription": {
     "syntax": "Syntax",
     "examples": "Examples"
diff --git a/web-frontend/package.json b/web-frontend/package.json
index 24e4d454d..a9fd0058a 100644
--- a/web-frontend/package.json
+++ b/web-frontend/package.json
@@ -33,15 +33,31 @@
     "@nuxtjs/sentry": "7.1.11",
     "@storybook/core-client": "6.5.9",
     "@tiptap/core": "^2.0.3",
-    "@tiptap/extension-document": "^2.0.3",
-    "@tiptap/extension-hard-break": "^2.0.3",
-    "@tiptap/extension-mention": "^2.0.3",
-    "@tiptap/extension-paragraph": "^2.0.3",
-    "@tiptap/extension-placeholder": "^2.0.3",
-    "@tiptap/extension-text": "^2.0.3",
-    "@tiptap/pm": "^2.0.3",
-    "@tiptap/suggestion": "^2.0.3",
-    "@tiptap/vue-2": "^2.0.3",
+    "@tiptap/extension-blockquote": "^2.2.2",
+    "@tiptap/extension-bold": "^2.2.2",
+    "@tiptap/extension-bullet-list": "^2.2.2",
+    "@tiptap/extension-code": "^2.2.2",
+    "@tiptap/extension-code-block": "^2.2.2",
+    "@tiptap/extension-document": "2.2.3",
+    "@tiptap/extension-hard-break": "2.2.3",
+    "@tiptap/extension-heading": "^2.0.3",
+    "@tiptap/extension-highlight": "^2.2.2",
+    "@tiptap/extension-horizontal-rule": "^2.2.2",
+    "@tiptap/extension-italic": "^2.2.2",
+    "@tiptap/extension-link": "^2.2.2",
+    "@tiptap/extension-list-item": "^2.2.2",
+    "@tiptap/extension-mention": "2.2.3",
+    "@tiptap/extension-ordered-list": "^2.2.2",
+    "@tiptap/extension-paragraph": "2.2.3",
+    "@tiptap/extension-placeholder": "2.2.3",
+    "@tiptap/extension-strike": "^2.2.3",
+    "@tiptap/extension-subscript": "^2.2.3",
+    "@tiptap/extension-superscript": "^2.2.3",
+    "@tiptap/extension-text": "2.2.3",
+    "@tiptap/extension-underline": "^2.2.3",
+    "@tiptap/pm": "2.2.3",
+    "@tiptap/suggestion": "2.2.3",
+    "@tiptap/vue-2": "2.2.3",
     "antlr4": "4.9.3",
     "async-mutex": "0.4.0",
     "axios": "^1.6.7",
@@ -55,7 +71,7 @@
     "jwt-decode": "^3.1.2",
     "lodash": "^4.17.21",
     "markdown-it": "13.0.1",
-    "moment": "2.29.4",
+    "moment": "^2.30.1",
     "moment-guess": "^1.2.4",
     "moment-timezone": "0.5.43",
     "node-sass": "8.0.0",
@@ -67,6 +83,7 @@
     "resize-observer-polyfill": "^1.5.1",
     "sass-loader": "10.4.1",
     "thenby": "^1.3.4",
+    "tiptap-markdown": "^0.8.9",
     "uuid": "9.0.0",
     "vue-chartjs": "4.1.2",
     "vuejs-datepicker": "1.6.2",
diff --git a/web-frontend/yarn.lock b/web-frontend/yarn.lock
index f46ec4acd..624b07e28 100644
--- a/web-frontend/yarn.lock
+++ b/web-frontend/yarn.lock
@@ -4263,86 +4263,168 @@
   resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.13.tgz#e21f566e81688c826c6f26d2940886734189e193"
   integrity sha512-cMC8bgTN63dj1Mv82iDeeLl6sa9kY0Pug8LSalxVEptRmyFVsVxGgu2/6Y3T+9aCYScxfS06EkA8SdzFMAwYTQ==
 
-"@tiptap/extension-bubble-menu@^2.1.13":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.13.tgz#884cd2e4e0c9586998baac3d0a14621b177f1859"
-  integrity sha512-Hm7e1GX3AI6lfaUmr6WqsS9MMyXIzCkhh+VQi6K8jj4Q4s8kY4KPoAyD/c3v9pZ/dieUtm2TfqrOCkbHzsJQBg==
+"@tiptap/extension-blockquote@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.2.3.tgz#0951a321f56c70b3f276e11bd17fa1ff109042e7"
+  integrity sha512-gN23d/ADhTOB0YIM4lR0VrVczdyaXpmIVYYWZ45tQEVJzFWRSIScE9m9NaVqtqwEMpYHyTHxLth0OQutZ91sog==
+
+"@tiptap/extension-bold@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.2.3.tgz#e4cd91de4e8dbdabd915bbc10c86eda321e91d17"
+  integrity sha512-bHeFkRY5+Nf2DKupstV8EIVn359tw/9MFwDEDoF9F+Sn/vjuS35vm0OqjXYg/Ya9CQvwl/2oym/fKv5kO+Q6og==
+
+"@tiptap/extension-bubble-menu@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.2.3.tgz#e3b603324726aa2f96b2500855622ace625117df"
+  integrity sha512-6ybColxLznGilzOY/yk3KcpV4JQy+QDDW6Za6zWV6OEs9D8I8VUeMAS77isMMc1dffvHfmgZpVZm/lsva8UuCw==
   dependencies:
     tippy.js "^6.3.7"
 
-"@tiptap/extension-document@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.13.tgz#5b68fa08e8a79eebd41f1360982db2ddd28ad010"
-  integrity sha512-wLwiTWsVmZTGIE5duTcHRmW4ulVxNW4nmgfpk95+mPn1iKyNGtrVhGWleLhBlTj+DWXDtcfNWZgqZkZNzhkqYQ==
+"@tiptap/extension-bullet-list@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.2.3.tgz#98b82afd9a6c553278d4b613b29dbed99da063f9"
+  integrity sha512-BpYg1pIfLE+2LTC90ts53deEWGSmAojhM/jJ84U19qfbfXt/7/KHrZJ4SAMxJSW3pLpy0bIq2XuOuvppOYVR5g==
 
-"@tiptap/extension-floating-menu@^2.1.13":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.13.tgz#e12e6e73ee095319d4a723a9b46b8f7b1a9f4b1a"
-  integrity sha512-9Oz7pk1Nts2+EyY+rYfnREGbLzQ5UFazAvRhF6zAJdvyuDmAYm0Jp6s0GoTrpV0/dJEISoFaNpPdMJOb9EBNRw==
+"@tiptap/extension-code-block@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.2.3.tgz#caeaad4f4ccf92963e73ddf1b90265edd94c7af3"
+  integrity sha512-1xFM2Aj/JEWAT1PWjQ/7hEVmo1Av6JHxTANxMIjXUcmrMJkXDA+BQ7yItlwrrHxY0SJdxBbR/WWFn4dWIxd7iA==
+
+"@tiptap/extension-code@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.2.3.tgz#183847b126496f9d4d473a72b7e1d2ab2a90da68"
+  integrity sha512-ZMp3CrbAV+PVOnPbGmruvlxFENLc+J/Fos8Y4mWvS1nDbrGuu19OKgKimwdzfDBpZVFVnHpEUnDTMBDzDe0hkg==
+
+"@tiptap/extension-document@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.2.3.tgz#40e4faac7369d0fea31ea4eb57716ed7393f24b7"
+  integrity sha512-60Egd9yKb5SzpQlstQAP2A/2a/Qr+A+TblMRKZugrT+NENUhAj6Tx1HxWlblqGu2MsS1iXvQLZ6BQO1jHkL2IQ==
+
+"@tiptap/extension-floating-menu@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.2.3.tgz#3e200f51760fd1d48cb572223dcaf54c70f244a6"
+  integrity sha512-ZeQGmIFNImhu/zzn//Xzupwa82j2vIwiMoviX2zd+2DutoFnm4qRIAU6qpjzV+ZOSHAq3aBMGnYwEAY6vl4f3g==
   dependencies:
     tippy.js "^6.3.7"
 
-"@tiptap/extension-hard-break@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.13.tgz#fc84d0ff7e2fe861bf421bc8000194ecc26979b0"
-  integrity sha512-TGkMzMQayuKg+vN4du0x1ahEItBLcCT1jdWeRsjdM8gHfzbPLdo4PQhVsvm1I0xaZmbJZelhnVsUwRZcIu1WNA==
+"@tiptap/extension-hard-break@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.2.3.tgz#7d7b8e7bcf99be5f518a705c65ebcc1dacaaa514"
+  integrity sha512-P7sP4WBEaQyiiFAswy9lKvaUWUAUwnfTSN3svTAgx0fpU3/ZeVWg+SDi5ve474Ym2oz2eRAr09mNTdWEUsL32Q==
 
-"@tiptap/extension-mention@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.1.13.tgz#6359c563268c46539660958847fe76c22131f2c8"
-  integrity sha512-OYqaucyBiCN/CmDYjpOVX74RJcIEKmAqiZxUi8Gfaq7ryEO5a8Gk93nK+8uZ0onaqHE+mHpoLFFbcAFbOPgkUQ==
+"@tiptap/extension-heading@^2.0.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.2.3.tgz#4934e3a887d8843f85706a809fd6293b2b42b2b5"
+  integrity sha512-7atctuvtwPqIAdnBPOhAMsJZd41UPnWN3CktzgzfsfEoplq/86QR1hGIE4JXVB2wAZDmbnKP9Fe8PCNr7Q8JCQ==
 
-"@tiptap/extension-paragraph@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.13.tgz#30f8ae3f8833c606b339f3554b9ffdbe1e604463"
-  integrity sha512-cEoZBJrsQn69FPpUMePXG/ltGXtqKISgypj70PEHXt5meKDjpmMVSY4/8cXvFYEYsI9GvIwyAK0OrfAHiSoROA==
+"@tiptap/extension-highlight@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.2.3.tgz#b9cf810547d2abc8b3b7567b9002397b6add3477"
+  integrity sha512-3K9WbrR2WCYq7a/2JSQi5K2zzG/5ebNfTOXyDcT3kn5B5PutyWuDCzqjkPxGXmkf8yEZTQ9Sn2lQPRMG3sNwFw==
 
-"@tiptap/extension-placeholder@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.13.tgz#b735591f719b9fe89c90dcc6327d2ef2851be510"
-  integrity sha512-vIY7y7UbqsrAW/y8bDE9eRenbQEU16kNHB5Wri8RU1YiUZpkPgdXP/pLqyjIIq95SwP/vdTIHjHoQ77VLRl1hA==
+"@tiptap/extension-horizontal-rule@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.2.3.tgz#ff76b7627b6fea3ba5397fbfccd818f0f2e6efbd"
+  integrity sha512-pc0J0hBcvj9ymJkFau1W/3L+OhB1PQzMjsx4ZWJvxURL8U7zdDqvYvJjfCA0i5Qw2ZuSVXFACGbEVr6NoCMRAw==
 
-"@tiptap/extension-text@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.13.tgz#ac17a0220aef1bae1bbd646a91491353e57bb5d1"
-  integrity sha512-zzsTTvu5U67a8WjImi6DrmpX2Q/onLSaj+LRWPh36A1Pz2WaxW5asZgaS+xWCnR+UrozlCALWa01r7uv69jq0w==
+"@tiptap/extension-italic@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.2.3.tgz#d01e075bf0db5ac01113a19ab80cc39af39033fc"
+  integrity sha512-SSsFuRnm4Y4Qnc6EuvmA4iarLCt/sg8qkqCKiNPjDUP5JR8HGESeoYVjQzprLHY8jusT9qoC26TP1Sin5vZmWQ==
 
-"@tiptap/pm@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.13.tgz#857753691580be760da13629fab2712c52750741"
-  integrity sha512-zNbA7muWsHuVg12GrTgN/j119rLePPq5M8dZgkKxUwdw8VmU3eUyBp1SihPEXJ2U0MGdZhNhFX7Y74g11u66sg==
+"@tiptap/extension-link@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.2.3.tgz#5c6571dffebbe328277b0abfae0deccfb20c2559"
+  integrity sha512-AKKgkllpj0Po/hi2bVz719OMqyB1nBhKU/Q05yeWVirOYwF2ZwfM4iK2Iab7xWUVhvlyIG3lrWFQL8A30yuqwQ==
   dependencies:
-    prosemirror-changeset "^2.2.0"
-    prosemirror-collab "^1.3.0"
-    prosemirror-commands "^1.3.1"
-    prosemirror-dropcursor "^1.5.0"
-    prosemirror-gapcursor "^1.3.1"
-    prosemirror-history "^1.3.0"
-    prosemirror-inputrules "^1.2.0"
-    prosemirror-keymap "^1.2.0"
-    prosemirror-markdown "^1.10.1"
-    prosemirror-menu "^1.2.1"
-    prosemirror-model "^1.18.1"
-    prosemirror-schema-basic "^1.2.0"
-    prosemirror-schema-list "^1.2.2"
-    prosemirror-state "^1.4.1"
-    prosemirror-tables "^1.3.0"
-    prosemirror-trailing-node "^2.0.2"
-    prosemirror-transform "^1.7.0"
-    prosemirror-view "^1.28.2"
+    linkifyjs "^4.1.0"
 
-"@tiptap/suggestion@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.13.tgz#0a8317260baed764a523a09099c0889a0e5b507e"
-  integrity sha512-Y05TsiXTFAJ5SrfoV+21MAxig5UNbY0AVa03lQlh/yicTRPpIc6hgZzblB0uxDSYoj6+kaHE4MIZvPvhUD8BJQ==
+"@tiptap/extension-list-item@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.2.3.tgz#dfdc268cc2063947dc46749464d6d91afc0842a4"
+  integrity sha512-eyfk4f1jOioj+mkIN2m6XQK61MpV0fi17utt8VNx893Td8kS0g7HHuuYMwyjIRtG35ENUaAt7c216JQwnLsrAw==
 
-"@tiptap/vue-2@^2.0.3":
-  version "2.1.13"
-  resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.1.13.tgz#e84c144fa36f79c36db3cf6913aef197002bd298"
-  integrity sha512-OsCINarPGyT3sDIXDrhVyaoH0I0VxeDDm+NgS5P0fPbBCnsHZ8csvxD9UB9/KZ/UoxYDfJ1zLplKQn1AIlnRzg==
+"@tiptap/extension-mention@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-mention/-/extension-mention-2.2.3.tgz#3b43619b572db693a1e776d1269ceef2c9474192"
+  integrity sha512-HFSZcGLUJ/31aiOsc2CnkjS5EBg6EbU+SKLQZx7/pA4/ew4uSWOPI7a03mgGmNoRfR16est55OrauEuBj8hKrQ==
+
+"@tiptap/extension-ordered-list@^2.2.2":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.2.3.tgz#07588d9091076e0577f5e4873e2e65c27d69a7be"
+  integrity sha512-YIWpjkHAJN74tY185ZqatlG4+KbXQOdkJpc5cKWqO89gVWLi7+4xwdeeXbTEG64/LOOWS4Q6r1/EJmDy2FCbyA==
+
+"@tiptap/extension-paragraph@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.2.3.tgz#39e705198eba640a57f58276044950d3d77067ff"
+  integrity sha512-4dP+Ecb2iEWW33ckFKjXRnSfEygaFUN19qzc7mUYD8e61ZA8caWL6//uL7DFIz4Q1rchyefbU52gCwTh2P42kQ==
+
+"@tiptap/extension-placeholder@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.2.3.tgz#d538bff70db199433a256fb37fac8e4058a3cfc1"
+  integrity sha512-Kc+9a/uACY9XBT0uB/qFVpIHm8MzVr0uWA7MCjwDcMneANRLsXEBzWBzyHxRFoNRECfocivV9hQIhuO4i09c9A==
+
+"@tiptap/extension-strike@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.2.3.tgz#9caaca60d4f717863b03a8ade71af22a1579096c"
+  integrity sha512-3wwFk01ociZajRzD08hp4j/4isFUeD6BIkKPDnZeGD5HKPdTOaDciE3dJ3JaZZrRZPPdPV3yMt5hkBOapqEKzQ==
+
+"@tiptap/extension-subscript@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-subscript/-/extension-subscript-2.2.3.tgz#91c994222ea8120e0a19bd870cf47c8cfdc82353"
+  integrity sha512-zWN8MOfYSaGXNI5yKTk4I4hHSpCUz//NQASHD8OOKN+rt6i8RUTNynpJyCZC77RXdlvTY70Ox2vNgp/rriz+Qw==
+
+"@tiptap/extension-superscript@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-superscript/-/extension-superscript-2.2.3.tgz#51cb2bde41656688ea6088e02d89d43195f6c1c6"
+  integrity sha512-4V4PoXPuxCiiISFxz1StP/5azQqUmlwCECJg8ketrQ6WFfUf54lzCEjMeo9RwwdBbfpL6dhwJ8mmv6qil4j1KA==
+
+"@tiptap/extension-text@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.2.3.tgz#3adc14b6f5956f2fb6102702beb0adbfe1f86131"
+  integrity sha512-BrWGCkmuzVcsNy7dSCfJyVwedPzeNz6BR/OUNzM8Mqt2KSxfoIRy7cg16HvFB4YW+ijrM9XUqDIFvqYI0TY+Jg==
+
+"@tiptap/extension-underline@^2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.2.3.tgz#ce77652d6d8d0a4337460be98910e5ff239ea41b"
+  integrity sha512-Y6PTaXmDFay39+Knk77T+Ezc5vuC/gFxZFD6cQhjctZHMJ2QMAguMKWtBVaSs78HBkKnwTU9EViAFBurz++Geg==
+
+"@tiptap/pm@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.2.3.tgz#88c8547015098ebd438211e839de64b043b655f3"
+  integrity sha512-jYZX+0fjN+a1J8qY72Poz1LK6X6oHVQkJIq6qzcx3rm0voYZNVRzP2GIfzstncZiEqRXABHY3mWfOi2I4K9tQA==
   dependencies:
-    "@tiptap/extension-bubble-menu" "^2.1.13"
-    "@tiptap/extension-floating-menu" "^2.1.13"
+    prosemirror-changeset "^2.2.1"
+    prosemirror-collab "^1.3.1"
+    prosemirror-commands "^1.5.2"
+    prosemirror-dropcursor "^1.8.1"
+    prosemirror-gapcursor "^1.3.2"
+    prosemirror-history "^1.3.2"
+    prosemirror-inputrules "^1.3.0"
+    prosemirror-keymap "^1.2.2"
+    prosemirror-markdown "^1.12.0"
+    prosemirror-menu "^1.2.4"
+    prosemirror-model "^1.19.4"
+    prosemirror-schema-basic "^1.2.2"
+    prosemirror-schema-list "^1.3.0"
+    prosemirror-state "^1.4.3"
+    prosemirror-tables "^1.3.5"
+    prosemirror-trailing-node "^2.0.7"
+    prosemirror-transform "^1.8.0"
+    prosemirror-view "^1.32.7"
+
+"@tiptap/suggestion@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.2.3.tgz#d9286d53b0e37816628205a09035c344f6d46e7f"
+  integrity sha512-pMInbk8+rYNaCz4oT/uS498mxSGIJXU32mkXv7wdDqMT2nnZQ2AHtJDUtMuB1RX+DS4ll9vdzrKqQHSW5t2ybQ==
+
+"@tiptap/vue-2@2.2.3":
+  version "2.2.3"
+  resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.2.3.tgz#a1bee805e4b3df43a22d6738ed23d412127f6b5d"
+  integrity sha512-RWiqbD1UrWQMbClHO3fr7hQcKVzJaKs6MI9cWTJ9xktb3GiHqXVFm/WECgoUGo1MVliGs7v2NoSWQlh9PVcP3w==
+  dependencies:
+    "@tiptap/extension-bubble-menu" "^2.2.3"
+    "@tiptap/extension-floating-menu" "^2.2.3"
     vue-ts-types "^1.6.0"
 
 "@tootallnate/once@1":
@@ -4542,11 +4624,24 @@
   resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
   integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
 
+"@types/linkify-it@*":
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.5.tgz#1e78a3ac2428e6d7e6c05c1665c242023a4601d8"
+  integrity sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==
+
 "@types/lodash@^4.14.167":
   version "4.14.202"
   resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8"
   integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==
 
+"@types/markdown-it@^12.2.3":
+  version "12.2.3"
+  resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51"
+  integrity sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==
+  dependencies:
+    "@types/linkify-it" "*"
+    "@types/mdurl" "*"
+
 "@types/mdast@^3.0.0":
   version "3.0.15"
   resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.15.tgz#49c524a263f30ffa28b71ae282f813ed000ab9f5"
@@ -4554,6 +4649,11 @@
   dependencies:
     "@types/unist" "^2"
 
+"@types/mdurl@*":
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.5.tgz#3e0d2db570e9fb6ccb2dc8fde0be1d79ac810d39"
+  integrity sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==
+
 "@types/mime@*":
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45"
@@ -12373,6 +12473,11 @@ linkify-it@^5.0.0:
   dependencies:
     uc.micro "^2.0.0"
 
+linkifyjs@^4.1.0:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.3.tgz#0edbc346428a7390a23ea2e5939f76112c9ae07f"
+  integrity sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==
+
 lit-element@^3.3.0:
   version "3.3.3"
   resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.3.tgz#10bc19702b96ef5416cf7a70177255bfb17b3209"
@@ -12745,6 +12850,11 @@ markdown-escapes@^1.0.0:
   resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
   integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
 
+markdown-it-task-lists@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/markdown-it-task-lists/-/markdown-it-task-lists-2.1.1.tgz#f68f4d2ac2bad5a2c373ba93081a1a6848417088"
+  integrity sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==
+
 markdown-it@13.0.1:
   version "13.0.1"
   resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430"
@@ -12756,6 +12866,17 @@ markdown-it@13.0.1:
     mdurl "^1.0.1"
     uc.micro "^1.0.5"
 
+markdown-it@^13.0.1:
+  version "13.0.2"
+  resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.2.tgz#1bc22e23379a6952e5d56217fbed881e0c94d536"
+  integrity sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==
+  dependencies:
+    argparse "^2.0.1"
+    entities "~3.0.1"
+    linkify-it "^4.0.1"
+    mdurl "^1.0.1"
+    uc.micro "^1.0.5"
+
 markdown-it@^14.0.0:
   version "14.0.0"
   resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.0.0.tgz#b4b2ddeb0f925e88d981f84c183b59bac9e3741b"
@@ -13256,11 +13377,16 @@ moment-timezone@0.5.43:
   dependencies:
     moment "^2.29.4"
 
-moment@2.29.4, moment@^2.29.4:
+moment@^2.29.4:
   version "2.29.4"
   resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
   integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
 
+moment@^2.30.1:
+  version "2.30.1"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
+  integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
+
 move-concurrently@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -15454,21 +15580,21 @@ property-information@^5.0.0, property-information@^5.3.0:
   dependencies:
     xtend "^4.0.0"
 
-prosemirror-changeset@^2.2.0:
+prosemirror-changeset@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz#dae94b63aec618fac7bb9061648e6e2a79988383"
   integrity sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==
   dependencies:
     prosemirror-transform "^1.0.0"
 
-prosemirror-collab@^1.3.0:
+prosemirror-collab@^1.3.1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz#0e8c91e76e009b53457eb3b3051fb68dad029a33"
   integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==
   dependencies:
     prosemirror-state "^1.0.0"
 
-prosemirror-commands@^1.0.0, prosemirror-commands@^1.3.1:
+prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2:
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz#e94aeea52286f658cd984270de9b4c3fff580852"
   integrity sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==
@@ -15477,7 +15603,7 @@ prosemirror-commands@^1.0.0, prosemirror-commands@^1.3.1:
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.0.0"
 
-prosemirror-dropcursor@^1.5.0:
+prosemirror-dropcursor@^1.8.1:
   version "1.8.1"
   resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz#49b9fb2f583e0d0f4021ff87db825faa2be2832d"
   integrity sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==
@@ -15486,7 +15612,7 @@ prosemirror-dropcursor@^1.5.0:
     prosemirror-transform "^1.1.0"
     prosemirror-view "^1.1.0"
 
-prosemirror-gapcursor@^1.3.1:
+prosemirror-gapcursor@^1.3.2:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz#5fa336b83789c6199a7341c9493587e249215cb4"
   integrity sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==
@@ -15496,7 +15622,7 @@ prosemirror-gapcursor@^1.3.1:
     prosemirror-state "^1.0.0"
     prosemirror-view "^1.0.0"
 
-prosemirror-history@^1.0.0, prosemirror-history@^1.3.0:
+prosemirror-history@^1.0.0, prosemirror-history@^1.3.2:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.3.2.tgz#ce6ad7ab9db83e761aee716f3040d74738311b15"
   integrity sha512-/zm0XoU/N/+u7i5zepjmZAEnpvjDtzoPWW6VmKptcAnPadN/SStsBjMImdCEbb3seiNTpveziPTIrXQbHLtU1g==
@@ -15506,15 +15632,15 @@ prosemirror-history@^1.0.0, prosemirror-history@^1.3.0:
     prosemirror-view "^1.31.0"
     rope-sequence "^1.3.0"
 
-prosemirror-inputrules@^1.2.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.3.0.tgz#d43ce469ffe09a1b4cbac3f0ad367b0e4b504875"
-  integrity sha512-z1GRP2vhh5CihYMQYsJSa1cOwXb3SYxALXOIfAkX8nZserARtl9LiL+CEl+T+OFIsXc3mJIHKhbsmRzC0HDAXA==
+prosemirror-inputrules@^1.3.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz#ef1519bb2cb0d1e0cec74bad1a97f1c1555068bb"
+  integrity sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==
   dependencies:
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.0.0"
 
-prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.0:
+prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz#14a54763a29c7b2704f561088ccf3384d14eb77e"
   integrity sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==
@@ -15522,7 +15648,7 @@ prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.0:
     prosemirror-state "^1.0.0"
     w3c-keyname "^2.2.0"
 
-prosemirror-markdown@^1.10.1:
+prosemirror-markdown@^1.11.1, prosemirror-markdown@^1.12.0:
   version "1.12.0"
   resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.12.0.tgz#d2de09d37897abf7adb6293d925ff132dac5b0a6"
   integrity sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==
@@ -15530,7 +15656,7 @@ prosemirror-markdown@^1.10.1:
     markdown-it "^14.0.0"
     prosemirror-model "^1.0.0"
 
-prosemirror-menu@^1.2.1:
+prosemirror-menu@^1.2.4:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz#3cfdc7c06d10f9fbd1bce29082c498bd11a0a79a"
   integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==
@@ -15540,21 +15666,21 @@ prosemirror-menu@^1.2.1:
     prosemirror-history "^1.0.0"
     prosemirror-state "^1.0.0"
 
-prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1:
+prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.19.0, prosemirror-model@^1.19.4, prosemirror-model@^1.8.1:
   version "1.19.4"
   resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.4.tgz#e45e84480c97dd3922095dbe579e1c98c86c0704"
   integrity sha512-RPmVXxUfOhyFdayHawjuZCxiROsm9L4FCUA6pWI+l7n2yCBsWy9VpdE1hpDHUS8Vad661YLY9AzqfjLhAKQ4iQ==
   dependencies:
     orderedmap "^2.0.0"
 
-prosemirror-schema-basic@^1.2.0:
+prosemirror-schema-basic@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz#6695f5175e4628aab179bf62e5568628b9cfe6c7"
   integrity sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==
   dependencies:
     prosemirror-model "^1.19.0"
 
-prosemirror-schema-list@^1.2.2:
+prosemirror-schema-list@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz#05374702cf35a3ba5e7ec31079e355a488d52519"
   integrity sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==
@@ -15563,7 +15689,7 @@ prosemirror-schema-list@^1.2.2:
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.7.3"
 
-prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.1:
+prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.3:
   version "1.4.3"
   resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.3.tgz#94aecf3ffd54ec37e87aa7179d13508da181a080"
   integrity sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==
@@ -15572,7 +15698,7 @@ prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, pr
     prosemirror-transform "^1.0.0"
     prosemirror-view "^1.27.0"
 
-prosemirror-tables@^1.3.0:
+prosemirror-tables@^1.3.5:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.3.5.tgz#80f03394f5b9991f9693bcb3a90b6dba6b16254d"
   integrity sha512-JSZ2cCNlApu/ObAhdPyotrjBe2cimniniTpz60YXzbL0kZ+47nEYk2LWbfKU2lKpBkUNquta2PjteoNi4YCluQ==
@@ -15583,7 +15709,7 @@ prosemirror-tables@^1.3.0:
     prosemirror-transform "^1.2.1"
     prosemirror-view "^1.13.3"
 
-prosemirror-trailing-node@^2.0.2:
+prosemirror-trailing-node@^2.0.7:
   version "2.0.7"
   resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.7.tgz#ba782a7929f18bcae650b1c7082a2d10443eab19"
   integrity sha512-8zcZORYj/8WEwsGo6yVCRXFMOfBo0Ub3hCUvmoWIZYfMP26WqENU0mpEP27w7mt8buZWuGrydBewr0tOArPb1Q==
@@ -15592,14 +15718,14 @@ prosemirror-trailing-node@^2.0.2:
     "@remirror/core-helpers" "^3.0.0"
     escape-string-regexp "^4.0.0"
 
-prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.0, prosemirror-transform@^1.7.3:
+prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.3, prosemirror-transform@^1.8.0:
   version "1.8.0"
   resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.8.0.tgz#a47c64a3c373c1bd0ff46e95be3210c8dda0cd11"
   integrity sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A==
   dependencies:
     prosemirror-model "^1.0.0"
 
-prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.28.2, prosemirror-view@^1.31.0:
+prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0:
   version "1.32.6"
   resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.32.6.tgz#8e8a366ea1ce9b59dbb7f4c6fa7aacf4af2532d7"
   integrity sha512-26r5LvyDlPgUNVf7ZdNdGrMJnylwjJtUJTfDuYOANIVx9lqWD1WCBlGg283weYQGKUC64DXR25LeAmliB9CrFQ==
@@ -15608,6 +15734,15 @@ prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, pros
     prosemirror-state "^1.0.0"
     prosemirror-transform "^1.1.0"
 
+prosemirror-view@^1.32.7:
+  version "1.33.1"
+  resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.33.1.tgz#58dfd154f4fb1c9f7353bf1097c54d6afc6f57ea"
+  integrity sha512-62qkYgSJIkwIMMCpuGuPzc52DiK1Iod6TWoIMxP4ja6BTD4yO8kCUL64PZ/WhH/dJ9fW0CDO39FhH1EMyhUFEg==
+  dependencies:
+    prosemirror-model "^1.16.0"
+    prosemirror-state "^1.0.0"
+    prosemirror-transform "^1.1.0"
+
 proto-list@~1.2.1:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
@@ -17847,6 +17982,16 @@ tippy.js@^6.3.7:
   dependencies:
     "@popperjs/core" "^2.9.0"
 
+tiptap-markdown@^0.8.9:
+  version "0.8.9"
+  resolved "https://registry.yarnpkg.com/tiptap-markdown/-/tiptap-markdown-0.8.9.tgz#e13f3ae9a1b1649f8c28bb3cae4516a53da7492c"
+  integrity sha512-TykSDcsb94VFCzPbSSTfB6Kh2HJi7x4B9J3Jm9uSOAMPy8App1YfrLW/rEJLajTxwMVhWBdOo4nidComSlLQsQ==
+  dependencies:
+    "@types/markdown-it" "^12.2.3"
+    markdown-it "^13.0.1"
+    markdown-it-task-lists "^2.1.1"
+    prosemirror-markdown "^1.11.1"
+
 tmp@^0.0.33:
   version "0.0.33"
   resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"