diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index c49cd3de..e925f422 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -256,6 +256,7 @@ export class Editor extends EventEmitter { * Creates a ProseMirror view. */ private createView() { + console.log('CREATE VIEW') this.view = new EditorView(this.options.element, { state: EditorState.create({ doc: this.createDocument(this.options.content), diff --git a/packages/core/src/ExtensionManager.ts b/packages/core/src/ExtensionManager.ts index 2da65cd5..ab26ef84 100644 --- a/packages/core/src/ExtensionManager.ts +++ b/packages/core/src/ExtensionManager.ts @@ -1,14 +1,14 @@ import { Plugin } from 'prosemirror-state' import { keymap } from 'prosemirror-keymap' -// import { Schema, Node as ProsemirrorNode } from 'prosemirror-model' +import { Schema, Node as ProsemirrorNode } from 'prosemirror-model' import { inputRules } from 'prosemirror-inputrules' -// import { EditorView, Decoration } from 'prosemirror-view' -import { Schema } from 'prosemirror-model' +import { EditorView, Decoration } from 'prosemirror-view' import { Editor } from './Editor' // import capitalize from './utils/capitalize' import { Extensions } from './types' import getSchema from './utils/getSchema' import getSchemaTypeByName from './utils/getSchemaTypeByName' +import splitExtensions from './utils/splitExtensions' export default class ExtensionManager { @@ -98,6 +98,38 @@ export default class ExtensionManager { } get nodeViews() { + const { nodeExtensions } = splitExtensions(this.extensions) + + return Object.fromEntries(nodeExtensions + .filter(extension => !!extension.addNodeView) + .map(extension => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), + } + + const renderer = extension.addNodeView?.bind(context)?.() + + const nodeview = ( + node: ProsemirrorNode, + view: EditorView, + getPos: (() => number) | boolean, + decorations: Decoration[], + ) => { + // @ts-ignore + return new renderer({ + editor: this.editor, + view, + node, + getPos, + decorations, + }) + } + + return [extension.name, nodeview] + })) + // const { renderer: Renderer } = this.editor // if (!Renderer || !Renderer.type) { diff --git a/packages/core/src/NodeExtension.ts b/packages/core/src/NodeExtension.ts index 76dba816..8de0c678 100644 --- a/packages/core/src/NodeExtension.ts +++ b/packages/core/src/NodeExtension.ts @@ -139,6 +139,11 @@ export interface NodeExtensionSpec extends Overwrit editor: Editor, type: NodeType, }) => Plugin[], + + /** + * Node View + */ + addNodeView?: (() => any) | null, }> {} export type NodeExtension = Required & { @@ -166,6 +171,7 @@ const defaultNode: NodeExtension = { parseHTML: () => null, renderHTML: null, addAttributes: () => ({}), + addNodeView: null, } export function createNode(config: NodeExtensionSpec) { diff --git a/packages/core/src/NodeView.ts b/packages/core/src/NodeView.ts new file mode 100644 index 00000000..30a8e894 --- /dev/null +++ b/packages/core/src/NodeView.ts @@ -0,0 +1,3 @@ +export class NodeView { + +} diff --git a/packages/extension-image/index.ts b/packages/extension-image/index.ts index 424cffc5..bf975076 100644 --- a/packages/extension-image/index.ts +++ b/packages/extension-image/index.ts @@ -1,4 +1,5 @@ import { Command, createNode, nodeInputRule } from '@tiptap/core' +import { VueRenderer } from '@tiptap/vue' export const inputRegex = /!\[(.+|:?)]\((\S+)(?:(?:\s+)["'](\S+)["'])?\)/ @@ -59,6 +60,12 @@ const Image = createNode({ }), ] }, + + addNodeView() { + return VueRenderer({ + template: '
vue component
', + }) + }, }) export default Image diff --git a/packages/vue/index.ts b/packages/vue/index.ts index 79050a05..f1e855cc 100644 --- a/packages/vue/index.ts +++ b/packages/vue/index.ts @@ -1,7 +1,10 @@ import { Editor as CoreEditor } from '@tiptap/core' import Renderer from './src/Renderer' +import VueRenderer from './src/VueRenderer' export * from '@tiptap/core' +export { Renderer } +export { VueRenderer } export { default as EditorContent } from './src/components/EditorContent' export class Editor extends CoreEditor { diff --git a/packages/vue/src/VueRenderer.ts b/packages/vue/src/VueRenderer.ts new file mode 100644 index 00000000..e58ab726 --- /dev/null +++ b/packages/vue/src/VueRenderer.ts @@ -0,0 +1,96 @@ +// @ts-nocheck + +// export default (component: any) => { +// console.log('vue renderer', component) + +// // return (node, view, getPos) => { +// return what => { + +// console.log(what) +// // return new class ImageView { +// // constructor(node, view, getPos) { +// // this.dom = document.createElement('img') +// // this.dom.src = node.attrs.src +// // this.dom.alt = node.attrs.alt +// // this.dom.addEventListener('click', e => { +// // e.preventDefault() +// // const alt = prompt('New alt text:', '') +// // if (alt) { +// // view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { +// // src: node.attrs.src, +// // alt, +// // })) +// // } +// // }) +// // } + +// // stopEvent() { return true } +// // }(node, view, getPos) + +// } +// } + +import { Editor } from '@tiptap/core' +import { Node as ProsemirrorNode } from 'prosemirror-model' +import { EditorView } from 'prosemirror-view' +import Vue from 'vue' + +export default (component: any) => class ImageView { + + vm!: Vue + + constructor(props: { editor: Editor, node: ProsemirrorNode, view: EditorView, getPos: any }) { + const { + node, editor, getPos, view, + } = props + // const { view } = editor + + // this.dom = document.createElement('div') + // this.dom.innerHTML = 'hello node view' + + this.mount(component) + } + + mount(component: Vue) { + const Component = Vue.extend(component) + + this.vm = new Component({ + // parent: this.parent, + // propsData: props, + }).$mount() + } + + get dom() { + return this.vm.$el + } + + get contentDOM() { + return this.vm.$refs.content + } + + stopEvent() { + return true + } + + // console.log(what) + // return new class ImageView { + // constructor(node, view, getPos) { + // this.dom = document.createElement('img') + // this.dom.src = node.attrs.src + // this.dom.alt = node.attrs.alt + // this.dom.addEventListener('click', e => { + // e.preventDefault() + // const alt = prompt('New alt text:', '') + // if (alt) { + // view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { + // src: node.attrs.src, + // alt, + // })) + // } + // }) + // } + + // stopEvent() { return true } + // }(node, view, getPos) + +}