@tiptap/vue-3
Advanced tools
Comparing version 2.5.0-beta.2 to 2.5.0-beta.3
import { BubbleMenuPlugin } from '@tiptap/extension-bubble-menu'; | ||
import { defineComponent, ref, onMounted, onBeforeUnmount, h, reactive, markRaw, customRef, getCurrentInstance, watchEffect, nextTick, unref, Teleport, shallowRef, provide } from 'vue'; | ||
import { defineComponent, ref, onMounted, onBeforeUnmount, h, markRaw, customRef, getCurrentInstance, watchEffect, nextTick, unref, shallowRef, reactive, render, provide } from 'vue'; | ||
import { Editor as Editor$1, NodeView } from '@tiptap/core'; | ||
@@ -75,4 +75,4 @@ export * from '@tiptap/core'; | ||
super(options); | ||
this.vueRenderers = reactive(new Map()); | ||
this.contentComponent = null; | ||
this.appContext = null; | ||
this.reactiveState = useDebouncedRef(this.view.state); | ||
@@ -130,2 +130,12 @@ this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage); | ||
editor.contentComponent = instance.ctx._; | ||
if (instance) { | ||
editor.appContext = { | ||
...instance.appContext, | ||
provides: { | ||
// @ts-ignore | ||
...instance.provides, | ||
...instance.appContext.provides, | ||
}, | ||
}; | ||
} | ||
editor.setOptions({ | ||
@@ -150,2 +160,3 @@ element, | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
if (!editor.options.element.firstChild) { | ||
@@ -163,18 +174,5 @@ return; | ||
render() { | ||
const vueRenderers = []; | ||
if (this.editor) { | ||
this.editor.vueRenderers.forEach(vueRenderer => { | ||
const node = h(Teleport, { | ||
to: vueRenderer.teleportElement, | ||
key: vueRenderer.id, | ||
}, h(vueRenderer.component, { | ||
ref: vueRenderer.id, | ||
...vueRenderer.props, | ||
})); | ||
vueRenderers.push(node); | ||
}); | ||
} | ||
return h('div', { | ||
ref: (el) => { this.rootEl = el; }, | ||
}, ...vueRenderers); | ||
}); | ||
}, | ||
@@ -287,18 +285,23 @@ }); | ||
this.component = markRaw(component); | ||
this.teleportElement = document.createElement('div'); | ||
this.element = this.teleportElement; | ||
this.el = document.createElement('div'); | ||
this.props = reactive(props); | ||
this.editor.vueRenderers.set(this.id, this); | ||
if (this.editor.contentComponent) { | ||
this.editor.contentComponent.update(); | ||
if (this.teleportElement.children.length !== 1) { | ||
throw Error('VueRenderer doesn’t support multiple child elements.'); | ||
this.renderedComponent = this.renderComponent(); | ||
} | ||
get element() { | ||
return this.renderedComponent.el; | ||
} | ||
renderComponent() { | ||
let vNode = h(this.component, this.props); | ||
if (typeof document !== 'undefined' && this.el) { | ||
render(vNode, this.el); | ||
} | ||
const destroy = () => { | ||
if (this.el) { | ||
render(null, this.el); | ||
} | ||
this.element = this.teleportElement.firstElementChild; | ||
} | ||
this.el = null; | ||
vNode = null; | ||
}; | ||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }; | ||
} | ||
get ref() { | ||
var _a; | ||
return (_a = this.editor.contentComponent) === null || _a === void 0 ? void 0 : _a.refs[this.id]; | ||
} | ||
updateProps(props = {}) { | ||
@@ -310,5 +313,6 @@ Object | ||
}); | ||
this.renderComponent(); | ||
} | ||
destroy() { | ||
this.editor.vueRenderers.delete(this.id); | ||
this.renderedComponent.destroy(); | ||
} | ||
@@ -399,3 +403,3 @@ } | ||
get dom() { | ||
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
throw Error('Please use the NodeViewWrapper component for your node view.'); | ||
@@ -445,3 +449,5 @@ } | ||
}); | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
} | ||
} | ||
@@ -452,3 +458,5 @@ deselectNode() { | ||
}); | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
} | ||
} | ||
@@ -455,0 +463,0 @@ getDecorationClasses() { |
@@ -75,4 +75,4 @@ (function (global, factory) { | ||
super(options); | ||
this.vueRenderers = vue.reactive(new Map()); | ||
this.contentComponent = null; | ||
this.appContext = null; | ||
this.reactiveState = useDebouncedRef(this.view.state); | ||
@@ -130,2 +130,12 @@ this.reactiveExtensionStorage = useDebouncedRef(this.extensionStorage); | ||
editor.contentComponent = instance.ctx._; | ||
if (instance) { | ||
editor.appContext = { | ||
...instance.appContext, | ||
provides: { | ||
// @ts-ignore | ||
...instance.provides, | ||
...instance.appContext.provides, | ||
}, | ||
}; | ||
} | ||
editor.setOptions({ | ||
@@ -150,2 +160,3 @@ element, | ||
editor.contentComponent = null; | ||
editor.appContext = null; | ||
if (!editor.options.element.firstChild) { | ||
@@ -163,18 +174,5 @@ return; | ||
render() { | ||
const vueRenderers = []; | ||
if (this.editor) { | ||
this.editor.vueRenderers.forEach(vueRenderer => { | ||
const node = vue.h(vue.Teleport, { | ||
to: vueRenderer.teleportElement, | ||
key: vueRenderer.id, | ||
}, vue.h(vueRenderer.component, { | ||
ref: vueRenderer.id, | ||
...vueRenderer.props, | ||
})); | ||
vueRenderers.push(node); | ||
}); | ||
} | ||
return vue.h('div', { | ||
ref: (el) => { this.rootEl = el; }, | ||
}, ...vueRenderers); | ||
}); | ||
}, | ||
@@ -287,18 +285,23 @@ }); | ||
this.component = vue.markRaw(component); | ||
this.teleportElement = document.createElement('div'); | ||
this.element = this.teleportElement; | ||
this.el = document.createElement('div'); | ||
this.props = vue.reactive(props); | ||
this.editor.vueRenderers.set(this.id, this); | ||
if (this.editor.contentComponent) { | ||
this.editor.contentComponent.update(); | ||
if (this.teleportElement.children.length !== 1) { | ||
throw Error('VueRenderer doesn’t support multiple child elements.'); | ||
this.renderedComponent = this.renderComponent(); | ||
} | ||
get element() { | ||
return this.renderedComponent.el; | ||
} | ||
renderComponent() { | ||
let vNode = vue.h(this.component, this.props); | ||
if (typeof document !== 'undefined' && this.el) { | ||
vue.render(vNode, this.el); | ||
} | ||
const destroy = () => { | ||
if (this.el) { | ||
vue.render(null, this.el); | ||
} | ||
this.element = this.teleportElement.firstElementChild; | ||
} | ||
this.el = null; | ||
vNode = null; | ||
}; | ||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null }; | ||
} | ||
get ref() { | ||
var _a; | ||
return (_a = this.editor.contentComponent) === null || _a === void 0 ? void 0 : _a.refs[this.id]; | ||
} | ||
updateProps(props = {}) { | ||
@@ -310,5 +313,6 @@ Object | ||
}); | ||
this.renderComponent(); | ||
} | ||
destroy() { | ||
this.editor.vueRenderers.delete(this.id); | ||
this.renderedComponent.destroy(); | ||
} | ||
@@ -399,3 +403,3 @@ } | ||
get dom() { | ||
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
throw Error('Please use the NodeViewWrapper component for your node view.'); | ||
@@ -445,3 +449,5 @@ } | ||
}); | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add('ProseMirror-selectednode'); | ||
} | ||
} | ||
@@ -452,3 +458,5 @@ deselectNode() { | ||
}); | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove('ProseMirror-selectednode'); | ||
} | ||
} | ||
@@ -489,3 +497,3 @@ getDecorationClasses() { | ||
Object.keys(core).forEach(function (k) { | ||
if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, { | ||
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { | ||
enumerable: true, | ||
@@ -496,5 +504,3 @@ get: function () { return core[k]; } | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
})); | ||
//# sourceMappingURL=index.umd.js.map |
@@ -0,0 +0,0 @@ import { PropType } from 'vue'; |
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core'; | ||
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state'; | ||
import { ComponentInternalInstance, ComponentPublicInstance } from 'vue'; | ||
import { VueRenderer } from './VueRenderer.js'; | ||
export declare type ContentComponent = ComponentInternalInstance & { | ||
import { AppContext, ComponentInternalInstance, ComponentPublicInstance } from 'vue'; | ||
export type ContentComponent = ComponentInternalInstance & { | ||
ctx: ComponentPublicInstance; | ||
@@ -11,4 +10,4 @@ }; | ||
private reactiveExtensionStorage; | ||
vueRenderers: Map<string, VueRenderer>; | ||
contentComponent: ContentComponent | null; | ||
appContext: AppContext | null; | ||
constructor(options?: Partial<EditorOptions>); | ||
@@ -15,0 +14,0 @@ get state(): EditorState; |
@@ -1,4 +0,4 @@ | ||
import { DefineComponent, PropType, Ref } from 'vue'; | ||
import { PropType, Ref } from 'vue'; | ||
import { Editor } from './Editor.js'; | ||
export declare const EditorContent: DefineComponent<{ | ||
export declare const EditorContent: import("vue").DefineComponent<{ | ||
editor: { | ||
@@ -5,0 +5,0 @@ default: null; |
@@ -0,0 +0,0 @@ import { PropType } from 'vue'; |
@@ -0,0 +0,0 @@ export * from './BubbleMenu.js'; |
@@ -0,0 +0,0 @@ export declare const NodeViewContent: import("vue").DefineComponent<{ |
@@ -0,0 +0,0 @@ export declare const NodeViewWrapper: import("vue").DefineComponent<{ |
import { EditorOptions } from '@tiptap/core'; | ||
import { Editor } from './Editor.js'; | ||
export declare const useEditor: (options?: Partial<EditorOptions>) => import("vue").ShallowRef<Editor | undefined>; |
@@ -0,0 +0,0 @@ import { DecorationWithType, NodeViewRenderer, NodeViewRendererOptions } from '@tiptap/core'; |
import { Editor } from '@tiptap/core'; | ||
import { Component } from 'vue'; | ||
import { Component, h } from 'vue'; | ||
import { Editor as ExtendedEditor } from './Editor.js'; | ||
@@ -8,2 +8,8 @@ export interface VueRendererOptions { | ||
} | ||
type ExtendedVNode = ReturnType<typeof h> | null; | ||
interface RenderedComponent { | ||
vNode: ExtendedVNode; | ||
destroy: () => void; | ||
el: Element | null; | ||
} | ||
/** | ||
@@ -14,11 +20,19 @@ * This class is used to render Vue components inside the editor. | ||
id: string; | ||
renderedComponent: RenderedComponent; | ||
editor: ExtendedEditor; | ||
component: Component; | ||
teleportElement: Element; | ||
element: Element; | ||
el: Element | null; | ||
props: Record<string, any>; | ||
constructor(component: Component, { props, editor }: VueRendererOptions); | ||
get ref(): any; | ||
get element(): Element | null; | ||
renderComponent(): { | ||
vNode: import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, { | ||
[key: string]: any; | ||
}>; | ||
destroy: () => void; | ||
el: Element | null; | ||
}; | ||
updateProps(props?: Record<string, any>): void; | ||
destroy(): void; | ||
} | ||
export {}; |
{ | ||
"name": "@tiptap/vue-3", | ||
"description": "Vue components for tiptap", | ||
"version": "2.5.0-beta.2", | ||
"version": "2.5.0-beta.3", | ||
"homepage": "https://tiptap.dev", | ||
@@ -32,8 +32,8 @@ "keywords": [ | ||
"dependencies": { | ||
"@tiptap/extension-bubble-menu": "^2.5.0-beta.2", | ||
"@tiptap/extension-floating-menu": "^2.5.0-beta.2" | ||
"@tiptap/extension-bubble-menu": "^2.5.0-beta.3", | ||
"@tiptap/extension-floating-menu": "^2.5.0-beta.3" | ||
}, | ||
"devDependencies": { | ||
"@tiptap/core": "^2.5.0-beta.2", | ||
"@tiptap/pm": "^2.5.0-beta.2", | ||
"@tiptap/core": "^2.5.0-beta.3", | ||
"@tiptap/pm": "^2.5.0-beta.3", | ||
"vue": "^3.0.0" | ||
@@ -40,0 +40,0 @@ }, |
import { Editor as CoreEditor, EditorOptions } from '@tiptap/core' | ||
import { EditorState, Plugin, PluginKey } from '@tiptap/pm/state' | ||
import { | ||
AppContext, | ||
ComponentInternalInstance, | ||
@@ -8,8 +9,5 @@ ComponentPublicInstance, | ||
markRaw, | ||
reactive, | ||
Ref, | ||
} from 'vue' | ||
import { VueRenderer } from './VueRenderer.js' | ||
function useDebouncedRef<T>(value: T) { | ||
@@ -46,6 +44,6 @@ return customRef<T>((track, trigger) => { | ||
public vueRenderers = reactive<Map<string, VueRenderer>>(new Map()) | ||
public contentComponent: ContentComponent | null = null | ||
public appContext: AppContext | null = null | ||
constructor(options: Partial<EditorOptions> = {}) { | ||
@@ -52,0 +50,0 @@ super(options) |
import { | ||
DefineComponent, | ||
defineComponent, | ||
@@ -11,3 +10,2 @@ getCurrentInstance, | ||
ref, | ||
Teleport, | ||
unref, | ||
@@ -49,2 +47,13 @@ watchEffect, | ||
if (instance) { | ||
editor.appContext = { | ||
...instance.appContext, | ||
provides: { | ||
// @ts-ignore | ||
...instance.provides, | ||
...instance.appContext.provides, | ||
}, | ||
} | ||
} | ||
editor.setOptions({ | ||
@@ -74,2 +83,3 @@ element, | ||
editor.contentComponent = null | ||
editor.appContext = null | ||
@@ -93,25 +103,2 @@ if (!editor.options.element.firstChild) { | ||
render() { | ||
const vueRenderers: any[] = [] | ||
if (this.editor) { | ||
this.editor.vueRenderers.forEach(vueRenderer => { | ||
const node = h( | ||
Teleport, | ||
{ | ||
to: vueRenderer.teleportElement, | ||
key: vueRenderer.id, | ||
}, | ||
h( | ||
vueRenderer.component as DefineComponent, | ||
{ | ||
ref: vueRenderer.id, | ||
...vueRenderer.props, | ||
}, | ||
), | ||
) | ||
vueRenderers.push(node) | ||
}) | ||
} | ||
return h( | ||
@@ -122,5 +109,4 @@ 'div', | ||
}, | ||
...vueRenderers, | ||
) | ||
}, | ||
}) |
@@ -127,3 +127,3 @@ import { | ||
get dom() { | ||
if (!this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
if (!this.renderer.element || !this.renderer.element.hasAttribute('data-node-view-wrapper')) { | ||
throw Error('Please use the NodeViewWrapper component for your node view.') | ||
@@ -187,3 +187,5 @@ } | ||
}) | ||
this.renderer.element.classList.add('ProseMirror-selectednode') | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.add('ProseMirror-selectednode') | ||
} | ||
} | ||
@@ -195,3 +197,5 @@ | ||
}) | ||
this.renderer.element.classList.remove('ProseMirror-selectednode') | ||
if (this.renderer.element) { | ||
this.renderer.element.classList.remove('ProseMirror-selectednode') | ||
} | ||
} | ||
@@ -198,0 +202,0 @@ |
import { Editor } from '@tiptap/core' | ||
import { Component, markRaw, reactive } from 'vue' | ||
import { | ||
Component, DefineComponent, h, markRaw, reactive, render, | ||
} from 'vue' | ||
@@ -11,2 +13,10 @@ import { Editor as ExtendedEditor } from './Editor.js' | ||
type ExtendedVNode = ReturnType<typeof h> | null | ||
interface RenderedComponent { | ||
vNode: ExtendedVNode | ||
destroy: () => void | ||
el: Element | null | ||
} | ||
/** | ||
@@ -18,2 +28,4 @@ * This class is used to render Vue components inside the editor. | ||
renderedComponent!: RenderedComponent | ||
editor: ExtendedEditor | ||
@@ -23,6 +35,4 @@ | ||
teleportElement: Element | ||
el: Element | null | ||
element: Element | ||
props: Record<string, any> | ||
@@ -34,23 +44,27 @@ | ||
this.component = markRaw(component) | ||
this.teleportElement = document.createElement('div') | ||
this.element = this.teleportElement | ||
this.el = document.createElement('div') | ||
this.props = reactive(props) | ||
this.editor.vueRenderers.set(this.id, this) | ||
this.renderedComponent = this.renderComponent() | ||
} | ||
if (this.editor.contentComponent) { | ||
this.editor.contentComponent.update() | ||
get element(): Element | null { | ||
return this.renderedComponent.el | ||
} | ||
if (this.teleportElement.children.length !== 1) { | ||
throw Error('VueRenderer doesn’t support multiple child elements.') | ||
} | ||
renderComponent() { | ||
let vNode: ExtendedVNode = h(this.component as DefineComponent, this.props) | ||
this.element = this.teleportElement.firstElementChild as Element | ||
if (typeof document !== 'undefined' && this.el) { render(vNode, this.el) } | ||
const destroy = () => { | ||
if (this.el) { render(null, this.el) } | ||
this.el = null | ||
vNode = null | ||
} | ||
} | ||
get ref(): any { | ||
return this.editor.contentComponent?.refs[this.id] | ||
return { vNode, destroy, el: this.el ? this.el.firstElementChild : null } | ||
} | ||
updateProps(props: Record<string, any> = {}): void { | ||
Object | ||
@@ -61,7 +75,8 @@ .entries(props) | ||
}) | ||
this.renderComponent() | ||
} | ||
destroy(): void { | ||
this.editor.vueRenderers.delete(this.id) | ||
this.renderedComponent.destroy() | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
312309
195
6235