Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(vue-3): Transition with editor destruction #5772

Merged
merged 12 commits into from
Nov 7, 2024
5 changes: 5 additions & 0 deletions .changeset/five-flowers-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tiptap/vue-3": patch
---

Fix editor destruction before transition end if editor is nested
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion demos/src/Examples/Transition/Vue/Extension.js
Original file line number Diff line number Diff line change
@@ -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',
Expand Down
36 changes: 36 additions & 0 deletions demos/src/Examples/Transition/Vue/ParentComponent.vue
Original file line number Diff line number Diff line change
@@ -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>
18 changes: 11 additions & 7 deletions demos/src/Examples/Transition/Vue/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
Expand Down
46 changes: 38 additions & 8 deletions demos/src/Examples/Transition/Vue/index.vue
Original file line number Diff line number Diff line change
@@ -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: `
Expand All @@ -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>
Expand All @@ -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);
Expand Down
1 change: 0 additions & 1 deletion packages/vue-3/src/EditorContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export const EditorContent = defineComponent({

editor.createNodeViews()
})

}
})

Expand Down
6 changes: 6 additions & 0 deletions packages/vue-3/src/useEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
})

Expand Down