Files
NextEdu/src/modules/lesson-preparation/lib/anchor-mark.ts

134 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Mark, mergeAttributes } from "@tiptap/core";
import { Node } from "@tiptap/core";
/**
* V4 锚点系统:用 Tiptap Mark 内嵌锚点,替代 v3 的字符串偏移。
*
* - AnchorMarkrange 锚点):包裹选中文本,渲染为高亮 + 底部细线 + 行内标签
* - AnchorPointpoint 锚点):独立 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 {};
},
});