@tiptap/vue-3 3.0.0 → 3.0.2

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.
Files changed (206) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +577 -455
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +228 -0
  6. package/dist/index.d.ts +228 -0
  7. package/dist/index.js +541 -443
  8. package/dist/index.js.map +1 -1
  9. package/dist/menus/index.cjs +693 -0
  10. package/dist/menus/index.cjs.map +1 -0
  11. package/dist/menus/index.d.cts +279 -0
  12. package/dist/menus/index.d.ts +279 -0
  13. package/dist/menus/index.js +685 -0
  14. package/dist/menus/index.js.map +1 -0
  15. package/package.json +28 -17
  16. package/src/Editor.ts +23 -17
  17. package/src/EditorContent.ts +14 -44
  18. package/src/VueMarkViewRenderer.ts +130 -0
  19. package/src/VueNodeViewRenderer.ts +99 -36
  20. package/src/VueRenderer.ts +27 -18
  21. package/src/index.ts +1 -2
  22. package/src/menus/BubbleMenu.ts +78 -0
  23. package/src/menus/FloatingMenu.ts +68 -0
  24. package/src/menus/index.ts +2 -0
  25. package/src/useEditor.ts +7 -1
  26. package/dist/index.umd.js +0 -495
  27. package/dist/index.umd.js.map +0 -1
  28. package/dist/packages/core/src/CommandManager.d.ts +0 -20
  29. package/dist/packages/core/src/Editor.d.ts +0 -161
  30. package/dist/packages/core/src/EventEmitter.d.ts +0 -11
  31. package/dist/packages/core/src/Extension.d.ts +0 -343
  32. package/dist/packages/core/src/ExtensionManager.d.ts +0 -55
  33. package/dist/packages/core/src/InputRule.d.ts +0 -42
  34. package/dist/packages/core/src/Mark.d.ts +0 -451
  35. package/dist/packages/core/src/Node.d.ts +0 -611
  36. package/dist/packages/core/src/NodePos.d.ts +0 -44
  37. package/dist/packages/core/src/NodeView.d.ts +0 -31
  38. package/dist/packages/core/src/PasteRule.d.ts +0 -50
  39. package/dist/packages/core/src/Tracker.d.ts +0 -11
  40. package/dist/packages/core/src/commands/blur.d.ts +0 -13
  41. package/dist/packages/core/src/commands/clearContent.d.ts +0 -14
  42. package/dist/packages/core/src/commands/clearNodes.d.ts +0 -13
  43. package/dist/packages/core/src/commands/command.d.ts +0 -18
  44. package/dist/packages/core/src/commands/createParagraphNear.d.ts +0 -13
  45. package/dist/packages/core/src/commands/cut.d.ts +0 -20
  46. package/dist/packages/core/src/commands/deleteCurrentNode.d.ts +0 -13
  47. package/dist/packages/core/src/commands/deleteNode.d.ts +0 -15
  48. package/dist/packages/core/src/commands/deleteRange.d.ts +0 -14
  49. package/dist/packages/core/src/commands/deleteSelection.d.ts +0 -13
  50. package/dist/packages/core/src/commands/enter.d.ts +0 -13
  51. package/dist/packages/core/src/commands/exitCode.d.ts +0 -13
  52. package/dist/packages/core/src/commands/extendMarkRange.d.ts +0 -25
  53. package/dist/packages/core/src/commands/first.d.ts +0 -14
  54. package/dist/packages/core/src/commands/focus.d.ts +0 -27
  55. package/dist/packages/core/src/commands/forEach.d.ts +0 -14
  56. package/dist/packages/core/src/commands/index.d.ts +0 -55
  57. package/dist/packages/core/src/commands/insertContent.d.ts +0 -34
  58. package/dist/packages/core/src/commands/insertContentAt.d.ts +0 -47
  59. package/dist/packages/core/src/commands/join.d.ts +0 -41
  60. package/dist/packages/core/src/commands/joinItemBackward.d.ts +0 -13
  61. package/dist/packages/core/src/commands/joinItemForward.d.ts +0 -13
  62. package/dist/packages/core/src/commands/joinTextblockBackward.d.ts +0 -12
  63. package/dist/packages/core/src/commands/joinTextblockForward.d.ts +0 -12
  64. package/dist/packages/core/src/commands/keyboardShortcut.d.ts +0 -14
  65. package/dist/packages/core/src/commands/lift.d.ts +0 -17
  66. package/dist/packages/core/src/commands/liftEmptyBlock.d.ts +0 -13
  67. package/dist/packages/core/src/commands/liftListItem.d.ts +0 -15
  68. package/dist/packages/core/src/commands/newlineInCode.d.ts +0 -13
  69. package/dist/packages/core/src/commands/resetAttributes.d.ts +0 -16
  70. package/dist/packages/core/src/commands/scrollIntoView.d.ts +0 -13
  71. package/dist/packages/core/src/commands/selectAll.d.ts +0 -13
  72. package/dist/packages/core/src/commands/selectNodeBackward.d.ts +0 -13
  73. package/dist/packages/core/src/commands/selectNodeForward.d.ts +0 -13
  74. package/dist/packages/core/src/commands/selectParentNode.d.ts +0 -13
  75. package/dist/packages/core/src/commands/selectTextblockEnd.d.ts +0 -13
  76. package/dist/packages/core/src/commands/selectTextblockStart.d.ts +0 -13
  77. package/dist/packages/core/src/commands/setContent.d.ts +0 -40
  78. package/dist/packages/core/src/commands/setMark.d.ts +0 -15
  79. package/dist/packages/core/src/commands/setMeta.d.ts +0 -15
  80. package/dist/packages/core/src/commands/setNode.d.ts +0 -16
  81. package/dist/packages/core/src/commands/setNodeSelection.d.ts +0 -14
  82. package/dist/packages/core/src/commands/setTextSelection.d.ts +0 -14
  83. package/dist/packages/core/src/commands/sinkListItem.d.ts +0 -15
  84. package/dist/packages/core/src/commands/splitBlock.d.ts +0 -17
  85. package/dist/packages/core/src/commands/splitListItem.d.ts +0 -15
  86. package/dist/packages/core/src/commands/toggleList.d.ts +0 -18
  87. package/dist/packages/core/src/commands/toggleMark.d.ts +0 -30
  88. package/dist/packages/core/src/commands/toggleNode.d.ts +0 -17
  89. package/dist/packages/core/src/commands/toggleWrap.d.ts +0 -16
  90. package/dist/packages/core/src/commands/undoInputRule.d.ts +0 -13
  91. package/dist/packages/core/src/commands/unsetAllMarks.d.ts +0 -13
  92. package/dist/packages/core/src/commands/unsetMark.d.ts +0 -25
  93. package/dist/packages/core/src/commands/updateAttributes.d.ts +0 -24
  94. package/dist/packages/core/src/commands/wrapIn.d.ts +0 -16
  95. package/dist/packages/core/src/commands/wrapInList.d.ts +0 -16
  96. package/dist/packages/core/src/extensions/clipboardTextSerializer.d.ts +0 -5
  97. package/dist/packages/core/src/extensions/commands.d.ts +0 -3
  98. package/dist/packages/core/src/extensions/editable.d.ts +0 -2
  99. package/dist/packages/core/src/extensions/focusEvents.d.ts +0 -2
  100. package/dist/packages/core/src/extensions/index.d.ts +0 -6
  101. package/dist/packages/core/src/extensions/keymap.d.ts +0 -2
  102. package/dist/packages/core/src/extensions/tabindex.d.ts +0 -2
  103. package/dist/packages/core/src/helpers/combineTransactionSteps.d.ts +0 -10
  104. package/dist/packages/core/src/helpers/createChainableState.d.ts +0 -10
  105. package/dist/packages/core/src/helpers/createDocument.d.ts +0 -12
  106. package/dist/packages/core/src/helpers/createNodeFromContent.d.ts +0 -15
  107. package/dist/packages/core/src/helpers/defaultBlockAt.d.ts +0 -7
  108. package/dist/packages/core/src/helpers/findChildren.d.ts +0 -9
  109. package/dist/packages/core/src/helpers/findChildrenInRange.d.ts +0 -10
  110. package/dist/packages/core/src/helpers/findParentNode.d.ts +0 -16
  111. package/dist/packages/core/src/helpers/findParentNodeClosestToPos.d.ts +0 -17
  112. package/dist/packages/core/src/helpers/generateHTML.d.ts +0 -8
  113. package/dist/packages/core/src/helpers/generateJSON.d.ts +0 -8
  114. package/dist/packages/core/src/helpers/generateText.d.ts +0 -12
  115. package/dist/packages/core/src/helpers/getAttributes.d.ts +0 -9
  116. package/dist/packages/core/src/helpers/getAttributesFromExtensions.d.ts +0 -6
  117. package/dist/packages/core/src/helpers/getChangedRanges.d.ts +0 -11
  118. package/dist/packages/core/src/helpers/getDebugJSON.d.ts +0 -8
  119. package/dist/packages/core/src/helpers/getExtensionField.d.ts +0 -9
  120. package/dist/packages/core/src/helpers/getHTMLFromFragment.d.ts +0 -2
  121. package/dist/packages/core/src/helpers/getMarkAttributes.d.ts +0 -3
  122. package/dist/packages/core/src/helpers/getMarkRange.d.ts +0 -3
  123. package/dist/packages/core/src/helpers/getMarkType.d.ts +0 -2
  124. package/dist/packages/core/src/helpers/getMarksBetween.d.ts +0 -3
  125. package/dist/packages/core/src/helpers/getNodeAtPosition.d.ts +0 -11
  126. package/dist/packages/core/src/helpers/getNodeAttributes.d.ts +0 -3
  127. package/dist/packages/core/src/helpers/getNodeType.d.ts +0 -2
  128. package/dist/packages/core/src/helpers/getRenderedAttributes.d.ts +0 -3
  129. package/dist/packages/core/src/helpers/getSchema.d.ts +0 -4
  130. package/dist/packages/core/src/helpers/getSchemaByResolvedExtensions.d.ts +0 -10
  131. package/dist/packages/core/src/helpers/getSchemaTypeByName.d.ts +0 -8
  132. package/dist/packages/core/src/helpers/getSchemaTypeNameByName.d.ts +0 -8
  133. package/dist/packages/core/src/helpers/getSplittedAttributes.d.ts +0 -9
  134. package/dist/packages/core/src/helpers/getText.d.ts +0 -15
  135. package/dist/packages/core/src/helpers/getTextBetween.d.ts +0 -14
  136. package/dist/packages/core/src/helpers/getTextContentFromNodes.d.ts +0 -8
  137. package/dist/packages/core/src/helpers/getTextSerializersFromSchema.d.ts +0 -8
  138. package/dist/packages/core/src/helpers/index.d.ts +0 -50
  139. package/dist/packages/core/src/helpers/injectExtensionAttributesToParseRule.d.ts +0 -9
  140. package/dist/packages/core/src/helpers/isActive.d.ts +0 -2
  141. package/dist/packages/core/src/helpers/isAtEndOfNode.d.ts +0 -2
  142. package/dist/packages/core/src/helpers/isAtStartOfNode.d.ts +0 -2
  143. package/dist/packages/core/src/helpers/isExtensionRulesEnabled.d.ts +0 -2
  144. package/dist/packages/core/src/helpers/isList.d.ts +0 -2
  145. package/dist/packages/core/src/helpers/isMarkActive.d.ts +0 -3
  146. package/dist/packages/core/src/helpers/isNodeActive.d.ts +0 -3
  147. package/dist/packages/core/src/helpers/isNodeEmpty.d.ts +0 -2
  148. package/dist/packages/core/src/helpers/isNodeSelection.d.ts +0 -2
  149. package/dist/packages/core/src/helpers/isTextSelection.d.ts +0 -2
  150. package/dist/packages/core/src/helpers/posToDOMRect.d.ts +0 -2
  151. package/dist/packages/core/src/helpers/resolveFocusPosition.d.ts +0 -4
  152. package/dist/packages/core/src/helpers/selectionToInsertionEnd.d.ts +0 -2
  153. package/dist/packages/core/src/helpers/splitExtensions.d.ts +0 -9
  154. package/dist/packages/core/src/index.d.ts +0 -24
  155. package/dist/packages/core/src/inputRules/index.d.ts +0 -5
  156. package/dist/packages/core/src/inputRules/markInputRule.d.ts +0 -13
  157. package/dist/packages/core/src/inputRules/nodeInputRule.d.ts +0 -23
  158. package/dist/packages/core/src/inputRules/textInputRule.d.ts +0 -10
  159. package/dist/packages/core/src/inputRules/textblockTypeInputRule.d.ts +0 -15
  160. package/dist/packages/core/src/inputRules/wrappingInputRule.d.ts +0 -28
  161. package/dist/packages/core/src/pasteRules/index.d.ts +0 -3
  162. package/dist/packages/core/src/pasteRules/markPasteRule.d.ts +0 -13
  163. package/dist/packages/core/src/pasteRules/nodePasteRule.d.ts +0 -13
  164. package/dist/packages/core/src/pasteRules/textPasteRule.d.ts +0 -10
  165. package/dist/packages/core/src/style.d.ts +0 -1
  166. package/dist/packages/core/src/types.d.ts +0 -255
  167. package/dist/packages/core/src/utilities/callOrReturn.d.ts +0 -9
  168. package/dist/packages/core/src/utilities/createStyleTag.d.ts +0 -1
  169. package/dist/packages/core/src/utilities/deleteProps.d.ts +0 -6
  170. package/dist/packages/core/src/utilities/elementFromString.d.ts +0 -1
  171. package/dist/packages/core/src/utilities/escapeForRegEx.d.ts +0 -1
  172. package/dist/packages/core/src/utilities/findDuplicates.d.ts +0 -1
  173. package/dist/packages/core/src/utilities/fromString.d.ts +0 -1
  174. package/dist/packages/core/src/utilities/index.d.ts +0 -20
  175. package/dist/packages/core/src/utilities/isAndroid.d.ts +0 -1
  176. package/dist/packages/core/src/utilities/isEmptyObject.d.ts +0 -1
  177. package/dist/packages/core/src/utilities/isFunction.d.ts +0 -1
  178. package/dist/packages/core/src/utilities/isMacOS.d.ts +0 -1
  179. package/dist/packages/core/src/utilities/isNumber.d.ts +0 -1
  180. package/dist/packages/core/src/utilities/isPlainObject.d.ts +0 -1
  181. package/dist/packages/core/src/utilities/isRegExp.d.ts +0 -1
  182. package/dist/packages/core/src/utilities/isString.d.ts +0 -1
  183. package/dist/packages/core/src/utilities/isiOS.d.ts +0 -1
  184. package/dist/packages/core/src/utilities/mergeAttributes.d.ts +0 -1
  185. package/dist/packages/core/src/utilities/mergeDeep.d.ts +0 -1
  186. package/dist/packages/core/src/utilities/minMax.d.ts +0 -1
  187. package/dist/packages/core/src/utilities/objectIncludes.d.ts +0 -8
  188. package/dist/packages/core/src/utilities/removeDuplicates.d.ts +0 -8
  189. package/dist/packages/extension-bubble-menu/src/bubble-menu-plugin.d.ts +0 -76
  190. package/dist/packages/extension-bubble-menu/src/bubble-menu.d.ts +0 -15
  191. package/dist/packages/extension-bubble-menu/src/index.d.ts +0 -4
  192. package/dist/packages/extension-floating-menu/src/floating-menu-plugin.d.ts +0 -66
  193. package/dist/packages/extension-floating-menu/src/floating-menu.d.ts +0 -15
  194. package/dist/packages/extension-floating-menu/src/index.d.ts +0 -4
  195. package/dist/packages/vue-3/src/BubbleMenu.d.ts +0 -59
  196. package/dist/packages/vue-3/src/Editor.d.ts +0 -23
  197. package/dist/packages/vue-3/src/EditorContent.d.ts +0 -17
  198. package/dist/packages/vue-3/src/FloatingMenu.d.ts +0 -48
  199. package/dist/packages/vue-3/src/NodeViewContent.d.ts +0 -13
  200. package/dist/packages/vue-3/src/NodeViewWrapper.d.ts +0 -13
  201. package/dist/packages/vue-3/src/VueNodeViewRenderer.d.ts +0 -48
  202. package/dist/packages/vue-3/src/VueRenderer.d.ts +0 -36
  203. package/dist/packages/vue-3/src/index.d.ts +0 -10
  204. package/dist/packages/vue-3/src/useEditor.d.ts +0 -3
  205. package/src/BubbleMenu.ts +0 -71
  206. package/src/FloatingMenu.ts +0 -66
