@tiptap/vue-3 2.5.3 → 2.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Editor.ts CHANGED
@@ -1,16 +1,14 @@
1
1
  import { Editor as CoreEditor, EditorOptions } from '@tiptap/core'
2
2
  import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'
3
3
  import {
4
+ AppContext,
4
5
  ComponentInternalInstance,
5
6
  ComponentPublicInstance,
6
7
  customRef,
7
8
  markRaw,
8
- reactive,
9
9
  Ref,
10
10
  } from 'vue'
11
11
 
12
- import { VueRenderer } from './VueRenderer.js'
13
-
14
12
  function useDebouncedRef<T>(value: T) {
15
13
  return customRef<T>((track, trigger) => {
16
14
  return {
@@ -42,18 +40,18 @@ export class Editor extends CoreEditor {
42
40
 
43
41
  private reactiveExtensionStorage: Ref<Record<string, any>>
44
42
 
45
- public vueRenderers = reactive<Map<string, VueRenderer>>(new Map())
46
-
47
43
  public contentComponent: ContentComponent | null = null
48
44
 
45
+ public appContext: AppContext | null = null
46
+
49
47
  constructor(options: Partial<EditorOptions> = {}) {
50
48
  super(options)
51
49
 
52
50
  this.reactiveState = useDebouncedRef(this.view.state)
53
51
  this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage)
54
52
 
55
- this.on('transaction', () => {
56
- this.reactiveState.value = this.view.state
53
+ this.on('beforeTransaction', ({ nextState }) => {
54
+ this.reactiveState.value = nextState
57
55
  this.reactiveExtensionStorage.value = this.extensionStorage
58
56
  })
59
57
 
@@ -1,5 +1,4 @@
1
1
  import {
2
- DefineComponent,
3
2
  defineComponent,
4
3
  getCurrentInstance,
5
4
  h,
@@ -8,7 +7,6 @@ import {
8
7
  PropType,
9
8
  Ref,
10
9
  ref,
11
- Teleport,
12
10
  unref,
13
11
  watchEffect,
14
12
  } from 'vue'
@@ -45,6 +43,17 @@ export const EditorContent = defineComponent({
45
43
  // @ts-ignore
46
44
  editor.contentComponent = instance.ctx._
47
45
 
46
+ if (instance) {
47
+ editor.appContext = {
48
+ ...instance.appContext,
49
+ provides: {
50
+ // @ts-ignore
51
+ ...instance.provides,
52
+ ...instance.appContext.provides,
53
+ },
54
+ }
55
+ }
56
+
48
57
  editor.setOptions({
49
58
  element,
50
59
  })
@@ -69,6 +78,7 @@ export const EditorContent = defineComponent({
69
78
  }
70
79
 
71
80
  editor.contentComponent = null
81
+ editor.appContext = null
72
82
 
73
83
  if (!editor.options.element.firstChild) {
74
84
  return
@@ -87,35 +97,11 @@ export const EditorContent = defineComponent({
87
97
  },
88
98
 
89
99
  render() {
90
- const vueRenderers: any[] = []
91
-
92
- if (this.editor) {
93
- this.editor.vueRenderers.forEach(vueRenderer => {
94
- const node = h(
95
- Teleport,
96
- {
97
- to: vueRenderer.teleportElement,
98
- key: vueRenderer.id,
99
- },
100
- h(
101
- vueRenderer.component as DefineComponent,
102
- {
103
- ref: vueRenderer.id,
104
- ...vueRenderer.props,
105
- },
106
- ),
107
- )
108
-
109
- vueRenderers.push(node)
110
- })
111
- }
112
-
113
100
  return h(
114
101
  'div',
115
102
  {
116
103
  ref: (el: any) => { this.rootEl = el },
117
104
  },
118
- ...vueRenderers,
119
105
  )
120
106
  },
121
107
  })
@@ -124,7 +124,7 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
124
124
  }
125
125
 
126
126
  get dom() {
127
- if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) {
127
+ if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) {
128
128
  throw Error('Please use the NodeViewWrapper component for your node view.')
129
129
  }
130
130
 
@@ -136,9 +136,7 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
136
136
  return null
137
137
  }
138
138
 
139
- const contentElement = this.dom.querySelector('[data-node-view-content]')
140
-
141
- return (contentElement || this.dom) as HTMLElement | null
139
+ return this.dom.querySelector('[data-node-view-content]') as HTMLElement | null
142
140
  }
143
141
 
144
142
  update(node: ProseMirrorNode, decorations: DecorationWithType[]) {
@@ -183,14 +181,18 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
183
181
  this.renderer.updateProps({
184
182
  selected: true,
185
183
  })
186
- this.renderer.element.classList.add('ProseMirror-selectednode')
184
+ if (this.renderer.element) {
185
+ this.renderer.element.classList.add('ProseMirror-selectednode')
186
+ }
187
187
  }
188
188
 
189
189
  deselectNode() {
190
190
  this.renderer.updateProps({
191
191
  selected: false,
192
192
  })
193
- this.renderer.element.classList.remove('ProseMirror-selectednode')
193
+ if (this.renderer.element) {
194
+ this.renderer.element.classList.remove('ProseMirror-selectednode')
195
+ }
194
196
  }
195
197
 
196
198
  getDecorationClasses() {
@@ -1,62 +1,87 @@
1
1
  import { Editor } from '@tiptap/core'
2
- import { Component, markRaw, reactive } from 'vue'
2
+ import {
3
+ Component, DefineComponent, h, markRaw, reactive, render,
4
+ } from 'vue'
3
5
 
4
6
  import { Editor as ExtendedEditor } from './Editor.js'
5
7
 
6
8
  export interface VueRendererOptions {
7
- editor: Editor,
8
- props?: Record<string, any>,
9
+ editor: Editor;
10
+ props?: Record<string, any>;
11
+ }
12
+
13
+ type ExtendedVNode = ReturnType<typeof h> | null;
14
+
15
+ interface RenderedComponent {
16
+ vNode: ExtendedVNode;
17
+ destroy: () => void;
18
+ el: Element | null;
9
19
  }
10
20
 
11
21
  /**
12
22
  * This class is used to render Vue components inside the editor.
13
23
  */
14
24
  export class VueRenderer {
15
- id: string
25
+ renderedComponent!: RenderedComponent
16
26
 
17
27
  editor: ExtendedEditor
18
28
 
19
29
  component: Component
20
30
 
21
- teleportElement: Element
22
-
23
- element: Element
31
+ el: Element | null
24
32
 
25
33
  props: Record<string, any>
26
34
 
27
35
  constructor(component: Component, { props = {}, editor }: VueRendererOptions) {
28
- this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
29
36
  this.editor = editor as ExtendedEditor
30
37
  this.component = markRaw(component)
31
- this.teleportElement = document.createElement('div')
32
- this.element = this.teleportElement
38
+ this.el = document.createElement('div')
33
39
  this.props = reactive(props)
34
- this.editor.vueRenderers.set(this.id, this)
35
-
36
- if (this.editor.contentComponent) {
37
- this.editor.contentComponent.update()
40
+ this.renderedComponent = this.renderComponent()
41
+ }
38
42
 
39
- if (this.teleportElement.children.length !== 1) {
40
- throw Error('VueRenderer doesn’t support multiple child elements.')
41
- }
43
+ get element(): Element | null {
44
+ return this.renderedComponent.el
45
+ }
42
46
 
43
- this.element = this.teleportElement.firstElementChild as Element
47
+ get ref(): any {
48
+ // Composition API
49
+ if (this.renderedComponent.vNode?.component?.exposed) {
50
+ return this.renderedComponent.vNode.component.exposed
44
51
  }
52
+ // Option API
53
+ return this.renderedComponent.vNode?.component?.proxy
45
54
  }
46
55
 
47
- get ref(): any {
48
- return this.editor.contentComponent?.refs[this.id]
56
+ renderComponent() {
57
+ let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props)
58
+
59
+ if (this.editor.appContext) {
60
+ vNode.appContext = this.editor.appContext
61
+ }
62
+ if (typeof document !== 'undefined' && this.el) {
63
+ render(vNode, this.el)
64
+ }
65
+
66
+ const destroy = () => {
67
+ if (this.el) {
68
+ render(null, this.el)
69
+ }
70
+ this.el = null
71
+ vNode = null
72
+ }
73
+
74
+ return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }
49
75
  }
50
76
 
51
77
  updateProps(props: Record<string, any> = {}): void {
52
- Object
53
- .entries(props)
54
- .forEach(([key, value]) => {
55
- this.props[key] = value
56
- })
78
+ Object.entries(props).forEach(([key, value]) => {
79
+ this.props[key] = value
80
+ })
81
+ this.renderComponent()
57
82
  }
58
83
 
59
84
  destroy(): void {
60
- this.editor.vueRenderers.delete(this.id)
85
+ this.renderedComponent.destroy()
61
86
  }
62
87
  }