tiptap-markdown-react 0.19.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +23 -37
  2. package/THIRD_PARTY_LICENSES.md +155 -1
  3. package/dist/{ReportContent-B8jIzhy3.js → ReportContent-w08GFm8v.js} +16 -8
  4. package/dist/{ReportContent-B8jIzhy3.js.map → ReportContent-w08GFm8v.js.map} +1 -1
  5. package/dist/blockDrag/actions.d.ts +30 -0
  6. package/dist/blockDrag/actions.test.d.ts +1 -0
  7. package/dist/blockDrag/listDrop.d.ts +21 -0
  8. package/dist/blockDrag/listDrop.test.d.ts +1 -0
  9. package/dist/blurSelection.dom.test.d.ts +1 -0
  10. package/dist/characterCount.d.ts +1 -0
  11. package/dist/characterCount.dom.test.d.ts +1 -0
  12. package/dist/characterCount.test.d.ts +1 -0
  13. package/dist/chart/createChart.d.ts +0 -3
  14. package/dist/components/BlockDragHandle.d.ts +14 -0
  15. package/dist/components/BlockDragHandle.dom.test.d.ts +1 -0
  16. package/dist/components/CodeBlockView.d.ts +2 -2
  17. package/dist/components/ColorPalette.d.ts +4 -3
  18. package/dist/components/EditorToolbar.d.ts +4 -3
  19. package/dist/components/FindReplaceBar.d.ts +4 -3
  20. package/dist/components/LinkPopover.d.ts +4 -3
  21. package/dist/components/MarkdownPreview.d.ts +4 -1
  22. package/dist/components/MarkdownWysiwygEditor.d.ts +30 -9
  23. package/dist/components/TocPanel.d.ts +4 -3
  24. package/dist/detailsMarkdown.d.ts +4 -0
  25. package/dist/detailsMarkdown.test.d.ts +1 -0
  26. package/dist/emoji/EmojiSuggestion.d.ts +23 -0
  27. package/dist/emoji/emojiCategories.d.ts +52 -0
  28. package/dist/emoji/emojiMarkdown.test.d.ts +1 -0
  29. package/dist/emoji/emojiSuggestion.dom.test.d.ts +1 -0
  30. package/dist/emoji/filterEmoji.d.ts +7 -0
  31. package/dist/emoji/markdownEmoji.d.ts +8 -0
  32. package/dist/{extractToc-CGrBMGvM.js → extractToc-Cr470fBy.js} +659 -5
  33. package/dist/extractToc-Cr470fBy.js.map +1 -0
  34. package/dist/fonts/OFL.txt +95 -0
  35. package/dist/i18n/index.d.ts +4 -0
  36. package/dist/i18n/store.d.ts +16 -0
  37. package/dist/i18n/types.d.ts +19 -0
  38. package/dist/i18n/zh.d.ts +3 -0
  39. package/dist/icons/index.d.ts +5 -0
  40. package/dist/imageUpload.d.ts +0 -3
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.js +1983 -407
  43. package/dist/index.js.map +1 -1
  44. package/dist/labels.d.ts +56 -2
  45. package/dist/numberingFormat.d.ts +67 -0
  46. package/dist/numberingFormat.test.d.ts +1 -0
  47. package/dist/reader.js +2 -2
  48. package/dist/{scrollToTocHeading-B2QmL4wi.js → scrollToTocHeading-kPgsn3cu.js} +2 -2
  49. package/dist/{scrollToTocHeading-B2QmL4wi.js.map → scrollToTocHeading-kPgsn3cu.js.map} +1 -1
  50. package/dist/server.js +4 -4
  51. package/dist/shortcuts/ShortcutPanel.d.ts +4 -4
  52. package/dist/shortcuts/types.d.ts +2 -2
  53. package/dist/slashMenu/SlashMenuExtension.d.ts +0 -3
  54. package/dist/slashMenu/items.d.ts +2 -2
  55. package/dist/style-inline.css +2110 -294
  56. package/dist/style.css +2110 -294
  57. package/dist/typography.test.d.ts +1 -0
  58. package/package.json +19 -3
  59. package/dist/extractToc-CGrBMGvM.js.map +0 -1
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiptap-markdown-react",
3
- "version": "0.19.1",
3
+ "version": "1.0.0",
4
4
  "description": "A batteries-included, self-styled Markdown WYSIWYG editor and reader suite built on Tiptap v3. Markdown in/out, SSR/static rendering, table of contents, themeable via CSS variables.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -72,12 +72,18 @@
72
72
  "@tiptap/core": "3.31.3",
73
73
  "@tiptap/extension-code": "3.31.3",
74
74
  "@tiptap/extension-code-block-lowlight": "3.31.3",
75
+ "@tiptap/extension-collaboration": "3.31.3",
76
+ "@tiptap/extension-details": "3.31.3",
77
+ "@tiptap/extension-drag-handle": "3.31.3",
78
+ "@tiptap/extension-drag-handle-react": "3.31.3",
79
+ "@tiptap/extension-emoji": "3.31.3",
75
80
  "@tiptap/extension-file-handler": "3.31.3",
76
81
  "@tiptap/extension-find-and-replace": "3.31.3",
77
82
  "@tiptap/extension-heading": "3.31.3",
78
83
  "@tiptap/extension-highlight": "3.31.3",
79
84
  "@tiptap/extension-image": "3.31.3",
80
85
  "@tiptap/extension-mathematics": "3.31.3",
86
+ "@tiptap/extension-node-range": "3.31.3",
81
87
  "@tiptap/extension-paragraph": "3.31.3",
82
88
  "@tiptap/extension-subscript": "3.31.3",
83
89
  "@tiptap/extension-superscript": "3.31.3",
@@ -87,6 +93,7 @@
87
93
  "@tiptap/extension-task-list": "3.31.3",
88
94
  "@tiptap/extension-text-align": "3.31.3",
89
95
  "@tiptap/extension-text-style": "3.31.3",
96
+ "@tiptap/extension-typography": "3.31.3",
90
97
  "@tiptap/extensions": "3.31.3",
91
98
  "@tiptap/markdown": "3.31.3",
92
99
  "@tiptap/pm": "3.31.3",
@@ -94,9 +101,13 @@
94
101
  "@tiptap/starter-kit": "3.31.3",
95
102
  "@tiptap/static-renderer": "3.31.3",
96
103
  "@tiptap/suggestion": "3.31.3",
104
+ "@tiptap/y-tiptap": "3.0.7",
97
105
  "chart.js": "^4.5.1",
106
+ "emoji-regex": "10.6.0",
98
107
  "katex": "^0.16.47",
99
- "lowlight": "3.3.0"
108
+ "lowlight": "3.3.0",
109
+ "y-protocols": "1.0.6",
110
+ "yjs": "13.6.29"
100
111
  },
101
112
  "devDependencies": {
102
113
  "@types/react": "^19.2.17",
@@ -117,8 +128,13 @@
117
128
  "@tiptap/extension-list": "3.31.3",
118
129
  "@tiptap/extensions": "3.31.3",
119
130
  "@tiptap/extension-code-block": "3.31.3",
131
+ "@tiptap/extension-details": "3.31.3",
120
132
  "@tiptap/extension-file-handler": "3.31.3",
121
133
  "@tiptap/extension-bubble-menu": "3.31.3",
122
- "@tiptap/extension-floating-menu": "3.31.3"
134
+ "@tiptap/extension-floating-menu": "3.31.3",
135
+ "@tiptap/extension-drag-handle": "3.31.3",
136
+ "@tiptap/extension-drag-handle-react": "3.31.3",
137
+ "@tiptap/extension-node-range": "3.31.3",
138
+ "@tiptap/extension-collaboration": "3.31.3"
123
139
  }
