diff --git a/docs/src/demos/Examples/Drawing/Component.vue b/docs/src/demos/Examples/Drawing/Component.vue index 9fed19886..3d426471e 100644 --- a/docs/src/demos/Examples/Drawing/Component.vue +++ b/docs/src/demos/Examples/Drawing/Component.vue @@ -31,6 +31,8 @@ import * as d3 from 'd3' import simplify from 'simplify-js' export default { + name: 'Paper', + props: { updateAttributes: { type: Function, diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 7a1fe8f7e..afda22592 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -252,9 +252,7 @@ export class Editor extends EventEmitter { this.view.updateState(newState) - this.view.setProps({ - nodeViews: this.extensionManager.nodeViews, - }) + this.createNodeViews() // Let’s store the editor instance in the DOM element. // So we’ll have access to it for tests. @@ -262,6 +260,15 @@ export class Editor extends EventEmitter { dom.editor = this.proxy } + /** + * Creates all node views. + */ + public createNodeViews() { + this.view.setProps({ + nodeViews: this.extensionManager.nodeViews, + }) + } + /** * Creates a ProseMirror document. */ diff --git a/packages/vue/src/VueRenderer.ts b/packages/vue/src/VueRenderer.ts index 3212f62ca..f5cd34bac 100644 --- a/packages/vue/src/VueRenderer.ts +++ b/packages/vue/src/VueRenderer.ts @@ -5,6 +5,12 @@ import { Node as ProseMirrorNode } from 'prosemirror-model' import Vue from 'vue' import { VueConstructor } from 'vue/types/umd' +function getComponentFromElement(element: HTMLElement): Vue { + // @ts-ignore + // eslint-disable-next-line + return element.__vue__ +} + interface VueRendererOptions { stopEvent: ((event: Event) => boolean) | null, update: ((node: ProseMirrorNode, decorations: Decoration[]) => boolean) | null, @@ -132,7 +138,7 @@ class VueNodeView implements NodeView { }, }) - const props = { + const propsData = { NodeViewWrapper, NodeViewContent, editor: this.editor, @@ -144,10 +150,13 @@ class VueNodeView implements NodeView { updateAttributes: (attributes = {}) => this.updateAttributes(attributes), } + const parent = this.editor.view.dom.parentElement + ? getComponentFromElement(this.editor.view.dom.parentElement) + : undefined + this.vm = new Component({ - // TODO: get parent component - // parent: this.parent, - propsData: props, + parent, + propsData, }).$mount() } @@ -258,11 +267,17 @@ class VueNodeView implements NodeView { return } + // prevents `Avoid mutating a prop directly` error message + const originalSilent = Vue.config.silent + Vue.config.silent = true + Object .entries(data) .forEach(([key, value]) => { this.vm.$props[key] = value }) + + Vue.config.silent = originalSilent } updateAttributes(attributes: {}) { @@ -295,5 +310,18 @@ class VueNodeView implements NodeView { } export default function VueRenderer(component: Vue | VueConstructor, options?: Partial) { - return (props: NodeViewRendererProps) => new VueNodeView(component, props, options) as NodeView + return (props: NodeViewRendererProps) => { + // try to get the parent component + // this is important for vue devtools to show the component hierarchy correctly + // maybe it’s `undefined` because isn’t rendered yet + const parent = props.editor.view.dom.parentElement + ? getComponentFromElement(props.editor.view.dom.parentElement) + : undefined + + if (!parent) { + return undefined + } + + return new VueNodeView(component, props, options) as NodeView + } } diff --git a/packages/vue/src/components/EditorContent.ts b/packages/vue/src/components/EditorContent.ts index 2f74d5ffa..1bfa76ab6 100644 --- a/packages/vue/src/components/EditorContent.ts +++ b/packages/vue/src/components/EditorContent.ts @@ -17,7 +17,7 @@ export default Vue.extend({ if (editor && editor.options.element) { this.$nextTick(() => { this.$el.appendChild(editor.options.element.firstChild) - // editor.setParentComponent(this) + editor.createNodeViews() }) } },