| |
| |
| |
| |
| |
| |
| |
|
|
| import { Node, mergeAttributes } from "@tiptap/core"; |
| import { ReactNodeViewRenderer } from "@tiptap/react"; |
| import type { ComponentDef } from "./registry"; |
| import { makeWrapperView } from "./WrapperView"; |
| import { makeAtomicView } from "./AtomicView"; |
| import { MermaidNodeView } from "./MermaidView"; |
| import { HfUserNodeView } from "./HfUserView"; |
| import { makeHtmlEmbedView } from "../embeds/HtmlEmbedView"; |
| import { makeIframeEmbedView } from "../embeds/IframeEmbedView"; |
|
|
| function buildAttrSchema(fields: ComponentDef["fields"]) { |
| const attrs: Record<string, { default: unknown }> = {}; |
| for (const f of fields) { |
| attrs[f.name] = { default: f.default ?? null }; |
| } |
| return attrs; |
| } |
|
|
| function buildDefaultAttrs(fields: ComponentDef["fields"]) { |
| const attrs: Record<string, unknown> = {}; |
| for (const f of fields) { |
| attrs[f.name] = f.default ?? null; |
| } |
| return attrs; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| export function createComponentExtension(def: ComponentDef) { |
| const isWrapper = def.kind === "wrapper"; |
| const commandName = `insert${def.tag}`; |
|
|
| return Node.create({ |
| name: def.name, |
| group: "block", |
| ...(isWrapper |
| ? { content: def.content || "block+", defining: true, isolating: true } |
| : { atom: true, draggable: true, selectable: true }), |
|
|
| addAttributes() { |
| return buildAttrSchema(def.fields); |
| }, |
|
|
| parseHTML() { |
| return [{ tag: `div[data-component="${def.name}"]` }]; |
| }, |
|
|
| renderHTML({ HTMLAttributes }) { |
| const base = mergeAttributes(HTMLAttributes, { "data-component": def.name }); |
| return isWrapper ? ["div", base, 0] : ["div", base]; |
| }, |
|
|
| addCommands() { |
| return { |
| [commandName]: |
| () => |
| ({ commands }: { commands: any }) => { |
| const content: any = { type: def.name, attrs: buildDefaultAttrs(def.fields) }; |
| if (isWrapper) content.content = [{ type: "paragraph" }]; |
| return commands.insertContent(content); |
| }, |
| } as any; |
| }, |
|
|
| addNodeView() { |
| if (isWrapper) { |
| return ReactNodeViewRenderer(makeWrapperView(def)); |
| } |
| let View; |
| if (def.name === "mermaid") View = MermaidNodeView; |
| else if (def.name === "hfUser") View = HfUserNodeView; |
| else if (def.name === "htmlEmbed") View = makeHtmlEmbedView(def); |
| else if (def.name === "iframe") View = makeIframeEmbedView(def); |
| else View = makeAtomicView(def); |
| return ReactNodeViewRenderer(View); |
| }, |
| }); |
| } |
|
|
| |
| export const createWrapperExtension = createComponentExtension; |
| |
| export const createAtomicExtension = createComponentExtension; |
|
|