diff --git a/docs/src/demos/Examples/NodeView/Component.vue b/docs/src/demos/Examples/NodeView/Component.vue index dcc31796..07385fdb 100644 --- a/docs/src/demos/Examples/NodeView/Component.vue +++ b/docs/src/demos/Examples/NodeView/Component.vue @@ -4,10 +4,21 @@ - +
+ attrs {{ node.attrs }} +
--> - + +
+ + hey {{ node.attrs.checked }} + +
+ + @@ -19,19 +30,44 @@ export default { required: true, }, + node: { + type: Object, + required: true, + }, + inner: { type: [Object, Function], required: true, }, + + updateAttrs: { + type: Function, + required: true, + }, }, data() { return { - foo: 'foo', + random: 'foo', } }, + methods: { + toggleChecked() { + this.editor.commands.focus() + this.updateAttrs({ + checked: !this.node.attrs.checked, + }) + }, + }, + mounted() { + // console.log(this.node) + + console.log('mounted') + // setInterval(() => { + // this.random = `foo${Math.random()}` + // }, 1000) // console.log(this) }, } diff --git a/docs/src/demos/Examples/NodeView/Test.ts b/docs/src/demos/Examples/NodeView/Test.ts index 33c790ee..981386cf 100644 --- a/docs/src/demos/Examples/NodeView/Test.ts +++ b/docs/src/demos/Examples/NodeView/Test.ts @@ -1,4 +1,4 @@ -import { Node } from '@tiptap/core' +import { Node, mergeAttributes } from '@tiptap/core' import { VueRenderer } from '@tiptap/vue' import Component from './Component.vue' @@ -13,6 +13,16 @@ export default Node.create({ selectable: false, + // atom: true, + + addAttributes() { + return { + checked: { + default: false, + }, + } + }, + parseHTML() { return [ { @@ -21,8 +31,8 @@ export default Node.create({ ] }, - renderHTML() { - return ['div', { 'data-type': 'test' }, 0] + renderHTML({ HTMLAttributes }) { + return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'test' }), 0] }, addNodeView() { diff --git a/packages/vue/src/VueRenderer.ts b/packages/vue/src/VueRenderer.ts index 46053db7..40ec5394 100644 --- a/packages/vue/src/VueRenderer.ts +++ b/packages/vue/src/VueRenderer.ts @@ -1,5 +1,5 @@ import { Editor, Node, NodeViewRendererProps } from '@tiptap/core' -import { NodeView } from 'prosemirror-view' +import { Decoration, NodeView } from 'prosemirror-view' import { Node as ProseMirrorNode, @@ -20,18 +20,17 @@ class VueNodeView implements NodeView { node!: ProseMirrorNode + decorations!: Decoration[] + id!: string - constructor(component: Vue | VueConstructor, props: NodeViewRendererProps) { - // eslint-disable-next-line - const { node, editor, getPos } = props - // eslint-disable-next-line - const { view } = editor + getPos!: any + constructor(component: Vue | VueConstructor, props: NodeViewRendererProps) { this.editor = props.editor this.extension = props.extension this.node = props.node - + this.getPos = props.getPos this.mount(component) } @@ -52,11 +51,13 @@ class VueNodeView implements NodeView { render(createElement, context) { return createElement( context.props.as, { + // this.as, { style: { whiteSpace: 'pre-wrap', }, attrs: { id, + // contenteditable: true, }, }, ) @@ -74,6 +75,8 @@ class VueNodeView implements NodeView { const props = { editor: this.editor, inner: Inner, + node: this.node, + updateAttrs: (attrs: {}) => this.updateAttrs(attrs), } this.vm = new Component({ @@ -95,6 +98,8 @@ class VueNodeView implements NodeView { } stopEvent(event: Event): boolean { + // console.log(event.type) + const isDraggable = this.node.type.spec.draggable const isCopy = event.type === 'copy' const isPaste = event.type === 'paste' @@ -108,6 +113,66 @@ class VueNodeView implements NodeView { return true } + ignoreMutation(mutation: MutationRecord | { type: 'selection'; target: Element }) { + // return false + // if (mutation.type === 'selection') { + // console.log({ mutation }) + // return true + // } + // return true + // console.log({ mutation }) + + if (!this.contentDOM) { + return true + } + + return !this.contentDOM.contains(mutation.target) + } + + update(node: ProseMirrorNode, decorations: Decoration[]) { + if (node.type !== this.node.type) { + return false + } + + if (node === this.node && this.decorations === decorations) { + return true + } + + this.node = node + this.decorations = decorations + + this.updateComponentProps() + + return true + } + + updateComponentProps() { + this.vm.$props.node = this.node + this.vm.$props.decorations = this.decorations + } + + updateAttrs(attrs: {}) { + if (!this.editor.view.editable) { + return + } + + const { state } = this.editor.view + // const { type } = this.node + const pos = this.getPos() + const newAttrs = { + ...this.node.attrs, + ...attrs, + } + // const transaction = this.isMark + // ? state.tr + // .removeMark(pos.from, pos.to, type) + // .addMark(pos.from, pos.to, type.create(newAttrs)) + // : state.tr.setNodeMarkup(pos, null, newAttrs) + const transaction = state.tr.setNodeMarkup(pos, undefined, newAttrs) + + this.editor.view.dispatch(transaction) + } + } export default function VueRenderer(component: Vue | VueConstructor) {