From 0c8f653257eea5cc9bd112b480f0e0eae9e4d32c Mon Sep 17 00:00:00 2001 From: Dominik Biedebach Date: Thu, 2 Mar 2023 22:09:39 +0100 Subject: [PATCH] fix(react): allow updating event handlers on editor --- .../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 00000000000..e69de29bb2d diff --git a/demos/src/Experiments/OnUpdateRerender/React/index.jsx b/demos/src/Experiments/OnUpdateRerender/React/index.jsx new file mode 100644 index 00000000000..183fa8b3d3e --- /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 ( +
+ = {index} + +
+ ) +} diff --git a/demos/src/Experiments/OnUpdateRerender/React/styles.scss b/demos/src/Experiments/OnUpdateRerender/React/styles.scss new file mode 100644 index 00000000000..46b51a4e147 --- /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 00000000000..05396d377a8 --- /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 00000000000..e69de29bb2d diff --git a/demos/src/Experiments/OnUpdateRerender/Vue/index.vue b/demos/src/Experiments/OnUpdateRerender/Vue/index.vue new file mode 100644 index 00000000000..60da36bbfed --- /dev/null +++ b/demos/src/Experiments/OnUpdateRerender/Vue/index.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/react/src/useEditor.ts b/packages/react/src/useEditor.ts index b6a090b6e0e..7734ab8d01b 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