fix(vue-3): on editor destruction, transition smoothly (#5772)

This commit is contained in:
Éric Le Maître 2024-11-07 09:19:46 +01:00 committed by GitHub
parent 8a2e548c5b
commit 94a8d258f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 98 additions and 18 deletions

View File

@ -0,0 +1,5 @@
---
"@tiptap/vue-3": patch
---
Fix editor destruction before transition end if editor is nested

View File

@ -36,7 +36,7 @@ Before submitting a pull request:
- Check the codebase to ensure that your feature doesn't already exist.
- Check the pull requests to ensure that another person hasn't already submitted the feature or fix.
Before commiting:
Before committing:
- Make sure to run the tests and linter before committing your changes.
- If you are making changes to one of the packages, make sure to **always** include a [changeset](https://github.com/changesets/changesets) in your PR describing **what changed** with a **description** of the change. Those are responsible for changelog creation

View File

@ -1,7 +1,7 @@
import { mergeAttributes, Node } from '@tiptap/core'
import { VueNodeViewRenderer } from '@tiptap/vue-3'
import Component from './Component.vue'
import Component from './VueComponent.vue'
export default Node.create({
name: 'vueComponent',

View File

@ -0,0 +1,36 @@
<template>
<div>
<EditorContent :editor="editor" />
</div>
</template>
<script setup lang="ts">
import StarterKit from '@tiptap/starter-kit'
import { EditorContent, useEditor } from '@tiptap/vue-3'
import { ref } from 'vue'
import VueComponent from './Extension.js'
import type { TNote } from './types.js'
const note = ref<TNote>({
id: 'note-1',
content: `
<p>Some random note text</p>
<vue-component count="0"></vue-component>
`,
})
const editor = useEditor({
content: note.value.content,
editorProps: {
attributes: {
class: 'textarea',
},
},
extensions: [
StarterKit,
VueComponent,
],
})
</script>

View File

@ -3,26 +3,30 @@ context('/src/Examples/Transition/Vue/', () => {
cy.visit('/src/Examples/Transition/Vue/')
})
it('should not have an active tiptap instance but a button', () => {
it('should have two buttons and no active tiptap instance', () => {
cy.get('.tiptap').should('not.exist')
cy.get('#toggle-editor').should('exist')
cy.get('#toggle-direct-editor').should('exist')
cy.get('#toggle-nested-editor').should('exist')
})
it('clicking the button should show the editor', () => {
cy.get('#toggle-editor').click()
it('clicking the buttons should show two editors', () => {
cy.get('#toggle-direct-editor').click()
cy.get('#toggle-nested-editor').click()
cy.get('.tiptap').should('exist')
cy.get('.tiptap').should('be.visible')
})
it('clicking the button again should hide the editor', () => {
cy.get('#toggle-editor').click()
it('clicking the buttons again should hide the editors', () => {
cy.get('#toggle-direct-editor').click()
cy.get('#toggle-nested-editor').click()
cy.get('.tiptap').should('exist')
cy.get('.tiptap').should('be.visible')
cy.get('#toggle-editor').click()
cy.get('#toggle-direct-editor').click()
cy.get('#toggle-nested-editor').click()
cy.get('.tiptap').should('not.exist')
})

View File

@ -1,12 +1,18 @@
<script setup lang="ts">
import StarterKit from '@tiptap/starter-kit'
import { EditorContent, useEditor } from '@tiptap/vue-3'
import { ref } from 'vue'
import VueComponent from './Extension.js'
import ParentComponent from './ParentComponent.vue'
import type { TNote } from './types.js'
/** Display editor in the same component */
const showDirectEditor = ref(false)
/** Display editor in a child component */
const showNestedEditor = ref(false)
const note = ref<TNote>({
id: 'note-1',
content: `
@ -28,24 +34,43 @@ const editor = useEditor({
],
})
const showEditor = ref(false)
</script>
<template>
<!-- Transition with editor in the same component -->
<div>
<button
id="toggle-direct-editor"
type="button"
@click="showEditor = !showEditor"
style="margin-bottom: 1rem;"
id="toggle-editor"
@click="showDirectEditor = !showDirectEditor"
>
{{ showEditor ? 'Hide editor' : 'Show editor' }}
{{ showDirectEditor ? 'Hide direct editor' : 'Show direct editor' }}
</button>
<transition name="fade">
<div v-if="showEditor" class="tiptap-wrapper">
<editor-content :editor="editor" />
<div v-if="showDirectEditor" class="tiptap-wrapper">
<EditorContent :editor="editor" />
</div>
</transition>
</div>
<hr>
<!-- Transition with editor in a child component -->
<div>
<button
id="toggle-nested-editor"
type="button"
style="margin-bottom: 1rem;"
@click="showNestedEditor = !showNestedEditor"
>
{{ showNestedEditor ? 'Hide nested editor' : 'Show nested editor' }}
</button>
<transition name="fade">
<div v-if="showNestedEditor" class="tiptap-wrapper">
<ParentComponent />
</div>
</transition>
</div>
@ -62,6 +87,11 @@ const showEditor = ref(false)
opacity: 0;
}
hr {
margin-top: 1rem;
margin-bottom: 1rem;
}
.tiptap-wrapper {
background-color: var(--purple-light);
border: 2px solid var(--purple);

View File

@ -59,7 +59,6 @@ export const EditorContent = defineComponent({
editor.createNodeViews()
})
}
})

View File

@ -11,6 +11,12 @@ export const useEditor = (options: Partial<EditorOptions> = {}) => {
})
onBeforeUnmount(() => {
// Cloning root node (and its children) to avoid content being lost by destroy
const nodes = editor.value?.options.element
const newEl = nodes?.cloneNode(true) as HTMLElement
nodes?.parentNode?.replaceChild(newEl, nodes)
editor.value?.destroy()
})