@tiptap/vue-3 3.0.0-next.3 → 3.0.0-next.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tiptap/vue-3",
3
3
  "description": "Vue components for tiptap",
4
- "version": "3.0.0-next.3",
4
+ "version": "3.0.0-next.5",
5
5
  "homepage": "https://tiptap.dev",
6
6
  "keywords": [
7
7
  "tiptap",
@@ -14,9 +14,20 @@
14
14
  },
15
15
  "exports": {
16
16
  ".": {
17
- "types": "./dist/index.d.ts",
17
+ "types": {
18
+ "import": "./dist/index.d.ts",
19
+ "require": "./dist/index.d.cts"
20
+ },
18
21
  "import": "./dist/index.js",
19
22
  "require": "./dist/index.cjs"
23
+ },
24
+ "./menus": {
25
+ "types": {
26
+ "import": "./dist/menus/index.d.ts",
27
+ "require": "./dist/menus/index.d.cts"
28
+ },
29
+ "import": "./dist/menus/index.js",
30
+ "require": "./dist/menus/index.cjs"
20
31
  }
21
32
  },
22
33
  "main": "dist/index.cjs",
@@ -27,19 +38,20 @@
27
38
  "src",
28
39
  "dist"
29
40
  ],
30
- "dependencies": {
31
- "@tiptap/extension-bubble-menu": "^3.0.0-next.3",
32
- "@tiptap/extension-floating-menu": "^3.0.0-next.3"
33
- },
34
41
  "devDependencies": {
35
- "@tiptap/core": "^3.0.0-next.3",
36
- "@tiptap/pm": "^3.0.0-next.3",
37
- "vue": "^3.0.0"
42
+ "@tiptap/core": "^3.0.0-next.5",
43
+ "@tiptap/pm": "^3.0.0-next.5",
44
+ "vue": "^3.5.13"
45
+ },
46
+ "optionalDependencies": {
47
+ "@tiptap/extension-bubble-menu": "^3.0.0-next.5",
48
+ "@tiptap/extension-floating-menu": "^3.0.0-next.5"
38
49
  },
39
50
  "peerDependencies": {
40
- "@tiptap/core": "^3.0.0-next.1",
41
- "@tiptap/pm": "^3.0.0-next.1",
42
- "vue": "^3.0.0"
51
+ "@tiptap/core": "^3.0.0-next.4",
52
+ "@tiptap/pm": "^3.0.0-next.4",
53
+ "vue": "^3.0.0",
54
+ "@floating-ui/dom": "^1.0.0"
43
55
  },
44
56
  "repository": {
45
57
  "type": "git",
@@ -48,6 +60,7 @@
48
60
  },
49
61
  "sideEffects": false,
50
62
  "scripts": {
51
- "build": "tsup"
63
+ "build": "tsup",
64
+ "lint": "prettier ./src/ --check && eslint --cache --quiet --no-error-on-unmatched-pattern ./src/"
52
65
  }
53
- }
66
+ }
package/src/Editor.ts CHANGED
@@ -1,14 +1,7 @@
1
1
  /* eslint-disable react-hooks/rules-of-hooks */
2
- import { Editor as CoreEditor, EditorOptions } from '@tiptap/core'
2
+ import { Editor as CoreEditor, EditorOptions, Storage } from '@tiptap/core'
3
3
  import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'
4
- import {
5
- AppContext,
6
- ComponentInternalInstance,
7
- ComponentPublicInstance,
8
- customRef,
9
- markRaw,
10
- Ref,
11
- } from 'vue'
4
+ import { AppContext, ComponentInternalInstance, ComponentPublicInstance, customRef, markRaw, Ref } from 'vue'
12
5
 
