From 6283cee5c7e3ca1efb4cfaf87aca077a7852e22e Mon Sep 17 00:00:00 2001
From: Dominik <6538827+bdbch@users.noreply.github.com>
Date: Fri, 3 Mar 2023 11:35:53 +0100
Subject: [PATCH] fix(react): allow updating event handlers on editor (#3811)
---
.../OnUpdateRerender/React/index.html | 0
.../OnUpdateRerender/React/index.jsx | 47 +++++++++++++++
.../OnUpdateRerender/React/styles.scss | 6 ++
.../OnUpdateRerender/Vue/TiptapComponent.vue | 52 ++++++++++++++++
.../OnUpdateRerender/Vue/index.html | 0
.../OnUpdateRerender/Vue/index.vue | 27 +++++++++
packages/react/src/useEditor.ts | 60 +++++++++++++++++++
7 files changed, 192 insertions(+)
create mode 100644 demos/src/Experiments/OnUpdateRerender/React/index.html
create mode 100644 demos/src/Experiments/OnUpdateRerender/React/index.jsx
create mode 100644 demos/src/Experiments/OnUpdateRerender/React/styles.scss
create mode 100644 demos/src/Experiments/OnUpdateRerender/Vue/TiptapComponent.vue
create mode 100644 demos/src/Experiments/OnUpdateRerender/Vue/index.html
create mode 100644 demos/src/Experiments/OnUpdateRerender/Vue/index.vue
diff --git a/demos/src/Experiments/OnUpdateRerender/React/index.html b/demos/src/Experiments/OnUpdateRerender/React/index.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/demos/src/Experiments/OnUpdateRerender/React/index.jsx b/demos/src/Experiments/OnUpdateRerender/React/index.jsx
new file mode 100644
index 0000000000..183fa8b3d3
--- /dev/null
+++ b/demos/src/Experiments/OnUpdateRerender/React/index.jsx
@@ -0,0 +1,47 @@
+import './styles.scss'
+
+import Document from '@tiptap/extension-document'
+import Paragraph from '@tiptap/extension-paragraph'
+import Text from '@tiptap/extension-text'
+import { EditorContent, useEditor } from '@tiptap/react'
+import React from 'react'
+
+const TiptapComponent = ({
+ onUpdate,
+}) => {
+ const editor = useEditor({
+ extensions: [
+ Document,
+ Paragraph,
+ Text,
+ ],
+ content: `
+
+ This is a radically reduced version of tiptap. It has support for a document, with paragraphs and text. That’s it. It’s probably too much for real minimalists though.
+
+
+ The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
+
+ `,
+ onUpdate,
+ })
+
+ return (
+
+ )
+}
+
+export default () => {
+ const [index, setIndex] = React.useState(0)
+
+ const handleUpdate = ({ editor: currentEditor }) => {
+ console.log(index, 'onUpdate', currentEditor.getHTML())
+ }
+
+ return (
+
+ setIndex(index + 1)}>INC = {index}
+
+
+ )
+}
diff --git a/demos/src/Experiments/OnUpdateRerender/React/styles.scss b/demos/src/Experiments/OnUpdateRerender/React/styles.scss
new file mode 100644
index 0000000000..46b51a4e14
--- /dev/null
+++ b/demos/src/Experiments/OnUpdateRerender/React/styles.scss
@@ -0,0 +1,6 @@
+/* Basic editor styles */
+.ProseMirror {
+ > * + * {
+ margin-top: 0.75em;
+ }
+}
diff --git a/demos/src/Experiments/OnUpdateRerender/Vue/TiptapComponent.vue b/demos/src/Experiments/OnUpdateRerender/Vue/TiptapComponent.vue
new file mode 100644
index 0000000000..05396d377a
--- /dev/null
+++ b/demos/src/Experiments/OnUpdateRerender/Vue/TiptapComponent.vue
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
diff --git a/demos/src/Experiments/OnUpdateRerender/Vue/index.html b/demos/src/Experiments/OnUpdateRerender/Vue/index.html
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/demos/src/Experiments/OnUpdateRerender/Vue/index.vue b/demos/src/Experiments/OnUpdateRerender/Vue/index.vue
new file mode 100644
index 0000000000..60da36bbfe
--- /dev/null
+++ b/demos/src/Experiments/OnUpdateRerender/Vue/index.vue
@@ -0,0 +1,27 @@
+
+ INC = {{ count }}
+
+
+
+
diff --git a/packages/react/src/useEditor.ts b/packages/react/src/useEditor.ts
index b6a090b6e0..7734ab8d01 100644
--- a/packages/react/src/useEditor.ts
+++ b/packages/react/src/useEditor.ts
@@ -11,8 +11,68 @@ function useForceUpdate() {
export const useEditor = (options: Partial = {}, deps: DependencyList = []) => {
const [editor, setEditor] = useState(null)
+
const forceUpdate = useForceUpdate()
+ const {
+ onBeforeCreate,
+ onBlur,
+ onCreate,
+ onDestroy,
+ onFocus,
+ onSelectionUpdate,
+ onTransaction,
+ onUpdate,
+ } = options
+
+ // This effect will handle updating the editor instance
+ // when the event handlers change.
+ useEffect(() => {
+ if (!editor) {
+ return
+ }
+
+ if (onBeforeCreate) {
+ editor.off('beforeCreate')
+ editor.on('beforeCreate', onBeforeCreate)
+ }
+
+ if (onBlur) {
+ editor.off('blur')
+ editor.on('blur', onBlur)
+ }
+
+ if (onCreate) {
+ editor.off('create')
+ editor.on('create', onCreate)
+ }
+
+ if (onDestroy) {
+ editor.off('destroy')
+ editor.on('destroy', onDestroy)
+ }
+
+ if (onFocus) {
+ editor.off('focus')
+ editor.on('focus', onFocus)
+ }
+
+ if (onSelectionUpdate) {
+ editor.off('selectionUpdate')
+ editor.on('selectionUpdate', onSelectionUpdate)
+ }
+
+ if (onTransaction) {
+ editor.off('transaction')
+ editor.on('transaction', onTransaction)
+ }
+
+ if (onUpdate) {
+ editor.off('update')
+ editor.on('update', onUpdate)
+ }
+ }, [onBeforeCreate, onBlur, onCreate, onDestroy, onFocus, onSelectionUpdate, onTransaction, onUpdate])
+
useEffect(() => {
let isMounted = true