124
140
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"extractToc-CGrBMGvM.js","sources":["../src/CitationRef.ts","../src/commentAnchor/CommentMark.ts","../src/commentAnchor/commentMapper.ts","../src/chart/ChartExtension.ts","../src/chart/codeBlockChartParse.ts","../src/imageMarkdown.ts","../src/math.ts","../src/paragraphMarkdown.ts","../src/paragraphStyles.ts","../src/extensions.ts","../src/chart/prepareChartMarkdown.ts","../src/toc/tocSlug.ts","../src/stabilizeMarkdown.ts","../src/toc/extractToc.ts"],"sourcesContent":["import { mergeAttributes, Node } from '@tiptap/core';\n\nexport interface CitationRefOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n citationRef: {\n insertCitationRef: (attrs: {\n index: string;\n url?: string | null;\n title?: string | null;\n }) => ReturnType;\n };\n }\n}\n\n/**\n * 脚注/引文引用——inline atom 节点。\n *\n * - 输入:`[^n]`(markdownTokenizer)或 `<span class=\"citation-ref\">`(parseHTML)\n * - 输出 HTML:居中圆形 pill(CSS `.citation-ref`),**不是**上下标\n * - 输出 markdown:`[^n]`\n *\n * Popover /「原文片段」由消费方通过 {@link createCitationRef} 的 `renderCitation`\n * 插槽完成;本节点只负责标记与默认圆标样式。\n */\nexport const CitationRef = Node.create<CitationRefOptions>({\n name: 'citationRef',\n\n group: 'inline',\n\n inline: true,\n\n atom: true,\n\n selectable: true,\n\n // 高于普通链接,确保 `[^1]` 不被拆成残缺 link\n priority: 1000,\n\n addOptions() {\n return { HTMLAttributes: {} };\n },\n\n addAttributes() {\n return {\n index: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-index'),\n renderHTML: (attributes) => {\n if (!attributes.index) return {};\n return { 'data-index': attributes.index };\n },\n },\n url: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-url'),\n renderHTML: (attributes) => {\n if (!attributes.url) return {};\n return { 'data-url': attributes.url };\n },\n },\n title: {\n default: null,\n parseHTML: (element) => element.getAttribute('data-title'),\n renderHTML: (attributes) => {\n if (!attributes.title) return {};\n return { 'data-title': attributes.title };\n },\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span.citation-ref' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const index = String(node.attrs.index ?? '');\n const url = node.attrs.url as string | null;\n const title = (node.attrs.title as string | null) || '';\n const attrs = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n class: 'citation-ref',\n });\n\n if (url) {\n return [\n 'span',\n attrs,\n [\n 'a',\n {\n href: url,\n title,\n target: '_blank',\n rel: 'noopener noreferrer',\n },\n index,\n ],\n ];\n }\n\n return ['span', attrs, index];\n },\n\n renderMarkdown(node) {\n return `[^${node?.attrs?.index ?? ''}]`;\n },\n\n parseMarkdown: (token, helpers) => {\n return helpers.createNode('citationRef', {\n index: String(token.index ?? ''),\n url: token.url ?? null,\n title: token.title ?? null,\n });\n },\n\n markdownTokenizer: {\n name: 'citationRef',\n level: 'inline' as const,\n start(src: string) {\n const match = /\\[\\^\\d+\\]/.exec(src);\n return match?.index ?? -1;\n },\n tokenize(src) {\n const match = /^\\[\\^(\\d+)\\]/.exec(src);\n if (!match) return undefined;\n return {\n type: 'citationRef',\n raw: match[0],\n index: match[1],\n };\n },\n },\n\n addCommands() {\n return {\n insertCitationRef:\n (attrs) =>\n ({ commands }) =>\n commands.insertContent({\n type: this.name,\n attrs: {\n index: attrs.index,\n url: attrs.url ?? null,\n title: attrs.title ?? null,\n },\n }),\n };\n },\n});\n","import { Mark, mergeAttributes } from '@tiptap/core';\n\n/**\n * 评论锚定 mark —— 仅存在于编辑会话内,导出 markdown 时剥离。\n *\n * - attrs.commentIds:string[]。ProseMirror 同一文本节点不能挂两个同名\n * mark,重叠评论由 commentMapper 合并成「区间 + commentIds[]」后一次性铺入。\n * - renderMarkdown 返回空串 → getMarkdown() 输出纯文本,评论数据不落库。\n * - 粘贴/拖拽拦截与 gutter / active 装饰见 commentAnchorPlugin(客户端)。\n * 本模块保持纯 schema,server 入口可安全导入。\n */\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n commentAnchor: {\n /** 按互不相交的区间 + commentIds 数组铺评论 mark(区间由 mergeCommentIntervals 产出)。 */\n applyCommentAnchors: (intervals: CommentInterval[]) => ReturnType;\n /** 清空全文档评论 mark(comments 刷新 / 退出编辑态前调用)。 */\n clearCommentAnchors: () => ReturnType;\n };\n }\n}\n\nexport interface CommentInterval {\n from: number;\n to: number;\n commentIds: string[];\n}\n\nexport interface CommentMarkOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\nexport const CommentMark = Mark.create<CommentMarkOptions>({\n name: 'commentAnchor',\n\n // 评论是「引用快照」:光标在区间边界输入不应自动扩展高亮。\n inclusive: false,\n // 与加粗/斜体等格式可共存。\n excludes: '',\n\n addOptions() {\n return { HTMLAttributes: {} };\n },\n\n addAttributes() {\n return {\n commentIds: {\n default: [] as string[],\n parseHTML: (element) =>\n (element.getAttribute('data-comment-ids') ?? '')\n .split(' ')\n .filter(Boolean),\n renderHTML: (attributes) => {\n const ids = attributes.commentIds as string[];\n return ids?.length\n ? { 'data-comment-ids': Array.from(new Set(ids)).join(' ') }\n : {};\n },\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'mark[data-comment-ids]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n 'mark',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n class: 'tmr-comment',\n }),\n 0,\n ];\n },\n\n // 关键契约:markdown 输出剥离评论 mark,落库内容永远干净。\n // 注意:@tiptap/markdown 的 registerExtension 以扩展 name 注册 renderMarkdown,\n // 无需(也不支持)markdownName 字段。\n renderMarkdown() {\n return '';\n },\n\n addCommands() {\n return {\n applyCommentAnchors:\n (intervals) =>\n ({ tr, dispatch }) => {\n const intervals_ = (intervals ?? []).filter(\n (iv) => iv.from < iv.to && iv.commentIds.length > 0,\n );\n if (intervals_.length === 0) return false;\n let next = tr;\n for (const iv of intervals_) {\n next = next.addMark(\n iv.from,\n iv.to,\n this.type.create({ commentIds: iv.commentIds }),\n );\n }\n // 锚定是会话级 UI,不是用户内容:不进 undo 历史,避免 Ctrl+Z 把\n // 高亮全部撤掉。真编辑(改字)仍可正常 undo。\n next.setMeta('addToHistory', false);\n if (dispatch) dispatch(next);\n return true;\n },\n clearCommentAnchors:\n () =>\n ({ tr, dispatch }) => {\n const markType = this.type;\n const ranges: Array<{ from: number; to: number }> = [];\n tr.doc.descendants((node, pos) => {\n if (node.isText && node.marks.some((m) => m.type === markType)) {\n ranges.push({ from: pos, to: pos + node.nodeSize });\n }\n return true;\n });\n // 无 mark 时视为成功(no-op),保证 chain 后续命令继续执行。\n if (ranges.length === 0) return true;\n let next = tr;\n for (const r of ranges) next = next.removeMark(r.from, r.to, markType);\n next.setMeta('addToHistory', false);\n if (dispatch) dispatch(next);\n return true;\n },\n };\n },\n});\n","import type { Node } from '@tiptap/pm/model';\nimport type { CommentInterval } from './CommentMark';\n\n/**\n * SPIKE 原型:把评论的 ref_content segments 映射到 ProseMirror doc 上的文本区间。\n *\n * 与旧 DOM textContent 匹配的区别:\n * - 工作在文档模型上(无表格 wrapper 空白 / text node 碎片问题);\n * - 按顶层 block 作用域搜索,避免跨 block 误命中;\n * - fallback 链与既有 anchorCommentsInDom 一致:hash → context → exact → prefix → outdated。\n */\n\nexport interface CommentSegment {\n /** block 文本哈希(可选快路径;哈希算法见 blockTextHash,需与捕获端一致)。 */\n blockHash?: string;\n prefix?: string;\n exact: string;\n suffix?: string;\n}\n\nexport interface CommentAnchorInput {\n commentId: string;\n segments: CommentSegment[];\n}\n\nexport type CommentAnchorStatus = 'matched' | 'ambiguous' | 'partial' | 'outdated';\n\nexport interface CommentRange {\n from: number;\n to: number;\n}\n\nexport interface CommentAnchorResult {\n commentId: string;\n ranges: CommentRange[];\n status: CommentAnchorStatus;\n}\n\ninterface TextSlice {\n pos: number;\n text: string;\n}\n\ninterface TextIndex {\n slices: TextSlice[];\n offsets: number[];\n fullText: string;\n}\n\nconst PREFIX_FALLBACK_LEN = 20;\n\n/** 收集 [start, end) 内所有 text 节点 + 位置,拼成可搜索的 flat text。 */\nfunction collectText(doc: Node, start = 0, end = doc.content.size): TextIndex {\n const slices: TextSlice[] = [];\n const offsets: number[] = [];\n let cursor = 0;\n doc.nodesBetween(start, end, (node, pos) => {\n if (node.isText && node.text) {\n slices.push({ pos, text: node.text });\n offsets.push(cursor);\n cursor += node.text.length;\n }\n return true;\n });\n offsets.push(cursor);\n return {\n slices,\n offsets,\n fullText: slices.map((s) => s.text).join(''),\n };\n}\n\nfunction findAll(fullText: string, needle: string): number[] {\n if (!needle) return [];\n const hits: number[] = [];\n let from = 0;\n while (from <= fullText.length - needle.length) {\n const idx = fullText.indexOf(needle, from);\n if (idx < 0) break;\n hits.push(idx);\n from = idx + needle.length;\n }\n return hits;\n}\n\n/** 把 fullText 上的 [start, start+len) 映射回 doc 绝对位置。 */\nfunction rangeAt(index: TextIndex, start: number, len: number): CommentRange | null {\n if (len <= 0) return null;\n let startIdx = -1;\n let endIdx = -1;\n for (let i = 0; i < index.slices.length; i++) {\n if (index.offsets[i] <= start && start < index.offsets[i + 1]) startIdx = i;\n const end = start + len;\n if (index.offsets[i] < end && end <= index.offsets[i + 1]) endIdx = i;\n if (startIdx >= 0 && endIdx >= 0) break;\n }\n if (startIdx < 0 || endIdx < 0) return null;\n return {\n from: index.slices[startIdx].pos + (start - index.offsets[startIdx]),\n to: index.slices[endIdx].pos + (start + len - index.offsets[endIdx]),\n };\n}\n\n/** 顶层 block 边界(doc 直接子节点)。 */\nfunction blockBounds(doc: Node): Array<{ start: number; end: number }> {\n const bounds: Array<{ start: number; end: number }> = [];\n doc.forEach((child, offset) => {\n bounds.push({ start: offset, end: offset + child.nodeSize });\n });\n return bounds;\n}\n\n/** djb2 哈希(捕获端与消费端必须用同一个实现;接入时对齐)。 */\nexport function blockTextHash(text: string): string {\n const normalized = text.replace(/\\s+/g, '');\n let hash = 5381;\n for (let i = 0; i < normalized.length; i++) {\n hash = (hash * 33) ^ normalized.charCodeAt(i);\n }\n return String(hash >>> 0);\n}\n\nfunction blockText(doc: Node, bound: { start: number; end: number }): string {\n return collectText(doc, bound.start, bound.end).fullText;\n}\n\n/** 在若干 block 内找 needle,返回命中区间;命中 >1 处标记 ambiguous。 */\nfunction matchInBlocks(\n doc: Node,\n bounds: Array<{ start: number; end: number }>,\n needle: string,\n markLen: number,\n markOffset: number,\n): { ranges: CommentRange[]; ambiguous: boolean } {\n const ranges: CommentRange[] = [];\n let hits = 0;\n for (const bound of bounds) {\n const index = collectText(doc, bound.start, bound.end);\n for (const start of findAll(index.fullText, needle)) {\n const range = rangeAt(index, start + markOffset, markLen);\n if (range) {\n ranges.push(range);\n hits += 1;\n }\n }\n }\n return { ranges, ambiguous: hits > 1 };\n}\n\n/** 单个 segment → doc 区间(fallback 链)。 */\nfunction matchSegment(doc: Node, seg: CommentSegment): {\n ranges: CommentRange[];\n ambiguous: boolean;\n} {\n const bounds = blockBounds(doc);\n\n // S1: blockHash 快路径\n if (seg.blockHash) {\n const ranges: CommentRange[] = [];\n let hits = 0;\n for (const bound of bounds) {\n if (blockTextHash(blockText(doc, bound)) !== seg.blockHash) continue;\n const index = collectText(doc, bound.start, bound.end);\n for (const start of findAll(index.fullText, seg.exact)) {\n const range = rangeAt(index, start, seg.exact.length);\n if (range) {\n ranges.push(range);\n hits += 1;\n }\n }\n }\n if (ranges.length > 0) return { ranges, ambiguous: hits > 1 };\n }\n\n // S2: 上下文(prefix+exact+suffix)定位\n if (seg.prefix || seg.suffix) {\n const composite = (seg.prefix ?? '') + seg.exact + (seg.suffix ?? '');\n const found = matchInBlocks(\n doc,\n bounds,\n composite,\n seg.exact.length,\n seg.prefix?.length ?? 0,\n );\n if (found.ranges.length > 0) return found;\n }\n\n // S3: block 内 exact\n const exact = matchInBlocks(doc, bounds, seg.exact, seg.exact.length, 0);\n if (exact.ranges.length > 0) return exact;\n\n // S4: 前缀降级(前 20 字)\n const prefix = seg.exact.slice(0, PREFIX_FALLBACK_LEN);\n if (prefix.length >= 4 && prefix !== seg.exact) {\n const fallback = matchInBlocks(doc, bounds, prefix, prefix.length, 0);\n if (fallback.ranges.length > 0) return fallback;\n }\n\n return { ranges: [], ambiguous: false };\n}\n\n/** 主入口:评论列表 → 每条的 doc 区间 + 状态。 */\nexport function mapCommentAnchors(\n doc: Node,\n comments: CommentAnchorInput[],\n): CommentAnchorResult[] {\n return comments.map((c) => {\n let matchedSegments = 0;\n let ambiguousSegments = 0;\n const ranges: CommentRange[] = [];\n for (const seg of c.segments) {\n const { ranges: segRanges, ambiguous } = matchSegment(doc, seg);\n if (segRanges.length > 0) {\n matchedSegments += 1;\n if (ambiguous) ambiguousSegments += 1;\n ranges.push(...segRanges);\n }\n }\n const status: CommentAnchorStatus =\n matchedSegments === 0\n ? 'outdated'\n : ambiguousSegments > 0\n ? 'ambiguous'\n : matchedSegments < c.segments.length\n ? 'partial'\n : 'matched';\n return { commentId: c.commentId, ranges, status };\n });\n}\n\n/** 把每条评论的区间合并成互不相交的 CommentInterval(重叠区间合并 commentIds)。 */\nexport function mergeCommentIntervals(\n entries: Array<{ commentId: string; ranges: CommentRange[] }>,\n): CommentInterval[] {\n interface Event {\n pos: number;\n delta: 1 | -1;\n id: string;\n }\n const events: Event[] = [];\n for (const e of entries) {\n // 先按评论合并相邻/接触区间(同一评论的多段 [0,2)+[2,4) 应视为连续覆盖),\n // 否则 sweep 会在接缝处错误地先关后开,产出多余分段。\n const sorted = e.ranges\n .filter((r) => r.from < r.to)\n .sort((a, b) => a.from - b.from || a.to - b.to);\n const merged: CommentRange[] = [];\n for (const r of sorted) {\n const last = merged[merged.length - 1];\n if (last && r.from <= last.to) {\n if (r.to > last.to) last.to = r.to;\n } else {\n merged.push({ from: r.from, to: r.to });\n }\n }\n for (const r of merged) {\n events.push({ pos: r.from, delta: 1, id: e.commentId });\n events.push({ pos: r.to, delta: -1, id: e.commentId });\n }\n }\n if (events.length === 0) return [];\n events.sort((a, b) => a.pos - b.pos || a.delta - b.delta);\n\n const intervals: CommentInterval[] = [];\n const active = new Set<string>();\n let prevPos = events[0].pos;\n for (const ev of events) {\n if (ev.pos > prevPos && active.size > 0) {\n intervals.push({\n from: prevPos,\n to: ev.pos,\n commentIds: Array.from(active),\n });\n }\n if (ev.delta === 1) active.add(ev.id);\n else active.delete(ev.id);\n prevPos = ev.pos;\n }\n return intervals;\n}\n","import { mergeAttributes, Node } from '@tiptap/core';\nimport { Plugin, PluginKey } from '@tiptap/pm/state';\nimport { CHART_FENCE_LANGS } from './codeBlockChartParse';\nimport {\n normalizeChartMarkdown,\n parseChartFenceBody,\n serializeChartPayload,\n} from './parse';\nimport type { ChartColumn, ChartConfig, ChartPayload } from './types';\n\nconst chartFenceUpgradeKey = new PluginKey('tmrChartFenceUpgrade');\n\nexport const CHART_NODE_NAME = 'chart';\n\nexport interface ChartNodeAttrs {\n config: ChartConfig[];\n columns: ChartColumn[];\n dataSource: Record<string, unknown>[];\n}\n\nfunction attrsToPayload(attrs: ChartNodeAttrs): ChartPayload {\n return {\n config: attrs.config ?? [],\n columns: attrs.columns ?? [],\n dataSource: attrs.dataSource ?? [],\n };\n}\n\nfunction encodePayload(payload: ChartPayload): string {\n return JSON.stringify(payload);\n}\n\nfunction decodePayloadAttr(raw: string | null): ChartPayload | null {\n if (!raw) return null;\n try {\n return parseChartFenceBody(raw) ?? (JSON.parse(raw) as ChartPayload);\n } catch {\n return null;\n }\n}\n\nexport interface ReportChartOptions {\n HTMLAttributes: Record<string, unknown>;\n}\n\n/**\n * Pure chart block node — safe for server / SSR.\n * Does not import chart.js or React. renderHTML emits a hydrate placeholder.\n */\nexport const reportChart = Node.create<ReportChartOptions>({\n name: CHART_NODE_NAME,\n\n group: 'block',\n\n atom: true,\n\n selectable: true,\n\n draggable: true,\n\n // Above default codeBlock so ```tmr-chart / ```chart bind here\n priority: 1000,\n\n addOptions() {\n return { HTMLAttributes: {} };\n },\n\n addAttributes() {\n return {\n config: {\n default: [],\n parseHTML: (element) => {\n const payload = decodePayloadAttr(element.getAttribute('data-chart'));\n return payload?.config ?? [];\n },\n },\n columns: {\n default: [],\n parseHTML: (element) => {\n const payload = decodePayloadAttr(element.getAttribute('data-chart'));\n return payload?.columns ?? [];\n },\n },\n dataSource: {\n default: [],\n parseHTML: (element) => {\n const payload = decodePayloadAttr(element.getAttribute('data-chart'));\n return payload?.dataSource ?? [];\n },\n },\n };\n },\n\n parseHTML() {\n return [{ tag: 'div[data-type=\"chart\"]' }];\n },\n\n renderHTML({ node, HTMLAttributes }) {\n const payload = attrsToPayload(node.attrs as ChartNodeAttrs);\n const title = payload.config[0]?.title;\n const height = payload.config[0]?.height ?? 320;\n const dataTime = payload.config[0]?.dataTime;\n\n return [\n 'div',\n mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {\n 'data-type': 'chart',\n 'data-chart': encodePayload(payload),\n class: 'tmr-chart',\n style: `min-height:${height}px`,\n }),\n title\n ? ['div', { class: 'tmr-chart-title' }, String(title)]\n : ['div', { class: 'tmr-chart-title tmr-chart-title--empty' }, ''],\n dataTime\n ? ['div', { class: 'tmr-chart-time' }, String(dataTime)]\n : ['div', { class: 'tmr-chart-time tmr-chart-time--empty' }, ''],\n [\n 'div',\n {\n class: 'tmr-chart-canvas-host tmr-chart-skeleton',\n 'aria-hidden': 'true',\n },\n ],\n ];\n },\n\n renderMarkdown(node) {\n const payload = attrsToPayload(node.attrs as ChartNodeAttrs);\n if (!payload.config.length) return '';\n return serializeChartPayload(payload);\n },\n\n parseMarkdown: (token, helpers) => {\n const body = String(token.content ?? token.text ?? token.raw ?? '');\n // Tokenizer may put JSON in `text` or leave fence body in content\n const json =\n typeof token.payload === 'string'\n ? token.payload\n : body.replace(/^```(?:tmr-chart|chart|json-chart)\\s*\\n?/i, '').replace(/\\n?```$/, '');\n const payload =\n parseChartFenceBody(typeof token.payload === 'string' ? token.payload : json) ??\n (token.payload && typeof token.payload === 'object'\n ? (token.payload as ChartPayload)\n : null);\n if (!payload) {\n return helpers.createNode('paragraph');\n }\n return helpers.createNode(CHART_NODE_NAME, {\n config: payload.config,\n columns: payload.columns,\n dataSource: payload.dataSource,\n });\n },\n\n markdownTokenizer: {\n name: CHART_NODE_NAME,\n level: 'block' as const,\n start(src: string) {\n const fence = src.match(/^```(?:tmr-chart|chart|json-chart)\\b/m);\n if (fence && fence.index !== undefined) return fence.index;\n return -1;\n },\n tokenize(src: string) {\n const match =\n /^```(tmr-chart|chart|json-chart)[^\\n]*\\n([\\s\\S]*?)```(?:\\r?\\n|$)/.exec(\n src,\n );\n if (!match) return undefined;\n const payload = parseChartFenceBody(match[2]);\n if (!payload) return undefined;\n return {\n type: CHART_NODE_NAME,\n raw: match[0],\n payload: JSON.stringify({\n config: payload.config,\n columns: payload.columns,\n dataSource: payload.dataSource,\n }),\n };\n },\n },\n\n /**\n * When the built-in `code` tokenizer wins, TipTap creates a codeBlock with\n * language=tmr-chart. Upgrade those nodes to chart (covers mid-column\n * CardMarkdownEditor + paste/setContent paths).\n */\n addProseMirrorPlugins() {\n const chartName = this.name;\n return [\n new Plugin({\n key: chartFenceUpgradeKey,\n appendTransaction(transactions, _oldState, newState) {\n if (!transactions.some((tr) => tr.docChanged)) return null;\n return buildChartFenceUpgradeTr(newState, chartName);\n },\n }),\n ];\n },\n});\n\nfunction buildChartFenceUpgradeTr(\n state: import('@tiptap/pm/state').EditorState,\n chartName: string,\n) {\n const chartType = state.schema.nodes[chartName];\n if (!chartType || !state.schema.nodes.codeBlock) return null;\n\n const replacements: { from: number; to: number; payload: ChartPayload }[] =\n [];\n state.doc.descendants((node, pos) => {\n if (node.type.name !== 'codeBlock') return;\n const lang = String(node.attrs.language ?? '')\n .trim()\n .toLowerCase();\n if (!CHART_FENCE_LANGS.has(lang)) return;\n const payload = parseChartFenceBody(node.textContent);\n if (!payload) return;\n replacements.push({\n from: pos,\n to: pos + node.nodeSize,\n payload,\n });\n });\n if (replacements.length === 0) return null;\n\n let tr = state.tr;\n for (let i = replacements.length - 1; i >= 0; i -= 1) {\n const { from, to, payload } = replacements[i];\n tr = tr.replaceWith(\n from,\n to,\n chartType.create({\n config: payload.config,\n columns: payload.columns,\n dataSource: payload.dataSource,\n }),\n );\n }\n return tr;\n}\n\n/** Re-export preprocess for parse pipelines. */\nexport { normalizeChartMarkdown };\n\n/** Pure chart extension alias for server / preview injection. */\nexport const pureChart = reportChart;\n","import type {\n JSONContent,\n MarkdownParseHelpers,\n MarkdownToken,\n} from '@tiptap/core';\nimport { CHART_NODE_NAME } from './ChartExtension';\nimport { parseChartFenceBody } from './parse';\n\n/** Fence languages that belong to chart nodes, not code blocks. */\nexport const CHART_FENCE_LANGS = new Set([\n 'tmr-chart',\n 'chart',\n 'json-chart',\n]);\n\n/**\n * TipTap's built-in `code` tokenizer often wins over custom chart fences.\n * When that happens, intercept CodeBlock.parseMarkdown and upgrade\n * ```tmr-chart / ```chart / ```json-chart into a chart node.\n */\nexport function parseCodeTokenAsChartOrCodeBlock(\n token: MarkdownToken,\n helpers: MarkdownParseHelpers,\n codeBlockName = 'codeBlock',\n): JSONContent | JSONContent[] {\n const lang = String(token.lang ?? '')\n .trim()\n .toLowerCase();\n if (CHART_FENCE_LANGS.has(lang)) {\n const payload = parseChartFenceBody(String(token.text ?? ''));\n if (payload) {\n return helpers.createNode(CHART_NODE_NAME, {\n config: payload.config,\n columns: payload.columns,\n dataSource: payload.dataSource,\n });\n }\n }\n\n if (\n token.raw?.startsWith('```') === false &&\n token.raw?.startsWith('~~~') === false &&\n token.codeBlockStyle !== 'indented'\n ) {\n return [];\n }\n\n return helpers.createNode(\n codeBlockName,\n { language: token.lang || null },\n token.text ? [helpers.createTextNode(token.text)] : [],\n );\n}\n","import type {\n JSONContent,\n MarkdownParseHelpers,\n MarkdownToken,\n MarkdownTokenizer,\n} from '@tiptap/core';\n// renderHTML 期望的是 prosemirror 的 DOMOutputSpec(支持多子节点数组),\n// 不是 tiptap 那个单链递归的 DOMOutputSpecArray\nimport type { DOMOutputSpec } from '@tiptap/pm/model';\n\n/**\n * 图片节点的 markdown 往返(客户端 / 预览 / server 三端共用)。\n *\n * 尺寸(拖拽缩放的产物,整数像素)、对齐(`data-align`)与描述(图注)在 markdown 里\n * 都没有原生语法,HTML 是唯一能带上它们的 CommonMark 合法形式:\n * `<img src=\"…\" alt=\"…\" width=\"300\" data-align=\"center\">`,\n * 带描述时再包一层 `<figure><img …><figcaption>…</figcaption></figure>`(HTML 标准语义,\n * GitHub 同样认)。因此:\n *\n * - 序列化:**只有带尺寸 / 对齐 / 描述的图**输出 HTML 形式;没动过的图保持标准\n * `![alt](src \"title\")`,markdown 不为没用过的功能付可读性代价。\n * - 解析:自建 block 级 tokenizer 认领 `<img …>` 与 `<figure>…</figure>`(一个扩展\n * 只能挂一个 tokenizer)。不认领的话,客户端靠 `window.DOMParser` 隐式还原、\n * server 端没有 window 会把它转义成字面文本(与 sup/sub 当初踩的是同一条边界)。\n *\n * 对齐的属性名用 `data-align`(attrs 里叫 `align`):与官方 image-align-button\n * 约定的属性名一致,宿主已有的 `img[data-align]` 样式可以直接吃。\n */\n\n/** 图片尺寸(整数像素);无尺寸为 null。 */\nexport interface ImageSizeAttrs {\n width?: number | null;\n height?: number | null;\n}\n\n/** 图片对齐(HTML 属性 `data-align`,与官方 image-align-button 同名)。 */\nexport type ImageAlign = 'left' | 'center' | 'right';\n\nconst IMAGE_ALIGN_VALUES = new Set<string>(['left', 'center', 'right']);\n\n/** 归一化对齐值:只认 left / center / right,其余(含空、任意脏值)为 null。 */\nexport function normalizeImageAlign(value: unknown): ImageAlign | null {\n return typeof value === 'string' && IMAGE_ALIGN_VALUES.has(value)\n ? (value as ImageAlign)\n : null;\n}\n\n/**\n * `align` 属性的共享配置(编辑器增强版与 pureImage 都挂它):attrs 名语义化、\n * HTML 渲染成 `data-align`。两份扩展都必须挂——attrs 只声明在扩展上,\n * markdown 解析出的 `align` 才有地方落。\n */\nexport const imageAlignAttribute = {\n default: null,\n parseHTML: (element: HTMLElement) =>\n normalizeImageAlign(element.getAttribute('data-align')),\n renderHTML: (attributes: Record<string, unknown>) => {\n const align = normalizeImageAlign(attributes.align);\n return align ? { 'data-align': align } : {};\n },\n};\n\n/**\n * `caption`(图注)属性的共享配置:不进 img 标签(是节点级 renderHTML 包的\n * `<figure>/<figcaption>` 结构),解析侧从 figure 里读。\n */\nexport const imageCaptionAttribute = {\n default: null,\n parseHTML: (element: HTMLElement) => {\n // 匹配到 img 时从它所在的 figure 里取(figure 规则通常已用 getAttrs 给全,\n // 这里是 HTML 粘贴的兜底)\n const figure = element.closest('figure');\n return normalizeImageCaption(\n figure?.querySelector('figcaption')?.textContent ?? null,\n );\n },\n renderHTML: () => ({}),\n};\n\n/**\n * 节点级 HTML 渲染:有描述时输出 `<figure><img …><figcaption>…</figcaption></figure>`\n * (HTML 标准语义),否则维持官方单 `<img>` 结构。两份扩展共用。\n */\nexport function imageNodeHtml(output: {\n attrs: Record<string, unknown>;\n htmlAttributes: Record<string, unknown>;\n}): DOMOutputSpec {\n const caption = normalizeImageCaption(output.attrs.caption);\n if (!caption) return ['img', output.htmlAttributes];\n // 多子节点直接展开跟在元素后面(嵌套数组会被 prosemirror 的 renderSpec 判为非法)\n return [\n 'figure',\n { class: 'tmr-image-figure' },\n ['img', output.htmlAttributes],\n ['figcaption', { class: 'tmr-image-caption' }, caption],\n ];\n}\n\n/**\n * `<figure><img …><figcaption>…</figcaption></figure>` 的 parse 规则(两份扩展共用,\n * 要排在 `img[src]` 规则之前)。读子 img 的全部属性 + figcaption 的纯文本描述。\n */\nexport function imageFigureParseRule(): {\n tag: string;\n getAttrs: (element: HTMLElement) => Record<string, unknown> | false;\n} {\n return {\n tag: 'figure',\n getAttrs: (element: HTMLElement) => {\n const img = element.querySelector('img');\n if (!img) return false;\n const caption = element.querySelector('figcaption');\n return {\n src: img.getAttribute('src'),\n alt: img.getAttribute('alt'),\n title: img.getAttribute('title'),\n width: toPixel(img.getAttribute('width')),\n height: toPixel(img.getAttribute('height')),\n align: normalizeImageAlign(img.getAttribute('data-align')),\n caption: normalizeImageCaption(caption?.textContent ?? null),\n };\n },\n };\n}\n\n/** 从 HTML 属性串里取一个属性值;双引号 / 单引号 / 无引号都认。 */\nfunction attrValue(attrs: string, name: string): string | null {\n const pattern = new RegExp(\n `(?:^|\\\\s)${name}\\\\s*=\\\\s*(?:\"([^\"]*)\"|'([^']*)'|([^\\\\s\"'=<>]+))`,\n 'i',\n );\n const match = pattern.exec(attrs);\n if (!match) return null;\n return match[1] ?? match[2] ?? match[3] ?? null;\n}\n\n/** 常见实体还原(`&amp;` / `&quot;` 等),与序列化侧的转义对称。 */\nconst ENTITIES: Record<string, string> = {\n '&amp;': '&',\n '&lt;': '<',\n '&gt;': '>',\n '&quot;': '\"',\n '&#39;': \"'\",\n};\n\nfunction decodeEntities(text: string): string {\n return text.replace(/&(?:amp|lt|gt|quot|#39);/g, (m) => ENTITIES[m] ?? m);\n}\n\n/** 属性值最小转义(`&` 与 `\"` 必须转,其余顺手,保证与 decodeEntities 对称)。 */\nfunction encodeAttr(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\n/** 文本节点最小转义(属性无关的 `\"` 不用转)。 */\nfunction encodeText(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\n/** 图片描述(图注)归一化:去掉首尾空白,空串归 null。 */\nexport function normalizeImageCaption(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const text = value.trim();\n return text === '' ? null : text;\n}\n\n/** HTML 宽高只认纯数字(`50%` / `auto` 这类留给 CSS,不当作像素尺寸)。 */\nfunction toPixel(value: string | null): number | null {\n if (value == null) return null;\n const n = Number(value);\n return Number.isFinite(n) && n > 0 ? Math.round(n) : null;\n}\n\n/**\n * 图片的 markdown 序列化:带尺寸 / 对齐 / 描述的输出 HTML 形式,否则标准语法。\n * 描述(图注)用 `<figure>` + `<figcaption>` 包裹(HTML 标准语义,GitHub 同样认);\n * 覆盖 @tiptap/extension-image 的内置实现(它只输出 src/alt/title,其余都会丢)。\n */\nexport function imageRenderMarkdown(node: {\n attrs?: Record<string, unknown>;\n}): string {\n const attrs = node.attrs ?? {};\n const src = typeof attrs.src === 'string' ? attrs.src : '';\n const alt = typeof attrs.alt === 'string' ? attrs.alt : '';\n const title = typeof attrs.title === 'string' ? attrs.title : '';\n const width = toPixel(attrs.width == null ? null : String(attrs.width));\n const height = toPixel(attrs.height == null ? null : String(attrs.height));\n const align = normalizeImageAlign(attrs.align);\n const caption = normalizeImageCaption(attrs.caption);\n\n if (width == null && height == null && !align && !caption) {\n return title ? `![${alt}](${src} \"${title}\")` : `![${alt}](${src})`;\n }\n\n const parts = [`src=\"${encodeAttr(src)}\"`];\n if (alt) parts.push(`alt=\"${encodeAttr(alt)}\"`);\n if (title) parts.push(`title=\"${encodeAttr(title)}\"`);\n if (width != null) parts.push(`width=\"${width}\"`);\n if (height != null) parts.push(`height=\"${height}\"`);\n if (align) parts.push(`data-align=\"${align}\"`);\n const imgTag = `<img ${parts.join(' ')}>`;\n\n if (!caption) return imgTag;\n return `<figure>\\n${imgTag}\\n<figcaption>${encodeText(caption)}</figcaption>\\n</figure>`;\n}\n\n/** 从 `<img …>` 的属性串里抽一个 token 需要的一切(figure / 裸 img 两种形态共用)。 */\nfunction imageTokenFromImgTag(\n raw: string,\n attrsString: string,\n caption: string | null = null,\n): MarkdownToken | undefined {\n const srcValue = attrValue(attrsString, 'src');\n if (!srcValue) return undefined;\n const alt = attrValue(attrsString, 'alt');\n const title = attrValue(attrsString, 'title');\n return {\n type: 'image',\n raw,\n src: decodeEntities(srcValue),\n alt: alt == null ? null : decodeEntities(alt),\n title: title == null ? null : decodeEntities(title),\n width: toPixel(attrValue(attrsString, 'width')),\n height: toPixel(attrValue(attrsString, 'height')),\n align: normalizeImageAlign(attrValue(attrsString, 'data-align')),\n caption,\n };\n}\n\n/**\n * 认领独占一行的 `<img …>` 与 `<figure>…</figure>`(block 级 tokenizer,一个扩展\n * 只能挂一个 tokenizer,所以两种形态都归它管)。属性在 tokenize 里就抽好,\n * `parseMarkdown` 只做搬运——与 CitationRef 的 tokenizer 同一套写法。\n */\nexport const imageMarkdownTokenizer: MarkdownTokenizer = {\n name: 'image',\n level: 'block',\n start(src) {\n const figure = /<figure[\\s>]/i.exec(src);\n const img = /<img[\\s>]/i.exec(src);\n const indexes = [figure?.index, img?.index].filter(\n (index): index is number => index != null,\n );\n return indexes.length ? Math.min(...indexes) : -1;\n },\n tokenize(src) {\n // 带描述的形式(本库写出的:figure > img + figcaption)\n const figure = /^<figure\\s*>([\\s\\S]*?)<\\/figure\\s*>/i.exec(src);\n if (figure) {\n const inner = figure[1] ?? '';\n const img = /<img\\s+([^>]*?)\\s*\\/?>/.exec(inner);\n if (!img) return undefined;\n const cap = /<figcaption[^>]*>([\\s\\S]*?)<\\/figcaption\\s*>/i.exec(inner);\n // 外部 markdown 的 figcaption 可能带内部标签:只取纯文本\n const caption = cap\n ? normalizeImageCaption(\n decodeEntities((cap[1] ?? '').replace(/<[^>]*>/g, '')),\n )\n : null;\n return imageTokenFromImgTag(figure[0], img[1] ?? '', caption);\n }\n // 裸 `<img …>` 形态\n const match = /^<img\\s+([^>]*?)\\s*\\/?>/.exec(src);\n if (!match) return undefined;\n return imageTokenFromImgTag(match[0], match[1] ?? '');\n },\n};\n\n/** 把上面认领的 token 还原成 image 节点(含尺寸、对齐与描述)。 */\nexport function imageParseMarkdown(\n token: MarkdownToken,\n helpers: MarkdownParseHelpers,\n): JSONContent {\n // 两种 token 形态:标准 `![alt](src \"title\")` 走 marked 的 image token\n // (字段是 href / text / title),本库 tokenizer 认领的 `<img …>` / `<figure>` 用 src / alt。\n const src = typeof token.src === 'string' ? token.src : token.href ?? null;\n const alt = typeof token.alt === 'string' ? token.alt : token.text ?? null;\n return helpers.createNode('image', {\n src,\n alt,\n title: token.title ?? null,\n width: token.width ?? null,\n height: token.height ?? null,\n align: token.align ?? null,\n caption: normalizeImageCaption(token.caption),\n });\n}\n","import { BlockMath, InlineMath } from '@tiptap/extension-mathematics';\nimport type { Node as PMNode } from '@tiptap/pm/model';\nimport katex from 'katex';\n\nconst KATEX_OPTIONS = { throwOnError: false as const };\n\nexport type MathKind = 'inline' | 'block';\n\nexport interface MathClickPayload {\n kind: MathKind;\n pos: number;\n latex: string;\n}\n\ntype MathClickListener = (payload: MathClickPayload) => void;\n\nlet mathClickListener: MathClickListener | null = null;\n\n/** 编辑器工具栏注册点击公式回调;未注册时点击无操作(预览 / SSR)。 */\nexport function subscribeMathClick(listener: MathClickListener): () => void {\n mathClickListener = listener;\n return () => {\n if (mathClickListener === listener) mathClickListener = null;\n };\n}\n\nfunction emitClick(kind: MathKind, node: PMNode, pos: number) {\n mathClickListener?.({\n kind,\n pos,\n latex: String(node.attrs.latex ?? ''),\n });\n}\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\n/** KaTeX HTML 片段(SSR / 预览弹层)。失败时回退为转义原文。 */\nexport function renderMathHtml(latex: string, displayMode: boolean): string {\n try {\n return katex.renderToString(latex ?? '', {\n ...KATEX_OPTIONS,\n displayMode,\n });\n } catch {\n return escapeHtml(latex ?? '');\n }\n}\n\n/** 把公式画进已有节点(编辑态原地预览,避免再叠一份 overlay)。 */\nexport function renderMathInto(\n el: HTMLElement,\n latex: string,\n displayMode: boolean,\n): void {\n try {\n katex.render(latex ?? '', el, { ...KATEX_OPTIONS, displayMode });\n } catch {\n el.textContent = latex ?? '';\n }\n}\n\nexport function renderMathElementHtml(\n latex: string,\n displayMode: boolean,\n): string {\n const inner = renderMathHtml(latex, displayMode);\n const attr = escapeHtml(latex ?? '');\n if (displayMode) {\n return `<div data-type=\"block-math\" data-latex=\"${attr}\" class=\"tiptap-mathematics-render\">${inner}</div>`;\n }\n return `<span data-type=\"inline-math\" data-latex=\"${attr}\" class=\"tiptap-mathematics-render\">${inner}</span>`;\n}\n\n/**\n * 行内公式:markdown 为 `$$latex$$`(单行、无换行)。\n * 关掉官方 `$…$` tokenizer 与 `$$` input rule——手打 `$` / `$$` 当字。\n */\nexport const reportInlineMath = InlineMath.extend({\n addInputRules() {\n return [];\n },\n\n renderMarkdown(node: { attrs?: { latex?: string } }) {\n return `$$${node.attrs?.latex || ''}$$`;\n },\n\n markdownTokenizer: {\n name: 'inlineMath',\n level: 'inline' as const,\n start(src: string) {\n return src.indexOf('$$');\n },\n tokenize(src: string) {\n const match = /^\\$\\$([^$\\n]+?)\\$\\$/.exec(src);\n if (!match) return undefined;\n return {\n type: 'inlineMath',\n raw: match[0],\n latex: match[1].trim(),\n };\n },\n },\n}).configure({\n katexOptions: { ...KATEX_OPTIONS, displayMode: false },\n onClick: (node, pos) => emitClick('inline', node, pos),\n});\n\n/**\n * 块级公式:markdown 为带换行的 `$$\\nlatex\\n$$`。\n * 单行 `$$…$$` 不在这里匹配,交给行内。无 input rule。\n */\nexport const reportBlockMath = BlockMath.extend({\n addInputRules() {\n return [];\n },\n\n renderMarkdown(node: { attrs?: { latex?: string } }) {\n const latex = node.attrs?.latex || '';\n return `$$\\n${latex}\\n$$`;\n },\n\n markdownTokenizer: {\n name: 'blockMath',\n level: 'block' as const,\n start(src: string) {\n const match = /\\$\\$\\r?\\n/.exec(src);\n return match ? match.index : -1;\n },\n tokenize(src: string) {\n const match = /^\\$\\$\\r?\\n([\\s\\S]+?)\\r?\\n\\$\\$(?:\\r?\\n|$)/.exec(src);\n if (!match) return undefined;\n return {\n type: 'blockMath',\n raw: match[0],\n latex: match[1].trim(),\n };\n },\n },\n}).configure({\n katexOptions: { ...KATEX_OPTIONS, displayMode: true },\n onClick: (node, pos) => emitClick('block', node, pos),\n});\n","import type {\n JSONContent,\n MarkdownParseHelpers,\n MarkdownRendererHelpers,\n MarkdownToken,\n MarkdownTokenizer,\n} from '@tiptap/core';\n\n/**\n * 段落级样式的 markdown 往返(文字对齐 / 缩进 / 行高,挂在段落与标题节点上)。\n *\n * markdown 没有段落级样式语法,带样式的段落序列化为行内 HTML:\n * `<p style=\"text-align: center; margin-left: 2em; line-height: 1.5\">…</p>`\n * (标题同理 `<h2 style=\"…\">…</h2>`)——与图片的 `<img …>` 班车同一套思路:\n * **只有带样式的段落**走 HTML 形式,普通段落保持原生 markdown。\n *\n * 对其它渲染器(GitHub 等)的降级是「样式被 sanitize 剥掉、内容原样显示」——\n * 段落样式是装饰而非内容,这个降级可以接受(图片裁剪那种内容性变化不能这么处理)。\n *\n * 解析侧:自建 block tokenizer 认领**带本库认识样式**的 `<p style>` / `<hN style>`\n * (其余 `style` 或无 style 的标签不抢,留给默认管线);内容是行内 markdown,\n * 用 `lexer.inlineTokens` 递归解析,bold/link 之类照常还原。server 端没有\n * window.DOMParser,认领后同样可用。\n */\n\n/** 缩进步长(em/级)。与 ParagraphStyles 的 indentStepEm 默认值一致(两处都硬编码 2)。 */\nconst INDENT_STEP_EM = 2;\n\nconst TEXT_ALIGN_VALUES = new Set(['left', 'center', 'right', 'justify']);\n\nfunction encodeAttr(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/\"/g, '&quot;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\n/** 本库认识的 style 键(其余键不算「本库样式」,tokenizer 不抢整段)。 */\nconst KNOWN_STYLE_KEYS = ['text-align', 'margin-left', 'line-height'] as const;\n\n/**\n * 从节点 attrs 生成 style 字符串(固定顺序,保证序列化幂等)。\n * 无任何样式时返回空串——调用方据此走原生 markdown 形式。\n */\nexport function paragraphStyleString(attrs: Record<string, unknown>): string {\n const parts: string[] = [];\n\n const align = typeof attrs.textAlign === 'string' ? attrs.textAlign : null;\n if (align && TEXT_ALIGN_VALUES.has(align)) {\n parts.push(`text-align: ${align}`);\n }\n\n const indent = Number(attrs.indent);\n if (Number.isFinite(indent) && indent > 0) {\n parts.push(`margin-left: ${indent * INDENT_STEP_EM}em`);\n }\n\n const lineHeight = Number(attrs.lineHeight);\n if (Number.isFinite(lineHeight) && lineHeight > 0) {\n parts.push(`line-height: ${lineHeight}`);\n }\n\n return parts.join('; ');\n}\n\n/** style 串 → 本库认识的 attrs(不认识 / 非法的键忽略)。 */\nexport function parseParagraphStyleAttrs(\n style: string,\n): Record<string, string | number> {\n const attrs: Record<string, string | number> = {};\n for (const entry of style.split(';')) {\n const index = entry.indexOf(':');\n if (index < 0) continue;\n const key = entry.slice(0, index).trim().toLowerCase();\n const value = entry.slice(index + 1).trim();\n if (!value) continue;\n\n if (key === 'text-align' && TEXT_ALIGN_VALUES.has(value)) {\n attrs.textAlign = value;\n } else if (key === 'margin-left') {\n const match = /^([\\d.]+)em$/.exec(value);\n const em = match ? Number.parseFloat(match[1]) : NaN;\n const level = Number.isFinite(em) && em > 0 ? Math.round(em / INDENT_STEP_EM) : 0;\n if (level > 0) attrs.indent = level;\n } else if (key === 'line-height') {\n const parsed = Number.parseFloat(value);\n if (Number.isFinite(parsed) && parsed > 0) attrs.lineHeight = parsed;\n }\n }\n return attrs;\n}\n\n/** style 串里有没有本库认识的键(决定 tokenizer 是否认领这段 HTML)。 */\nfunction hasKnownStyle(style: string): boolean {\n const lowered = style.toLowerCase();\n return KNOWN_STYLE_KEYS.some((key) => lowered.includes(`${key}:`));\n}\n\n/** 段落的 markdown 序列化:带样式走 `<p style=\"…\">`,否则保持默认(纯内容)。 */\nexport function paragraphRenderMarkdown(\n node: JSONContent,\n helpers: MarkdownRendererHelpers,\n): string {\n // 注意传**子节点数组**而不是节点本身:空段落没有 content 字段,传节点会落进\n // 序列化器的回退分支、把段落自己当子节点再渲染一遍 → 无限递归。\n const children = helpers.renderChildren(node.content ?? []);\n const style = paragraphStyleString(\n (node.attrs ?? {}) as Record<string, unknown>,\n );\n if (!style) return children;\n return `<p style=\"${encodeAttr(style)}\">${children}</p>`;\n}\n\n/** 标题的 markdown 序列化:带样式走 `<hN style=\"…\">`,否则保持 `## 前缀`。 */\nexport function headingRenderMarkdown(\n node: JSONContent,\n helpers: MarkdownRendererHelpers,\n): string {\n const children = helpers.renderChildren(node.content ?? []);\n const level = Math.min(\n Math.max(Number((node.attrs as { level?: unknown })?.level) || 1, 1),\n 6,\n );\n const style = paragraphStyleString(\n (node.attrs ?? {}) as Record<string, unknown>,\n );\n if (!style) return `${'#'.repeat(level)} ${children}`;\n return `<h${level} style=\"${encodeAttr(style)}\">${children}</h${level}>`;\n}\n\n/**\n * 认领**带本库样式**的 `<p style=\"…\">…</p>` / `<hN style=\"…\">…</hN>`(block 级)。\n * 一个扩展只能挂一个 tokenizer,段落与标题两种形态都归它管(同图片的 figure/img)。\n */\nexport const paragraphMarkdownTokenizer: MarkdownTokenizer = {\n name: 'paragraph',\n level: 'block',\n start(src) {\n const match = /<(?:p|h[1-6])\\s+style=/i.exec(src);\n return match ? match.index : -1;\n },\n tokenize(src, _tokens, lexer) {\n const match = /^<(p|h([1-6]))\\s+style=\"([^\"]*)\"\\s*>([\\s\\S]*?)<\\/\\1\\s*>/i.exec(\n src,\n );\n if (!match) return undefined;\n const [, tag, headingLevel, style, inner] = match;\n if (!hasKnownStyle(style)) return undefined; // 不认识的样式不抢,留给默认管线\n return {\n type: 'paragraph',\n raw: match[0],\n tag,\n hLevel: headingLevel ? Number(headingLevel) : null,\n style,\n // 行内内容交给 marked 的 lexer 解析:bold / link 等照常还原(与 sup/sub 同一手法)\n tokens: lexer.inlineTokens(inner ?? ''),\n };\n },\n};\n\n/**\n * 独占一行时会被\"提块\"的节点类型(本库的块级节点)。\n *\n * `![a](url)` 的 marked token 是段落(内含 image 行内 token),而 prosemirror 的\n * schema 不允许块级 image 待在段落里——内置解析器会把它们提成顶层节点;我们接管\n * 段落解析后要维持这一行为,否则图片会被塞在段落里(后续选中 / 命令都找不到它)。\n * 新增\"独占一行的块级节点\"时把类型名加进来。\n */\nconst ROW_BLOCK_TYPES = new Set(['image', 'chart']);\n\n/** token → 段落 / 标题节点(attrs 与内容一起还原)。 */\nexport function paragraphParseMarkdown(\n token: MarkdownToken,\n helpers: MarkdownParseHelpers,\n): JSONContent | JSONContent[] {\n const attrs = parseParagraphStyleAttrs(String(token.style ?? ''));\n const content = helpers.parseInline(token.tokens ?? []);\n\n // 段内只有块级节点(且段落自身没有样式):提出去当顶层节点\n const blockOnly =\n content.length > 0 &&\n Object.keys(attrs).length === 0 &&\n content.every((child) => ROW_BLOCK_TYPES.has(String(child.type)));\n if (blockOnly) return content;\n\n if (token.hLevel) {\n return helpers.createNode('heading', { level: token.hLevel, ...attrs }, content);\n }\n return helpers.createNode('paragraph', attrs, content);\n}\n","import { Extension, type CommandProps } from '@tiptap/core';\n\n/**\n * 段落样式(缩进 / 行高):给段落与标题两类节点加 `indent`(缩进级数)与\n * `lineHeight` attrs,渲染成行内 `style` 片段。\n *\n * 文字对齐用官方 `@tiptap/extension-text-align`(免费),它同样往节点 style 上写\n * `text-align`——tiptap 的 mergeAttributes 对 style 是**拼接合并**(按属性去重),\n * 两边各写各的片段,不会互相覆盖(有测试盯住三者共存)。\n *\n * markdown 侧的往返在 paragraphMarkdown.ts(段落级 `<p style=\"…\">` 形式)。\n */\nexport interface ParagraphStylesOptions {\n /** 参与的节点类型(与 TextAlign 的 types 对齐)。 */\n types: string[];\n /** 每级缩进的 em 数,默认 2(一个中文字宽)。 */\n indentStepEm: number;\n /** 最大缩进级数,默认 8。 */\n maxIndent: number;\n}\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n paragraphStyles: {\n /** 设置缩进级数;0 / null 清除。 */\n setIndent: (level: number | null) => ReturnType;\n /** 缩进 +1 级(到上限为止)。 */\n increaseIndent: () => ReturnType;\n /** 缩进 -1 级(到 0 即清除)。 */\n decreaseIndent: () => ReturnType;\n /** 设置行高(如 1.5);null 清除(回默认)。 */\n setLineHeight: (value: number | null) => ReturnType;\n };\n }\n}\n\n/** `'2em'` → 1 级(按 indentStepEm 折算);非法 / 非正值为 null。 */\nexport function parseIndentValue(\n value: string | null | undefined,\n stepEm: number,\n): number | null {\n if (!value) return null;\n const match = /^([\\d.]+)em$/.exec(value.trim());\n if (!match) return null;\n const em = Number.parseFloat(match[1]);\n if (!Number.isFinite(em) || em <= 0) return null;\n const level = Math.round(em / stepEm);\n return level > 0 ? level : null;\n}\n\n/** 只认纯数字(与本库序列化输出对称;`1.5` ✔,`150%` / `normal` ✘)。 */\nexport function parseLineHeightValue(\n value: string | null | undefined,\n): number | null {\n if (!value) return null;\n const parsed = Number.parseFloat(value);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\n\nfunction clampIndent(level: number, max: number): number {\n if (!Number.isFinite(level) || level <= 0) return 0;\n return Math.min(Math.round(level), max);\n}\n\nexport const ParagraphStyles = Extension.create<ParagraphStylesOptions>({\n name: 'paragraphStyles',\n\n addOptions() {\n return {\n types: [],\n indentStepEm: 2,\n maxIndent: 8,\n };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n indent: {\n default: null,\n parseHTML: (element) =>\n parseIndentValue(element.style.marginLeft, this.options.indentStepEm),\n renderHTML: (attributes) => {\n const level = clampIndent(\n Number(attributes.indent),\n this.options.maxIndent,\n );\n if (level === 0) return {};\n return {\n style: `margin-left: ${level * this.options.indentStepEm}em`,\n };\n },\n },\n lineHeight: {\n default: null,\n parseHTML: (element) => parseLineHeightValue(element.style.lineHeight),\n renderHTML: (attributes) => {\n const value = Number(attributes.lineHeight);\n if (!Number.isFinite(value) || value <= 0) return {};\n return { style: `line-height: ${value}` };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n /**\n * 对配置的每个类型都尝试 updateAttributes,有一个成功即成功。\n * **不要用 `every`**:光标在标题里时,第一个「段落」类型找不到节点会返回 false,\n * 短路会让标题永远拿不到样式(官方 TextAlign 用的是 `.map(...).some(...)`)。\n */\n const runOnTypes =\n (attrs: Record<string, unknown>) =>\n (props: CommandProps): boolean =>\n this.options.types\n .map((type) => props.commands.updateAttributes(type, attrs))\n .some((response) => response);\n\n /** 读「当前段落 / 标题」的缩进级数(取第一个匹配类型的值)。 */\n const currentIndent = ({ editor }: CommandProps): number => {\n for (const type of this.options.types) {\n const value = editor.getAttributes(type).indent;\n if (value != null) return Number(value) || 0;\n }\n return 0;\n };\n\n return {\n setIndent:\n (level) =>\n (props) => {\n const next = clampIndent(Number(level), this.options.maxIndent);\n return runOnTypes({ indent: next || null })(props);\n },\n increaseIndent:\n () =>\n (props) =>\n runOnTypes({\n indent: clampIndent(currentIndent(props) + 1, this.options.maxIndent) || null,\n })(props),\n decreaseIndent:\n () =>\n (props) =>\n runOnTypes({\n indent: clampIndent(currentIndent(props) - 1, this.options.maxIndent) || null,\n })(props),\n setLineHeight:\n (value) =>\n (props) =>\n runOnTypes({\n lineHeight: value == null ? null : parseLineHeightValue(String(value)),\n })(props),\n };\n },\n});\n","import Code from '@tiptap/extension-code';\nimport CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';\nimport Heading from '@tiptap/extension-heading';\nimport Highlight from '@tiptap/extension-highlight';\nimport Image from '@tiptap/extension-image';\nimport Paragraph from '@tiptap/extension-paragraph';\nimport Subscript from '@tiptap/extension-subscript';\nimport Superscript from '@tiptap/extension-superscript';\nimport { TableKit } from '@tiptap/extension-table';\nimport TaskItem from '@tiptap/extension-task-item';\nimport TaskList from '@tiptap/extension-task-list';\nimport TextAlign from '@tiptap/extension-text-align';\nimport {\n Color,\n FontSize,\n TextStyle,\n} from '@tiptap/extension-text-style';\n// AnyExtension 从 @tiptap/react 取(它 re-export 自 core),避免新增 @tiptap/core 直接依赖\nimport type { AnyExtension } from '@tiptap/react';\nimport { mergeAttributes } from '@tiptap/core';\nimport StarterKit from '@tiptap/starter-kit';\nimport { common, createLowlight } from 'lowlight';\nimport type {\n JSONContent,\n MarkdownParseHelpers,\n MarkdownRendererHelpers,\n MarkdownToken,\n MarkdownTokenizer,\n} from '@tiptap/core';\nimport { parseCodeTokenAsChartOrCodeBlock } from './chart/codeBlockChartParse';\nimport {\n imageAlignAttribute,\n imageCaptionAttribute,\n imageFigureParseRule,\n imageMarkdownTokenizer,\n imageNodeHtml,\n imageParseMarkdown,\n imageRenderMarkdown,\n} from './imageMarkdown';\nimport { reportBlockMath, reportInlineMath } from './math';\nimport {\n headingRenderMarkdown,\n paragraphMarkdownTokenizer,\n paragraphParseMarkdown,\n paragraphRenderMarkdown,\n} from './paragraphMarkdown';\nimport { ParagraphStyles } from './paragraphStyles';\n\n/**\n * StarterKit 默认 Code 的 excludes:'_' 禁止与任何其他 mark 共存。\n * CommonMark 允许 `**bold `code` bold**`;markdown 导入时会抛\n * RangeError: Invalid collection of marks for node text: bold,code。\n */\nconst InlineCode = Code.extend({\n excludes: '',\n});\n\n/**\n * 编辑器的「内容 schema 级」扩展集——纯节点/标记定义,不含任何 React NodeView\n * 或键盘交互绑定。三处共用:\n * 1. 编辑器(MarkdownWysiwygEditor):base + 交互增强版 CodeBlock/Image\n * 2. 只读预览(MarkdownPreview)\n * 3. server 端 markdown→HTML 渲染(renderReportHtml)\n *\n * 分层动机:交互增强依赖 @tiptap/react / 浏览器,会污染 server bundle(RSC)。\n * base 保持纯 schema,server import 它只引入节点定义,无 React 代码。\n *\n * 关键边界:CodeBlock / Image / CitationRef「会被客户端增强」,**不放进 base**——\n * 否则编辑器追加增强版会与 base 的纯版同名冲突(Tiptap 报 \"Duplicate extension names\")。\n * 改为:base 不含这三类,由调用方按需注入:\n * - 编辑器 / 预览注入「增强版」(React NodeView)\n * - server 注入「纯版」(pureCodeBlock / pureImage / CitationRef)\n */\n\n// lowlight 实例:代码块语法高亮。导出供编辑器增强版与 server 纯版共用同一实例。\nexport const lowlight = createLowlight(common);\n\n/**\n * 颜色 / 字号的 markdown 往返:markdown 没有原生颜色语法,序列化为行内 HTML\n * `<span style=\"...\">`(marked 支持行内 HTML,Tiptap 解析端经 parseHTML 还原成\n * TextStyle/Color/FontSize mark)。否则 getMarkdown() 会把这些 mark 静默剥掉,\n * 保存后再预览颜色丢失。\n *\n * 注意:Color / FontSize 通过 `types: [TextStyle.name]` 把 color / fontSize\n * 属性挂在 **textStyle** mark 的 attrs 上,文档里出现的 mark 类型名是\n * `textStyle`——所以 renderMarkdown 必须扩展在 TextStyle 上,序列化器才能按\n * mark 类型名查到 handler。\n */\nconst MarkdownTextStyle = TextStyle.extend({\n renderMarkdown(\n node: { attrs?: Record<string, unknown> },\n helpers: {\n renderChildren: (\n nodes: JSONContent | JSONContent[],\n separator?: string,\n ) => string;\n },\n ) {\n const { color, fontSize } = (node.attrs ?? {}) as {\n color?: string;\n fontSize?: string;\n };\n const styles: string[] = [];\n if (color) styles.push(`color:${color}`);\n if (fontSize) styles.push(`font-size:${fontSize}`);\n if (styles.length === 0) return '';\n // getMarkOpening 用占位符调用 renderChildren()(无需传节点),类型按签名兜底转换。\n const children = (helpers.renderChildren as () => string)();\n return `<span style=\"${styles.join(';')}\">${children}</span>`;\n },\n});\n\n/**\n * 认领一组行内 HTML 标签对(`<sup>…</sup>` / `<sub>…</sub>`)的 marked 行内\n * tokenizer。官方管线只把「没被扩展认领」的行内 HTML 交给 window.DOMParser,\n * 而 server 端没有 window 会把它转义成字面文本(见 renderReportHtml 的已知边界);\n * 自己认领后 SSR / Node 同样还原成 mark,且内层 markdown(`<sup>**x**</sup>`)\n * 照常解析。token 名与扩展名一致,序列化器按它查 parseMarkdown——同 CitationRef。\n */\nfunction htmlTagTokenizer(tag: string, tokenType: string): MarkdownTokenizer {\n const opening = new RegExp(`<${tag}(?:\\\\s[^>]*)?>`, 'i');\n const pair = new RegExp(\n `^<${tag}(?:\\\\s[^>]*)?>([\\\\s\\\\S]*?)<\\\\/${tag}\\\\s*>`,\n 'i',\n );\n return {\n name: tokenType,\n level: 'inline',\n start(src) {\n const match = opening.exec(src);\n return match ? match.index : -1;\n },\n tokenize(src, _tokens, lexer) {\n const match = pair.exec(src);\n if (!match) return undefined;\n return {\n type: tokenType,\n raw: match[0],\n tokens: lexer.inlineTokens(match[1]),\n };\n },\n };\n}\n\n/**\n * 上标 / 下标的 markdown 往返:markdown 无原生语法,序列化为行内 HTML\n * `<sup>` / `<sub>`(GFM 同样支持这两个标签)。\n *\n * 不加这层,getMarkdown() 会把这两个 mark 静默丢掉——@tiptap/markdown 对\n * 没有 renderMarkdown 的 mark 直接返回空串。renderMarkdown 同时被序列化器\n * 用作 mark 的开闭语法(getMarkOpening / getMarkClosing 用占位符切分),\n * 与 MarkdownTextStyle 的 span 是同一套机制。\n */\nconst MarkdownSuperscript = Superscript.extend({\n renderMarkdown(node: JSONContent, helpers: MarkdownRendererHelpers) {\n return `<sup>${helpers.renderChildren(node)}</sup>`;\n },\n markdownTokenizer: htmlTagTokenizer('sup', 'superscript'),\n parseMarkdown: (token: MarkdownToken, helpers: MarkdownParseHelpers) =>\n helpers.applyMark('superscript', helpers.parseInline(token.tokens ?? [])),\n});\n\nconst MarkdownSubscript = Subscript.extend({\n renderMarkdown(node: JSONContent, helpers: MarkdownRendererHelpers) {\n return `<sub>${helpers.renderChildren(node)}</sub>`;\n },\n markdownTokenizer: htmlTagTokenizer('sub', 'subscript'),\n parseMarkdown: (token: MarkdownToken, helpers: MarkdownParseHelpers) =>\n helpers.applyMark('subscript', helpers.parseInline(token.tokens ?? [])),\n});\n\n/**\n * 纯版代码块(无 React 视图):server / 预览用。\n * 顺带把 ```tmr-chart 围栏升级为 chart 节点(内置 code tokenizer 抢先时)。\n */\nexport const pureCodeBlock = CodeBlockLowlight.extend({\n parseMarkdown: (token, helpers) =>\n parseCodeTokenAsChartOrCodeBlock(token, helpers, 'codeBlock'),\n}).configure({ lowlight });\n\n/**\n * 纯版块级图片(无删除快捷键):server / 预览用。\n * inline:false(官方默认)——研报里图片均为大图独占一行,块级图片可直接作为 doc\n * 顶层子节点,避免「inline image 裸挂 doc 顶层」被 generateTocIds 严格校验判非法。\n *\n * markdown 往返接 imageMarkdown:带尺寸 / 对齐 / 描述(图注)的图序列化为\n * `<img …>` / `<figure>…</figure>`、解析时自建 tokenizer 认领——官方解析内联 HTML\n * 依赖 window.DOMParser,server 端没有 window,不认领会把它转义成字面文本\n * (见 imageMarkdown.ts 头注)。\n */\nexport const pureImage = Image.extend({\n addAttributes() {\n return {\n ...(Image.config.addAttributes?.call(this) ?? {}),\n align: imageAlignAttribute,\n caption: imageCaptionAttribute,\n };\n },\n parseHTML() {\n // figure 规则要排在 img 前面:带描述的图整体归 figure\n return [\n imageFigureParseRule(),\n {\n tag: this.options.allowBase64\n ? 'img[src]'\n : 'img[src]:not([src^=\"data:\"])',\n },\n ];\n },\n renderHTML({ node, HTMLAttributes }) {\n return imageNodeHtml({\n attrs: node.attrs,\n htmlAttributes: mergeAttributes(\n this.options.HTMLAttributes,\n HTMLAttributes,\n ),\n });\n },\n renderMarkdown: imageRenderMarkdown,\n parseMarkdown: imageParseMarkdown,\n markdownTokenizer: imageMarkdownTokenizer,\n}).configure({ inline: false });\n\nexport { pureChart, reportChart } from './chart/ChartExtension';\n\n/**\n * 段落 / 标题的 markdown 版本:带段落级样式(对齐 / 缩进 / 行高)时序列化为\n * `<p style=\"…\">` / `<hN style=\"…\">`,无样式保持原生形式(见 paragraphMarkdown.ts)。\n * StarterKit 里这两个节点要关掉,改用下面这份(同 CodeBlock / Image 的分层做法)。\n */\nexport const MarkdownParagraph = Paragraph.extend({\n renderMarkdown: paragraphRenderMarkdown,\n markdownTokenizer: paragraphMarkdownTokenizer,\n parseMarkdown: paragraphParseMarkdown,\n});\n\nexport const MarkdownHeading = Heading.extend({\n renderMarkdown: headingRenderMarkdown,\n});\n\n/**\n * 三处共用的纯 schema 扩展——**不含 CodeBlock / Image / CitationRef / Chart**(见上方边界说明)。\n * 编辑器:`[...baseExtensions, 增强CodeBlock, 增强Image, createCitationRef(), createChart(), Markdown]`\n * server/预览:`[...baseExtensions, pureCodeBlock, pureImage, CitationRef, pureChart, …]`\n */\nexport const baseExtensions: AnyExtension[] = [\n // 禁用 StarterKit 内置 codeBlock / code(改用 lowlight 代码块 + 可共存的 InlineCode)\n // 与 paragraph / heading(改用带 markdown 样式往返的版本,见上)\n StarterKit.configure({\n codeBlock: false,\n code: false,\n paragraph: false,\n heading: false,\n }),\n MarkdownParagraph,\n MarkdownHeading,\n // 段落级样式:文字对齐用官方扩展(免费);缩进 / 行高自研(官方无此扩展)。\n // 三者都往节点 style 上写片段,tiptap 的 mergeAttributes 对 style 做拼接合并。\n TextAlign.configure({ types: [MarkdownParagraph.name, MarkdownHeading.name] }),\n ParagraphStyles.configure({\n types: [MarkdownParagraph.name, MarkdownHeading.name],\n }),\n InlineCode,\n MarkdownTextStyle,\n Color.configure({ types: [TextStyle.name] }),\n // 正文字号:官方 FontSize(v3 起并入 text-style 包),以内联样式挂在 TextStyle\n // 的 <span> 上(如 style=\"font-size: 16px\"),与 Color 同基座,三端共用。\n FontSize.configure({ types: [TextStyle.name] }),\n Highlight.configure({ multicolor: true }),\n MarkdownSuperscript,\n MarkdownSubscript,\n TableKit.configure({\n table: {\n resizable: true,\n // SSR/renderHTML 默认不包 wrapper;阅读页无 NodeView 时宽表会被挤扁。\n // 与编辑器 TableView 的 `.tableWrapper` 对齐,静态 HTML 也可 overflow-x。\n renderWrapper: true,\n },\n }),\n TaskList,\n TaskItem.configure({ nested: true }),\n reportInlineMath,\n reportBlockMath,\n];\n","import { normalizeChartMarkdown } from './parse';\n\n/**\n * Unwrap `<div data-card=\"true\">…</div>` so comment↔table\n * adjacency survives for normalizeChartMarkdown.\n */\nfunction unwrapDataCardDivs(markdown: string): string {\n return markdown.replace(\n /<div\\s+data-card=([\"']?)true\\1\\s*>\\s*([\\s\\S]*?)\\s*<\\/div>/gi,\n '\\n$2\\n',\n );\n}\n\n/**\n * Prepare markdown before TipTap / MarkdownManager parse:\n * unwrap data-card wrappers, then collapse `<!-- chart -->` + GFM table\n * pairs into ```tmr-chart fences.\n */\nexport function prepareChartMarkdown(markdown: string): string {\n return normalizeChartMarkdown(unwrapDataCardDivs(markdown ?? ''));\n}\n","/**\n * 目录锚点 id 生成——阅读页(SSR)与编辑页(editor)共用的**单一真源**,\n * 保证「创作预览的锚点 = 发布后阅读页的锚点」。\n *\n * 用 slug 而非官方默认 UUID:slug 跨 SSR / ISR revalidate 稳定(UUID 每次都变、\n * 分享的 #hash 会失效),且 `#introduction` 比 `#d4590f81-…` 可读、对 SEO 友好。\n *\n * slug 会重名(两个「细节」都 slug 成 `xi-jie`),故用闭包计数器去重:\n * 同名追加 -2 / -3(已实测:details / details-2 / details-3,HTML id 全唯一)。\n */\n\n/** 单个标题文本 → 基础 slug(保留中文,去标点,空白转连字符)。 */\nfunction baseSlug(text: string): string {\n return (\n text\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, '-')\n // 保留字母/数字/下划线/中文/连字符,其余剔除\n .replace(/[^\\w一-龥-]/g, '')\n .replace(/^-+|-+$/g, '') || 'section'\n );\n}\n\n/**\n * 造一个带去重的 `getId`。每次生成新实例(闭包各自计数),传给\n * `TableOfContents.configure({ getId })` 或 `generateTocIds` 的扩展配置。\n */\nexport function makeTocGetId(): (content: string) => string {\n const seen = new Map<string, number>();\n return (content: string) => {\n const base = baseSlug(content);\n const n = (seen.get(base) ?? 0) + 1;\n seen.set(base, n);\n return n === 1 ? base : `${base}-${n}`;\n };\n}\n","/**\n * 给流式半成品 markdown 补闭合围栏,避免未结束的 ``` 把后文吞进 code。\n * 完整稿不要调用(ISR / 已落库卡)。\n */\nexport function stabilizeMarkdown(markdown: string): string {\n if (!markdown) return markdown;\n\n let inFence = false;\n let fenceChar = '`';\n let fenceLen = 3;\n\n for (const line of markdown.split('\\n')) {\n const match = line.match(/^(`{3,}|~{3,})/);\n if (!match) continue;\n const marker = match[1];\n const char = marker[0];\n if (!inFence) {\n inFence = true;\n fenceChar = char;\n fenceLen = marker.length;\n continue;\n }\n if (char === fenceChar && marker.length >= fenceLen && /^[`~]+\\s*$/.test(line)) {\n inFence = false;\n }\n }\n\n if (!inFence) return markdown;\n const closer = fenceChar.repeat(fenceLen);\n return markdown.endsWith('\\n') ? `${markdown}${closer}` : `${markdown}\\n${closer}`;\n}\n","/**\n * 最小 Tiptap JSON 节点结构(只取本模块用到的字段)。\n * 不从 `@tiptap/core` 引 `JSONContent`——core 是嵌套依赖、非直接依赖,\n * 直接 import 类型解析不到(与仓库既有做法一致,见 extensions.ts)。\n */\ninterface TocDocNode {\n type?: string;\n text?: string;\n attrs?: Record<string, unknown> | null;\n content?: TocDocNode[];\n}\n\n/** 目录项。 */\nexport interface TocItem {\n /** 锚点 id(= heading 的 data-toc-id / id,由 generateTocIds 注入)。 */\n id: string;\n /** 标题层级(1-6)。 */\n level: number;\n /** 标题纯文本。 */\n text: string;\n /** 付费墙锁住的章节(置灰不可点)。 */\n locked?: boolean;\n}\n\n/** 目录纳入的最大层级(h1-h6,全层级入目录)。 */\nconst MAX_LEVEL = 6;\n\n/** 取 heading 节点的纯文本(拼接其 text 子节点)。 */\nfunction headingText(node: TocDocNode): string {\n if (!node.content) return '';\n return node.content\n .map((c) => (c.type === 'text' ? c.text ?? '' : ''))\n .join('')\n .trim();\n}\n\n/**\n * 从已注入锚点 id 的 Tiptap JSON doc 提取 h1-h6 目录。\n *\n * 必须在 `generateTocIds` 之后调用(heading 的 attrs 里才有 `data-toc-id`)。\n * `lockedTitles`:被截断(锁住)章节标题,命中则标 `locked`——\n * 目录列全部章节,锁住项置灰不可点(付费墙钩子)。用 Set 便于去重命中。\n */\nexport function extractToc(\n doc: TocDocNode,\n lockedTitles: string[] = [],\n): TocItem[] {\n const locked = new Set(lockedTitles.map((t) => t.trim()));\n const items: TocItem[] = [];\n\n const walk = (node: TocDocNode) => {\n const level = node.attrs?.level;\n if (\n node.type === 'heading' &&\n typeof level === 'number' &&\n level <= MAX_LEVEL\n ) {\n const text = headingText(node);\n const id = (node.attrs?.['data-toc-id'] ?? node.attrs?.id) as\n | string\n | undefined;\n // 有文本 + 有锚点 id 才入目录(空标题 / 未注入 id 的跳过)。\n if (text && id) {\n items.push({\n id,\n level,\n text,\n locked: locked.has(text) || undefined,\n });\n }\n }\n node.content?.forEach(walk);\n };\n\n walk(doc);\n return items;\n}\n"],"names":["encodeAttr"],"mappings":"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"}