13
6
  function useDebouncedRef<T>(value: T) {
14
7
  return customRef<T>((track, trigger) => {
@@ -39,7 +32,7 @@ export type ContentComponent = ComponentInternalInstance & {
39
32
  export class Editor extends CoreEditor {
40
33
  private reactiveState: Ref<EditorState>
41
34
 
42
- private reactiveExtensionStorage: Ref<Record<string, any>>
35
+ private reactiveExtensionStorage: Ref<Storage>
43
36
 
44
37
  public contentComponent: ContentComponent | null = null
45
38
 
@@ -32,10 +32,11 @@ export const EditorContent = defineComponent({
32
32
 
33
33
  if (editor && editor.options.element && rootEl.value) {
34
34
  nextTick(() => {
35
- if (!rootEl.value || !editor.options.element.firstChild) {
35
+ if (!rootEl.value || !editor.options.element?.firstChild) {
36
36
  return
37
37
  }
38
38
 
39
+ // TODO using the new editor.mount method might allow us to remove this
39
40
  const element = unref(rootEl.value)
40
41
 
41
42
  rootEl.value.append(...editor.options.element.childNodes)
@@ -77,11 +78,10 @@ export const EditorContent = defineComponent({
77
78
  },
78
79
 
79
80
  render() {
80
- return h(
81
- 'div',
82
- {
83
- ref: (el: any) => { this.rootEl = el },
81
+ return h('div', {
82
+ ref: (el: any) => {
83
+ this.rootEl = el
84
84
  },
85
- )
85
+ })
86
86
  },
87
87
  })
@@ -0,0 +1,112 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import { MarkView, MarkViewProps, MarkViewRenderer, MarkViewRendererOptions } from '@tiptap/core'
3
+ import { Component, defineComponent, h, PropType } from 'vue'
4
+
5
+ import { Editor } from './Editor.js'
6
+ import { VueRenderer } from './VueRenderer.js'
7
+
8
+ export interface VueMarkViewRendererOptions extends MarkViewRendererOptions {
9
+ as?: string
10
+ className?: string
11
+ attrs?: { [key: string]: string }
12
+ }
13
+
14
+ export const markViewProps = {
15
+ editor: {
16
+ type: Object as PropType<MarkViewProps['editor']>,
17
+ required: true as const,
18
+ },
19
+ mark: {
20
+ type: Object as PropType<MarkViewProps['mark']>,
21
+ required: true as const,
22
+ },
23
+ extension: {
24
+ type: Object as PropType<MarkViewProps['extension']>,
25
+ required: true as const,
26
+ },
27
+ inline: {
28
+ type: Boolean as PropType<MarkViewProps['inline']>,
29
+ required: true as const,
30
+ },
31
+ view: {
32
+ type: Object as PropType<MarkViewProps['view']>,
33
+ required: true as const,
34
+ },
35
+ }
36
+
37
+ export const MarkViewContent = defineComponent({
38
+ name: 'MarkViewContent',
39
+
40
+ props: {
41
+ as: {
42
+ type: String,
43
+ default: 'span',
44
+ },
45
+ },
46
+
47
+ render() {
48
+ return h(this.as, {
49
+ style: {
50
+ whiteSpace: 'inherit',
51
+ },
52
+ 'data-mark-view-content': '',
53
+ })
54
+ },
55
+ })
56
+
57
+ export class VueMarkView extends MarkView<Component, VueMarkViewRendererOptions> {
58
+ renderer: VueRenderer
59
+
60
+ constructor(component: Component, props: MarkViewProps, options?: Partial<VueMarkViewRendererOptions>) {
61
+ super(component, props, options)
62
+
63
+ // Create extended component with provide
64
+ const extendedComponent = defineComponent({
65
+ extends: { ...component },
66
+ props: Object.keys(props),
67
+ template: (this.component as any).template,
68
+ setup: reactiveProps => {
69
+ return (component as any).setup?.(reactiveProps, {
70
+ expose: () => undefined,
71
+ })
72
+ },
73
+ // Add support for scoped styles
74
+ __scopeId: (component as any).__scopeId,
75
+ __cssModules: (component as any).__cssModules,
76
+ __name: (component as any).__name,
77
+ __file: (component as any).__file,
78
+ })
79
+ this.renderer = new VueRenderer(extendedComponent, {
80
+ editor: this.editor,
81
+ props,
82
+ })
83
+ }
84
+
85
+ get dom() {
86
+ return this.renderer.element as HTMLElement
87
+ }
88
+
89
+ get contentDOM() {
90
+ return this.dom.querySelector('[data-mark-view-content]') as HTMLElement | null
91
+ }
92
+
93
+ destroy() {
94
+ this.renderer.destroy()
95
+ }
96
+ }
97
+
98
+ export function VueMarkViewRenderer(
99
+ component: Component,
100
+ options: Partial<VueMarkViewRendererOptions> = {},
101
+ ): MarkViewRenderer {
102
+ return props => {
103
+ // try to get the parent component
104
+ // this is important for vue devtools to show the component hierarchy correctly
105
+ // maybe it’s `undefined` because <editor-content> isn’t rendered yet
106
+ if (!(props.editor as Editor).contentComponent) {
107
+ return {} as unknown as MarkView<any, any>
108
+ }
109
+
110
+ return new VueMarkView(component, props, options)
111
+ }
112
+ }
@@ -1,16 +1,8 @@
1
1
  /* eslint-disable no-underscore-dangle */
2
- import {
3
- DecorationWithType,
4
- NodeView,
5
- NodeViewProps,
6
- NodeViewRenderer,
7
- NodeViewRendererOptions,
8
- } from '@tiptap/core'
2
+ import { DecorationWithType, NodeView, NodeViewProps, NodeViewRenderer, NodeViewRendererOptions } from '@tiptap/core'
9
3
  import { Node as ProseMirrorNode } from '@tiptap/pm/model'
10
4
  import { Decoration, DecorationSource, NodeView as ProseMirrorNodeView } from '@tiptap/pm/view'
11
- import {
12
- Component, defineComponent, PropType, provide, Ref, ref,
13
- } from 'vue'
5
+ import { Component, defineComponent, PropType, provide, Ref, ref } from 'vue'
14
6
 
15
7
  import { Editor } from './Editor.js'
16
8
  import { VueRenderer } from './VueRenderer.js'
@@ -48,20 +40,32 @@ export const nodeViewProps = {
48
40
  type: Function as PropType<NodeViewProps['deleteNode']>,
49
41
  required: true as const,
50
42
  },
43
+ view: {
44
+ type: Object as PropType<NodeViewProps['view']>,
45
+ required: true as const,
46
+ },
47
+ innerDecorations: {
48
+ type: Object as PropType<NodeViewProps['innerDecorations']>,
49
+ required: true as const,
50
+ },
51
+ HTMLAttributes: {
52
+ type: Object as PropType<NodeViewProps['HTMLAttributes']>,
53
+ required: true as const,
54
+ },
51
55
  }
52
56
 
53
57
  export interface VueNodeViewRendererOptions extends NodeViewRendererOptions {
54
58
  update:
55
59
  | ((props: {
56
- oldNode: ProseMirrorNode;
57
- oldDecorations: readonly Decoration[];
58
- oldInnerDecorations: DecorationSource;
59
- newNode: ProseMirrorNode;
60
- newDecorations: readonly Decoration[];
61
- innerDecorations: DecorationSource;
62
- updateProps: () => void;
60
+ oldNode: ProseMirrorNode
61
+ oldDecorations: readonly Decoration[]
62
+ oldInnerDecorations: DecorationSource
63
+ newNode: ProseMirrorNode
64
+ newDecorations: readonly Decoration[]
65
+ innerDecorations: DecorationSource
66
+ updateProps: () => void
63
67
  }) => boolean)
64
- | null;
68
+ | null
65
69
  }
66
70
 
67
71
  class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions> {
@@ -181,11 +185,7 @@ class VueNodeView extends NodeView<Component, Editor, VueNodeViewRendererOptions
181
185
  * On update, update the React component.
182
186
  * To prevent unnecessary updates, the `update` option can be used.
183
187
  */
184
- update(
185
- node: ProseMirrorNode,
186
- decorations: readonly Decoration[],
187
- innerDecorations: DecorationSource,
188
- ): boolean {
188
+ update(node: ProseMirrorNode, decorations: readonly Decoration[], innerDecorations: DecorationSource): boolean {
189
189
  const rerenderComponent = (props?: Record<string, any>) => {
190
190
  this.decorationClasses.value = this.getDecorationClasses()
191
191
  this.renderer.updateProps(props)
@@ -282,9 +282,8 @@ export function VueNodeViewRenderer(
282
282
  return {} as unknown as ProseMirrorNodeView
283
283
  }
284
284
  // check for class-component and normalize if neccessary
285
- const normalizedComponent = typeof component === 'function' && '__vccOpts' in component
286
- ? (component.__vccOpts as Component)
287
- : component
285
+ const normalizedComponent =
286
+ typeof component === 'function' && '__vccOpts' in component ? (component.__vccOpts as Component) : component
288
287
 
289
288
  return new VueNodeView(normalizedComponent, props, options)
290
289
  }
@@ -1,21 +1,19 @@
1
1
  import { Editor } from '@tiptap/core'
2
- import {
3
- Component, DefineComponent, h, markRaw, reactive, render,
4
- } from 'vue'
2
+ import { Component, DefineComponent, h, markRaw, reactive, render } from 'vue'
5
3
 
6
4
  import { Editor as ExtendedEditor } from './Editor.js'
7
5
 
8
6
  export interface VueRendererOptions {
9
- editor: Editor;
10
- props?: Record<string, any>;
7
+ editor: Editor
8
+ props?: Record<string, any>
11
9
  }
12
10
 
13
- type ExtendedVNode = ReturnType<typeof h> | null;
11
+ type ExtendedVNode = ReturnType<typeof h> | null
14
12
 
15
13
  interface RenderedComponent {
16
- vNode: ExtendedVNode;
17
- destroy: () => void;
18
- el: Element | null;
14
+ vNode: ExtendedVNode
15
+ destroy: () => void
16
+ el: Element | null
19
17
  }
20
18
 
21
19
  /**
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'
@@ -1,13 +1,5 @@
1
1
  import { BubbleMenuPlugin, BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu'
2
- import {
3
- defineComponent,
4
- h,
5
- onBeforeUnmount,
6
- onMounted,
7
- PropType,
8
- ref,
9
- Teleport,
10
- } from 'vue'
2
+ import { defineComponent, h, onBeforeUnmount, onMounted, PropType, ref, Teleport } from 'vue'
11
3
 
12
4
  export const BubbleMenu = defineComponent({
13
5
  name: 'BubbleMenu',
@@ -48,14 +40,7 @@ export const BubbleMenu = defineComponent({
48
40
  const root = ref<HTMLElement | null>(null)
49
41
 
50
42
  onMounted(() => {
51
- const {
52
- editor,
53
- options,
54
- pluginKey,
55
- resizeDelay,
56
- shouldShow,
57
- updateDelay,
58
- } = props
43
+ const { editor, options, pluginKey, resizeDelay, shouldShow, updateDelay } = props
59
44
 
60
45
  if (!root.value) {
61
46
  return
@@ -67,15 +52,17 @@ export const BubbleMenu = defineComponent({
67
52
  // remove the element from the DOM
68
53
  root.value.remove()
69
54
 
70
- editor.registerPlugin(BubbleMenuPlugin({
71
- editor,
72
- element: root.value as HTMLElement,
73
- options,
74
- pluginKey,
75
- resizeDelay,
76
- shouldShow,
77
- updateDelay,
78
- }))
55
+ editor.registerPlugin(
56
+ BubbleMenuPlugin({
57
+ editor,
58
+ element: root.value as HTMLElement,
59
+ options,
60
+ pluginKey,
61
+ resizeDelay,
62
+ shouldShow,
63
+ updateDelay,
64
+ }),
65
+ )
79
66
  })
80
67
 
81
68
  onBeforeUnmount(() => {
@@ -1,14 +1,5 @@
1
- import type { BubbleMenuPluginProps } from '@tiptap/extension-bubble-menu'
2
1
  import { FloatingMenuPlugin, FloatingMenuPluginProps } from '@tiptap/extension-floating-menu'
3
- import {
4
- defineComponent,
5
- h,
6
- onBeforeUnmount,
7
- onMounted,
8
- PropType,
9
- ref,
10
- Teleport,
11
- } from 'vue'
2
+ import { defineComponent, h, onBeforeUnmount, onMounted, PropType, ref, Teleport } from 'vue'
12
3
 
13
4
  export const FloatingMenu = defineComponent({
14
5
  name: 'FloatingMenu',
@@ -27,7 +18,7 @@ export const FloatingMenu = defineComponent({
27
18
  },
28
19
 
29
20
  options: {
30
- type: Object as PropType<BubbleMenuPluginProps['options']>,
21
+ type: Object as PropType<FloatingMenuPluginProps['options']>,
31
22
  default: () => ({}),
32
23
  },
33
24
 
@@ -41,12 +32,7 @@ export const FloatingMenu = defineComponent({
41
32
  const root = ref<HTMLElement | null>(null)
42
33
 
43
34
  onMounted(() => {
44
- const {
45
- pluginKey,
46
- editor,
47
- options,
48
- shouldShow,
49
- } = props
35
+ const { pluginKey, editor, options, shouldShow } = props
50
36
 
51
37
  if (!root.value) {
52
38
  return
@@ -58,13 +44,15 @@ export const FloatingMenu = defineComponent({
58
44
  // remove the element from the DOM
59
45
  root.value.remove()
60
46
 
61
- editor.registerPlugin(FloatingMenuPlugin({
62
- pluginKey,
63
- editor,
64
- element: root.value as HTMLElement,
65
- options,
66
- shouldShow,
67
- }))
47
+ editor.registerPlugin(
48
+ FloatingMenuPlugin({
49
+ pluginKey,
50
+ editor,
51
+ element: root.value as HTMLElement,
52
+ options,
53
+ shouldShow,
54
+ }),
55
+ )
68
56
  })
69
57
 
70
58
  onBeforeUnmount(() => {
@@ -0,0 +1,2 @@
1
+ export * from './BubbleMenu.js'
2
+ export * from './FloatingMenu.js'