/** * `mention` — atomic inline node for @user / @record mentions. * * Notion-style mention chips. `id` is the target (user/record/page id), * `label` the display text (resolved at insert time; the chip is atomic — * never split or edited as text). Rendered as a span so the inline editor * (apps/web) can style it; the block codec ignores it (it lives inside a * text block's inline content, not at block level). */ import { mergeAttributes, Node } from "@tiptap/core"; export interface MentionOptions { readonly HTMLAttributes: Record; } declare module "@tiptap/core" { interface Config { options: MentionOptions; } } export const MentionNode = Node.create({ name: "factoryMention", group: "inline", inline: true, atom: true, selectable: true, addOptions() { return { HTMLAttributes: { class: "factory-mention", }, }; }, addAttributes() { return { id: { default: null, parseHTML: (element) => element.getAttribute("data-mention-id"), renderHTML: (attributes) => attributes.id === null ? {} : { "data-mention-id": attributes.id }, }, label: { default: null, parseHTML: (element) => element.textContent, renderHTML: () => ({}), }, }; }, parseHTML() { return [{ tag: "span.factory-mention" }]; }, renderHTML({ node, HTMLAttributes }) { return [ "span", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), (node.attrs.label as string | null) ?? "…", ]; }, });