@@ -1,23 +1,12 @@
1
- import {
2
- DecorationWithType,
3
- NodeView,
4
- NodeViewProps,
5
- NodeViewRenderer,
6
- NodeViewRendererOptions,
7
- NodeViewRendererProps,
8
- } from '@tiptap/core'
9
- import { Node as ProseMirrorNode } from '@tiptap/pm/model'
10
- import { Decoration, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
11
- import {
12
- Component,
13
- defineComponent,
14
- PropType,
15
- provide,
16
- Ref,
17
- ref,
18
- } from 'vue'
19
-
20
- import { Editor } from './Editor.js'
1
+ /* eslint-disable no-underscore-dangle */
2
+ import type { DecorationWithType, NodeViewProps, NodeViewRenderer, NodeViewRendererOptions } from '@tiptap/core'
3
+ import { NodeView } from '@tiptap/core'
4
+ import type { Node as ProseMirrorNode } from '@tiptap/pm/model'
5
+ import type { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
6
+ import type { Component, PropType, Ref } from 'vue'
7
+ import { defineComponent, provide, ref } from 'vue'
8
+
9
+ import type { Editor } from './Editor.js'
21
10
  import { VueRenderer } from './VueRenderer.js'
22
11
 
23
12
  export const nodeViewProps = {
@@ -53,15 +42,29 @@ export const nodeViewProps = {
53
42
  type: Function as PropType<NodeViewProps['deleteNode']>,
54
43
  required: true as const,
55
44
  },
45
+ view: {
46
+ type: Object as PropType<NodeViewProps['view']>,
47
+ required: true as const,
48
+ },
49
+ innerDecorations: {
50
+ type: Object as PropType<NodeViewProps['innerDecorations']>,
51
+ required: true as const,
52
+ },
53
+ HTMLAttributes: {
54
+ type: Object as PropType<NodeViewProps['HTMLAttributes']>,
55
+ required: true as const,
56
+ },
56
57
  }
57
58
 
58
59
  export interface VueNodeViewRendererOptions extends NodeViewRendererOptions {
59
60
  update:
60
61
  | ((props: {
61
62
  oldNode: ProseMirrorNode
62
- oldDecorations: Decoration[]
63
+ oldDecorations: readonly Decoration[]
64
+ oldInnerDecorations: DecorationSource
63
65
  newNode: ProseMirrorNode
64
- newDecorations: Decoration[]
66
+ newDecorations: readonly Decoration[]
67
+ innerDecorations: DecorationSource
65
68
  updateProps: () => void
66
69
  }) => boolean)
67
70
  | null
@@ -73,16 +76,19 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
73
76
  decorationClasses!: Ref<string>
74
77
 
75
78
  mount() {
76
- const props: NodeViewProps = {
79
+ const props = {
77
80
  editor: this.editor,
78
81
  node: this.node,
79
- decorations: this.decorations,
82
+ decorations: this.decorations as DecorationWithType[],
83
+ innerDecorations: this.innerDecorations,
84
+ view: this.view,
80
85
  selected: false,
81
86
  extension: this.extension,
87
+ HTMLAttributes: this.HTMLAttributes,
82
88
  getPos: () => this.getPos(),
83
89
  updateAttributes: (attributes = {}) => this.updateAttributes(attributes),
84
90
  deleteNode: () => this.deleteNode(),
85
- }
91
+ } satisfies NodeViewProps
86
92
 
87
93
  const onDragStart = this.onDragStart.bind(this)
88
94
 
@@ -117,12 +123,19 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
117
123
  __file: this.component.__file,
118
124
  })
119
125
 
126
+ this.handleSelectionUpdate = this.handleSelectionUpdate.bind(this)
127
+ this.editor.on('selectionUpdate', this.handleSelectionUpdate)
128
+
120
129
  this.renderer = new VueRenderer(extendedComponent, {
121
130
  editor: this.editor,
122
131
  props,
123
132
  })
124
133
  }
125
134
 
135
+ /**
136
+ * Return the DOM element.
137
+ * This is the element that will be used to display the node view.
138
+ */
126
139
  get dom() {
127
140
  if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) {
128
141
  throw Error('Please use the NodeViewWrapper component for your node view.')
@@ -131,18 +144,51 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
131
144
  return this.renderer.element as HTMLElement
132
145
  }
133
146
 
147
+ /**
148
+ * Return the content DOM element.
149
+ * This is the element that will be used to display the rich-text content of the node.
150
+ */
134
151
  get contentDOM() {
135
152
  if (this.node.isLeaf) {
136
153
  return null
137
154
  }
138
155
 
139
- const contentElement = this.dom.querySelector('[data-node-view-content]')
156
+ return this.dom.querySelector('[data-node-view-content]') as HTMLElement | null
157
+ }
158
+
159
+ /**
160
+ * On editor selection update, check if the node is selected.
161
+ * If it is, call `selectNode`, otherwise call `deselectNode`.
162
+ */
163
+ handleSelectionUpdate() {
164
+ const { from, to } = this.editor.state.selection
165
+ const pos = this.getPos()
166
+
167
+ if (typeof pos !== 'number') {
168
+ return
169
+ }
170
+
171
+ if (from <= pos && to >= pos + this.node.nodeSize) {
172
+ if (this.renderer.props.selected) {
173
+ return
174
+ }
140
175
 
141
- return (contentElement || this.dom) as HTMLElement | null
176
+ this.selectNode()
177
+ } else {
178
+ if (!this.renderer.props.selected) {
179
+ return
180
+ }
181
+
182
+ this.deselectNode()
183
+ }
142
184
  }
143
185
 
144
- update(node: ProseMirrorNode, decorations: DecorationWithType[]) {
145
- const updateProps = (props?: Record<string, any>) => {
186
+ /**
187
+ * On update, update the React component.
188
+ * To prevent unnecessary updates, the `update` option can be used.
189
+ */
190
+ update(node: ProseMirrorNode, decorations: readonly Decoration[], innerDecorations: DecorationSource): boolean {
191
+ const rerenderComponent = (props?: Record<string, any>) => {
146
192
  this.decorationClasses.value = this.getDecorationClasses()
147
193
  this.renderer.updateProps(props)
148
194
  }
@@ -150,16 +196,20 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
150
196
  if (typeof this.options.update === 'function') {
151
197
  const oldNode = this.node
152
198
  const oldDecorations = this.decorations
199
+ const oldInnerDecorations = this.innerDecorations
153
200
 
154
201
  this.node = node
155
202
  this.decorations = decorations
203
+ this.innerDecorations = innerDecorations
156
204
 
157
205
  return this.options.update({
158
206
  oldNode,
159
207
  oldDecorations,
160
208
  newNode: node,
161
209
  newDecorations: decorations,
162
- updateProps: () => updateProps({ node, decorations }),
210
+ oldInnerDecorations,
211
+ innerDecorations,
212
+ updateProps: () => rerenderComponent({ node, decorations, innerDecorations }),
163
213
  })
164
214
  }
165
215
 
@@ -167,18 +217,23 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
167
217
  return false
168
218
  }
169
219
 
170
- if (node === this.node && this.decorations === decorations) {
220
+ if (node === this.node && this.decorations === decorations && this.innerDecorations === innerDecorations) {
171
221
  return true
172
222
  }
173
223
 
174
224
  this.node = node
175
225
  this.decorations = decorations
226
+ this.innerDecorations = innerDecorations
176
227
 
177
- updateProps({ node, decorations })
228
+ rerenderComponent({ node, decorations, innerDecorations })
178
229
 
179
230
  return true
180
231
  }
181
232
 
233
+ /**
234
+ * Select the node.
235
+ * Add the `selected` prop and the `ProseMirror-selectednode` class.
236
+ */
182
237
  selectNode() {
183
238
  this.renderer.updateProps({
184
239
  selected: true,
@@ -188,6 +243,10 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
188
243
  }
189
244
  }
190
245
 
246
+ /**
247
+ * Deselect the node.
248
+ * Remove the `selected` prop and the `ProseMirror-selectednode` class.
249
+ */
191
250
  deselectNode() {
192
251
  this.renderer.updateProps({
193
252
  selected: false,
@@ -209,21 +268,25 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
209
268
 
210
269
  destroy() {
211
270
  this.renderer.destroy()
271
+ this.editor.off('selectionUpdate', this.handleSelectionUpdate)
212
272
  }
213
273
  }
214
274
 
215
275
  export function VueNodeViewRenderer(
216
- component: Component,
276
+ component: Component<NodeViewProps>,
217
277
  options?: Partial<VueNodeViewRendererOptions>,
218
278
  ): NodeViewRenderer {
219
- return (props: NodeViewRendererProps) => {
279
+ return props => {
220
280
  // try to get the parent component
221
281
  // this is important for vue devtools to show the component hierarchy correctly
222
282
  // maybe it’s `undefined` because <editor-content> isn’t rendered yet
223
283
  if (!(props.editor as Editor).contentComponent) {
224
- return {}
284
+ return {} as unknown as ProseMirrorNodeView
225
285
  }
286
+ // check for class-component and normalize if neccessary
287
+ const normalizedComponent =
288
+ typeof component === 'function' && '__vccOpts' in component ? (component.__vccOpts as Component) : component
226
289
 
227
- return new VueNodeView(component, props, options) as unknown as ProseMirrorNodeView
290
+ return new VueNodeView(normalizedComponent, props, options)
228
291
  }
229
292
  }
@@ -1,13 +1,12 @@
1
- import { Editor } from '@tiptap/core'
2
- import {
3
- Component, DefineComponent, h, markRaw, reactive, render,
4
- } from 'vue'
1
+ import type { Editor } from '@tiptap/core'
2
+ import type { Component, DefineComponent } from 'vue'
3
+ import { h, markRaw, reactive, render } from 'vue'
5
4
 
6
- import { Editor as ExtendedEditor } from './Editor.js'
5
+ import type { Editor as ExtendedEditor } from './Editor.js'
7
6
 
8
7
  export interface VueRendererOptions {
9
- editor: Editor,
10
- props?: Record<string, any>,
8
+ editor: Editor
9
+ props?: Record<string, any>
11
10
  }
12
11
 
13
12
  type ExtendedVNode = ReturnType<typeof h> | null
@@ -22,8 +21,6 @@ interface RenderedComponent {
22
21
  * This class is used to render Vue components inside the editor.
23
22
  */
24
23
  export class VueRenderer {
25
- id: string
26
-
27
24
  renderedComponent!: RenderedComponent
28
25
 
29
26
  editor: ExtendedEditor
@@ -35,7 +32,6 @@ export class VueRenderer {
35
32
  props: Record<string, any>
36
33
 
37
34
  constructor(component: Component, { props = {}, editor }: VueRendererOptions) {
38
- this.id = Math.floor(Math.random() * 0xFFFFFFFF).toString()
39
35
  this.editor = editor as ExtendedEditor
40
36
  this.component = markRaw(component)
41
37
  this.el = document.createElement('div')
@@ -47,13 +43,29 @@ export class VueRenderer {
47
43
  return this.renderedComponent.el
48
44
  }
49
45
 
46
+ get ref(): any {
47
+ // Composition API
48
+ if (this.renderedComponent.vNode?.component?.exposed) {
49
+ return this.renderedComponent.vNode.component.exposed
50
+ }
51
+ // Option API
52
+ return this.renderedComponent.vNode?.component?.proxy
53
+ }
54
+
50
55
  renderComponent() {
51
56
  let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props)
52
57
 
53
- if (typeof document !== 'undefined' && this.el) { render(vNode, this.el) }
58
+ if (this.editor.appContext) {
59
+ vNode.appContext = this.editor.appContext
60
+ }
61
+ if (typeof document !== 'undefined' && this.el) {
62
+ render(vNode, this.el)
63
+ }
54
64
 
55
65
  const destroy = () => {
56
- if (this.el) { render(null, this.el) }
66
+ if (this.el) {
67
+ render(null, this.el)
68
+ }
57
69
  this.el = null
58
70
  vNode = null
59
71
  }
@@ -62,12 +74,9 @@ export class VueRenderer {
62
74
  }
63
75
 
64
76
  updateProps(props: Record<string, any> = {}): void {
65
-
66
- Object
67
- .entries(props)
68
- .forEach(([key, value]) => {
69
- this.props[key] = value
70
- })
77
+ Object.entries(props).forEach(([key, value]) => {
78
+ this.props[key] = value
79
+ })
71
80
  this.renderComponent()
72
81
  }
73
82
 
package/src/index.ts CHANGED
@@ -1,10 +1,9 @@
1
- export * from './BubbleMenu.js'
2
1
  export { Editor } from './Editor.js'
3
2
  export * from './EditorContent.js'
4
- export * from './FloatingMenu.js'
5
3
  export * from './NodeViewContent.js'
6
4
  export * from './NodeViewWrapper.js'
7
5
  export * from './useEditor.js'
6
+ export * from './VueMarkViewRenderer.js'
8
7
  export * from './VueNodeViewRenderer.js'
9
8
  export * from './VueRenderer.js'
10
9
  export * from '@tiptap/core'
@@ -0,0 +1,78 @@
1
+ import type { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu'
2
+ import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'
3
+ import type { PropType } from 'vue'
4
+ import { defineComponent, h, onBeforeUnmount, onMounted, ref, Teleport } from 'vue'
5
+
6
+ export const BubbleMenu = defineComponent({
7
+ name: 'BubbleMenu',
8
+
9
+ props: {
10
+ pluginKey: {
11
+ type: [String, Object] as PropType<BubbleMenuPluginProps['pluginKey']>,
12
+ default: 'bubbleMenu',
13
+ },
14
+
15
+ editor: {
16
+ type: Object as PropType<BubbleMenuPluginProps['editor']>,
17
+ required: true,
18
+ },
19
+
20
+ updateDelay: {
21
+ type: Number as PropType<BubbleMenuPluginProps['updateDelay']>,
22
+ default: undefined,
23
+ },
24
+
25
+ resizeDelay: {
26
+ type: Number as PropType<BubbleMenuPluginProps['resizeDelay']>,
27
+ default: undefined,
28
+ },
29
+
30
+ options: {
31
+ type: Object as PropType<BubbleMenuPluginProps['options']>,
32
+ default: () => ({}),
33
+ },
34
+
35
+ shouldShow: {
36
+ type: Function as PropType<Exclude<Required<BubbleMenuPluginProps>['shouldShow'], null>>,
37
+ default: null,
38
+ },
39
+ },
40
+
41
+ setup(props, { slots }) {
42
+ const root = ref<HTMLElement | null>(null)
43
+
44
+ onMounted(() => {
45
+ const { editor, options, pluginKey, resizeDelay, shouldShow, updateDelay } = props
46
+
47
+ if (!root.value) {
48
+ return
49
+ }
50
+
51
+ root.value.style.visibility = 'hidden'
52
+ root.value.style.position = 'absolute'
53
+
54
+ // remove the element from the DOM
55
+ root.value.remove()
56
+
57
+ editor.registerPlugin(
58
+ BubbleMenuPlugin({
59
+ editor,
60
+ element: root.value as HTMLElement,
61
+ options,
62
+ pluginKey,
63
+ resizeDelay,
64
+ shouldShow,
65
+ updateDelay,
66
+ }),
67
+ )
68
+ })
69
+
70
+ onBeforeUnmount(() => {
71
+ const { pluginKey, editor } = props
72
+
73
+ editor.unregisterPlugin(pluginKey)
74
+ })
75
+
76
+ return () => h(Teleport, { to: 'body' }, h('div', { ref: root }, slots.default?.()))
77
+ },
78
+ })
@@ -0,0 +1,68 @@
1
+ import type { FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'
2
+ import { FloatingMenuPlugin } from '@tiptap/extension-floating-menu'
3
+ import type { PropType } from 'vue'
4
+ import { defineComponent, h, onBeforeUnmount, onMounted, ref, Teleport } from 'vue'
5
+
6
+ export const FloatingMenu = defineComponent({
7
+ name: 'FloatingMenu',
8
+
9
+ props: {
10
+ pluginKey: {
11
+ // TODO: TypeScript breaks :(
12
+ // type: [String, Object as PropType<Exclude<FloatingMenuPluginProps['pluginKey'], string>>],
13
+ type: null,
14
+ default: 'floatingMenu',
15
+ },
16
+
17
+ editor: {
18
+ type: Object as PropType<FloatingMenuPluginProps['editor']>,
19
+ required: true,
20
+ },
21
+
22
+ options: {
23
+ type: Object as PropType<FloatingMenuPluginProps['options']>,
24
+ default: () => ({}),
25
+ },
26
+
27
+ shouldShow: {
28
+ type: Function as PropType<Exclude<Required<FloatingMenuPluginProps>['shouldShow'], null>>,
29
+ default: null,
30
+ },
31
+ },
32
+
33
+ setup(props, { slots }) {
34
+ const root = ref<HTMLElement | null>(null)
35
+
36
+ onMounted(() => {
37
+ const { pluginKey, editor, options, shouldShow } = props
38
+
39
+ if (!root.value) {
40
+ return
41
+ }
42
+
43
+ root.value.style.visibility = 'hidden'
44
+ root.value.style.position = 'absolute'
45
+
46
+ // remove the element from the DOM
47
+ root.value.remove()
48
+
49
+ editor.registerPlugin(
50
+ FloatingMenuPlugin({
51
+ pluginKey,
52
+ editor,
53
+ element: root.value as HTMLElement,
54
+ options,
55
+ shouldShow,
56
+ }),
57
+ )
58
+ })
59
+
60
+ onBeforeUnmount(() => {
61
+ const { pluginKey, editor } = props
62
+
63
+ editor.unregisterPlugin(pluginKey)
64
+ })
65
+
66
+ return () => h(Teleport, { to: 'body' }, h('div', { ref: root }, slots.default?.()))
67
+ },
68
+ })
@@ -0,0 +1,2 @@
1
+ export * from './BubbleMenu.js'
2
+ export * from './FloatingMenu.js'
package/src/useEditor.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { EditorOptions } from '@tiptap/core'
1
+ import type { EditorOptions } from '@tiptap/core'
2
2
  import { onBeforeUnmount, onMounted, shallowRef } from 'vue'
3
3
 
4
4
  import { Editor } from './Editor.js'
@@ -11,6 +11,12 @@ export const useEditor = (options: Partial<EditorOptions> = {}) => {
11
11
  })
12
12
 
13
13
  onBeforeUnmount(() => {
14
+ // Cloning root node (and its children) to avoid content being lost by destroy
15
+ const nodes = editor.value?.options.element
16
+ const newEl = nodes?.cloneNode(true) as HTMLElement
17
+
18
+ nodes?.parentNode?.replaceChild(newEl, nodes)
19
+
14
20
  editor.value?.destroy()
15
21
  })
16
22