mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-11-24 03:39:01 +08:00
fix(react): allow updating event handlers on editor (#3811)
This commit is contained in:
parent
1615d7a9bb
commit
6283cee5c7
47
demos/src/Experiments/OnUpdateRerender/React/index.jsx
Normal file
47
demos/src/Experiments/OnUpdateRerender/React/index.jsx
Normal file
@ -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: `
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
|
||||
</p>
|
||||
`,
|
||||
onUpdate,
|
||||
})
|
||||
|
||||
return (
|
||||
<EditorContent editor={editor} />
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const [index, setIndex] = React.useState(0)
|
||||
|
||||
const handleUpdate = ({ editor: currentEditor }) => {
|
||||
console.log(index, 'onUpdate', currentEditor.getHTML())
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => setIndex(index + 1)}>INC</button> = {index}
|
||||
<TiptapComponent onUpdate={handleUpdate} />
|
||||
</div>
|
||||
)
|
||||
}
|
6
demos/src/Experiments/OnUpdateRerender/React/styles.scss
Normal file
6
demos/src/Experiments/OnUpdateRerender/React/styles.scss
Normal file
@ -0,0 +1,6 @@
|
||||
/* Basic editor styles */
|
||||
.ProseMirror {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<editor-content :editor="editor" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
count: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
StarterKit,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<p>
|
||||
The paragraph extension is not really required, but you need at least one node. Sure, that node can be something different.
|
||||
</p>
|
||||
`,
|
||||
onUpdate: ({ editor: currentEditor }) => {
|
||||
console.log(this.count, 'onUpdate', currentEditor.getHTML())
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
unmounted() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
}
|
||||
</script>
|
27
demos/src/Experiments/OnUpdateRerender/Vue/index.vue
Normal file
27
demos/src/Experiments/OnUpdateRerender/Vue/index.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div><button @click="countUp">INC</button> = {{ count }}</div>
|
||||
<TiptapComponent :count="count" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TiptapComponent from './TiptapComponent.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TiptapComponent,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
count: 0,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
countUp() {
|
||||
this.count += 1
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
@ -11,8 +11,68 @@ function useForceUpdate() {
|
||||
|
||||
export const useEditor = (options: Partial<EditorOptions> = {}, deps: DependencyList = []) => {
|
||||
const [editor, setEditor] = useState<Editor | null>(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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user