import { Mark, mergeAttributes } from "@tiptap/core"; import { Node } from "@tiptap/core"; /** * V4 锚点系统:用 Tiptap Mark 内嵌锚点,替代 v3 的字符串偏移。 * * - AnchorMark(range 锚点):包裹选中文本,渲染为高亮 + 底部细线 + 行内标签 * - AnchorPoint(point 锚点):独立 Node,渲染为黑色小圆圈带数字 * * 锚点数据存储在 Mark/Node 的 attributes 中,编辑时自动跟随文本移动。 */ export interface AnchorMarkAttributes { anchorId: string; nodeId: string; type: "range"; } export const AnchorMark = Mark.create({ name: "anchor", addAttributes() { return { anchorId: { default: null, parseHTML: (el) => el.getAttribute("data-anchor-id"), renderHTML: (attrs) => ({ "data-anchor-id": attrs.anchorId, }), }, nodeId: { default: null, parseHTML: (el) => el.getAttribute("data-node-id"), renderHTML: (attrs) => ({ "data-node-id": attrs.nodeId, }), }, type: { default: "range", parseHTML: (el) => el.getAttribute("data-anchor-type") ?? "range", renderHTML: (attrs) => ({ "data-anchor-type": attrs.type, }), }, }; }, parseHTML() { return [ { tag: "span[data-anchor-id]", }, ]; }, renderHTML({ HTMLAttributes }) { return [ "span", mergeAttributes(HTMLAttributes, { class: "lp-anchor-range", }), ]; }, // 不自动添加任何快捷键 addKeyboardShortcuts() { return {}; }, }); /** * AnchorPoint:点锚点,作为独立 Node 插入文本流。 * 渲染为带数字的黑色小圆圈。 */ export const AnchorPoint = Node.create({ name: "anchorPoint", group: "inline", inline: true, atom: true, addAttributes() { return { anchorId: { default: null, parseHTML: (el) => el.getAttribute("data-anchor-id"), renderHTML: (attrs) => ({ "data-anchor-id": attrs.anchorId, }), }, nodeId: { default: null, parseHTML: (el) => el.getAttribute("data-node-id"), renderHTML: (attrs) => ({ "data-node-id": attrs.nodeId, }), }, label: { default: "•", parseHTML: (el) => el.getAttribute("data-label") ?? "•", renderHTML: (attrs) => ({ "data-label": attrs.label, }), }, }; }, parseHTML() { return [ { tag: "span[data-anchor-point]", }, ]; }, renderHTML({ HTMLAttributes }) { return [ "span", mergeAttributes(HTMLAttributes, { "data-anchor-point": "true", class: "lp-anchor-point", contenteditable: "false", }), HTMLAttributes.label ?? "•", ]; }, addKeyboardShortcuts() { return {}; }, });