tiptap-markdown-react 0.6.3 → 0.7.1

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.
package/dist/labels.d.ts CHANGED
@@ -61,3 +61,13 @@ export interface CodeBlockLabels {
61
61
  delete: string;
62
62
  }
63
63
  export declare const defaultCodeBlockLabels: CodeBlockLabels;
64
+ export interface CommentLabels {
65
+ open: string;
66
+ resolved: string;
67
+ dismissed: string;
68
+ outdated: string;
69
+ ambiguous: string;
70
+ partial: string;
71
+ gutterTitle: string;
72
+ }
73
+ export declare const defaultCommentLabels: CommentLabels;
package/dist/server.d.ts CHANGED
@@ -4,6 +4,8 @@
4
4
  */
5
5
  export { baseExtensions, lowlight, pureCodeBlock, pureImage, } from './extensions';
6
6
  export { CitationRef } from './CitationRef';
7
+ export { CommentMark, type CommentMarkOptions, type CommentInterval } from './commentAnchor/CommentMark';
8
+ export { mapCommentAnchors, mergeCommentIntervals, blockTextHash, type CommentSegment, type CommentAnchorInput, type CommentAnchorResult, type CommentAnchorStatus, type CommentRange, } from './commentAnchor/commentMapper';
7
9
  export { applyCitationSources, enrichMarkdownCitations, type SourceRef, } from './citationUtils';
8
10
  export { ReportContent, type ReportContentProps } from './ReportContent';
9
11
  export { renderReportHtml, type RenderedReport, type RenderReportHtmlOptions, } from './renderReportHtml';
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { c as applyCitationSources, b as baseExtensions, p as pureCodeBlock, a as pureImage, C as CitationRef, m as makeTocGetId, d as extractToc } from "./extractToc-DknI9ylT.js";
2
- import { R, e, l } from "./extractToc-DknI9ylT.js";
1
+ import { g as applyCitationSources, b as baseExtensions, p as pureCodeBlock, f as pureImage, C as CitationRef, d as makeTocGetId, i as extractToc } from "./extractToc-AUH9u6o-.js";
2
+ import { c, R, h, e, l, a, m } from "./extractToc-AUH9u6o-.js";
3
3
  import { TableOfContents, generateTocIds } from "@tiptap/extension-table-of-contents";
4
4
  import { MarkdownManager } from "@tiptap/markdown";
5
5
  import { renderToHTMLString } from "@tiptap/static-renderer";
@@ -42,13 +42,17 @@ function renderReportHtml(markdown, lockedTitlesOrOptions = []) {
42
42
  }
43
43
  export {
44
44
  CitationRef,
45
+ c as CommentMark,
45
46
  R as ReportContent,
46
47
  applyCitationSources,
47
48
  baseExtensions,
49
+ h as blockTextHash,
48
50
  e as enrichMarkdownCitations,
49
51
  extractToc,
50
52
  l as lowlight,
51
53
  makeTocGetId,
54
+ a as mapCommentAnchors,
55
+ m as mergeCommentIntervals,
52
56
  pureCodeBlock,
53
57
  pureImage,
54
58
  renderReportHtml
package/dist/style.css CHANGED
@@ -308,7 +308,7 @@
308
308
  color: var(--tmr-citation-fg-hover, #ffffff);
309
309
  }
310
310
  /* 代码块 NodeView:白底、细边框、顶部 header 放语言选择(Radix 下拉)+ 删除。 */
311
- ._wrapper_2dv2g_2 {
311
+ ._wrapper_5i2vi_2 {
312
312
  position: relative;
313
313
  margin: 0.9em 0;
314
314
  border: 1px solid #e8e8e8;
@@ -318,13 +318,13 @@
318
318
  }
319
319
 
320
320
  /* 选中整个代码块时(NodeSelection):accent 边框高亮,作为删除前的二次确认提示 */
321
- ._wrapper_2dv2g_2.ProseMirror-selectednode,
322
- .ProseMirror-selectednode > ._wrapper_2dv2g_2 {
321
+ ._wrapper_5i2vi_2.ProseMirror-selectednode,
322
+ .ProseMirror-selectednode > ._wrapper_5i2vi_2 {
323
323
  border-color: var(--tmr-accent, #ff6719);
324
324
  box-shadow: 0 0 0 1px var(--tmr-accent, #ff6719);
325
325
  }
326
326
 
327
- ._header_2dv2g_18 {
327
+ ._header_5i2vi_18 {
328
328
  display: flex;
329
329
  align-items: center;
330
330
  justify-content: flex-end;
@@ -334,7 +334,7 @@
334
334
  }
335
335
 
336
336
  /* 语言选择触发按钮:无边框胶囊,hover 出灰底,右侧箭头图标 */
337
- ._langTrigger_2dv2g_28 {
337
+ ._langTrigger_5i2vi_28 {
338
338
  display: inline-flex;
339
339
  align-items: center;
340
340
  gap: 4px;
@@ -351,18 +351,33 @@
351
351
  transition: background 0.15s;
352
352
  }
353
353
 
354
- ._langTrigger_2dv2g_28:hover,
355
- ._langTrigger_2dv2g_28[data-state='open'] {
354
+ ._langTrigger_5i2vi_28:hover,
355
+ ._langTrigger_5i2vi_28[data-state='open'] {
356
356
  background-color: #f0f0f0;
357
357
  }
358
358
 
359
- ._langChevron_2dv2g_50 {
359
+ ._langChevron_5i2vi_50 {
360
360
  color: #8a8a8a;
361
361
  flex-shrink: 0;
362
362
  }
363
363
 
364
+ /* 只读态语言徽标:无下拉 / 删除交互,样式对齐 langTrigger 但不可点 */
365
+ ._langBadge_5i2vi_56 {
366
+ display: inline-flex;
367
+ align-items: center;
368
+ padding: 3px 10px;
369
+ margin: 8px 12px;
370
+ border-radius: 8px;
371
+ background: #f0f0f0;
372
+ color: #6b7280;
373
+ font-size: 13px;
374
+ font-weight: 500;
375
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
376
+ user-select: none;
377
+ }
378
+
364
379
  /* 下拉菜单气泡:白底圆角、细边框、轻阴影,最大高度可滚动 */
365
- ._langMenu_2dv2g_56 {
380
+ ._langMenu_5i2vi_71 {
366
381
  z-index: 50;
367
382
  min-width: 160px;
368
383
  max-height: 280px;
@@ -375,7 +390,7 @@
375
390
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
376
391
  }
377
392
 
378
- ._langItem_2dv2g_69 {
393
+ ._langItem_5i2vi_84 {
379
394
  display: flex;
380
395
  align-items: center;
381
396
  gap: 6px;
@@ -390,16 +405,16 @@
390
405
  }
391
406
 
392
407
  /* 键盘方向键 / 鼠标 hover 高亮态(Radix 用 data-highlighted 标记) */
393
- ._langItem_2dv2g_69[data-highlighted] {
408
+ ._langItem_5i2vi_84[data-highlighted] {
394
409
  background-color: #f0f0f0;
395
410
  }
396
411
 
397
- ._langItemSelected_2dv2g_88 {
412
+ ._langItemSelected_5i2vi_103 {
398
413
  color: var(--tmr-accent, #ff6719);
399
414
  font-weight: 600;
400
415
  }
401
416
 
402
- ._langItemCheck_2dv2g_93 {
417
+ ._langItemCheck_5i2vi_108 {
403
418
  display: inline-flex;
404
419
  align-items: center;
405
420
  justify-content: center;
@@ -407,7 +422,7 @@
407
422
  flex-shrink: 0;
408
423
  }
409
424
 
410
- ._deleteBtn_2dv2g_101 {
425
+ ._deleteBtn_5i2vi_116 {
411
426
  display: inline-flex;
412
427
  align-items: center;
413
428
  justify-content: center;
@@ -422,12 +437,12 @@
422
437
  transition: background 0.15s, color 0.15s;
423
438
  }
424
439
 
425
- ._deleteBtn_2dv2g_101:hover {
440
+ ._deleteBtn_5i2vi_116:hover {
426
441
  background: #f4f4f4;
427
442
  color: #d4380d;
428
443
  }
429
444
 
430
- ._pre_2dv2g_121 {
445
+ ._pre_5i2vi_136 {
431
446
  margin: 0;
432
447
  padding: 16px 18px;
433
448
  background: transparent;
@@ -438,7 +453,7 @@
438
453
  line-height: 1.65;
439
454
  }
440
455
 
441
- ._pre_2dv2g_121 code {
456
+ ._pre_5i2vi_136 code {
442
457
  display: block;
443
458
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
444
459
  color: #24292e;
@@ -450,45 +465,45 @@
450
465
  }
451
466
 
452
467
  /* 语法高亮配色(lowlight / highlight.js token,GitHub 浅色主题) */
453
- ._pre_2dv2g_121 .hljs-comment,
454
- ._pre_2dv2g_121 .hljs-quote {
468
+ ._pre_5i2vi_136 .hljs-comment,
469
+ ._pre_5i2vi_136 .hljs-quote {
455
470
  color: #6a737d;
456
471
  font-style: italic;
457
472
  }
458
473
 
459
- ._pre_2dv2g_121 .hljs-keyword,
460
- ._pre_2dv2g_121 .hljs-selector-tag,
461
- ._pre_2dv2g_121 .hljs-literal,
462
- ._pre_2dv2g_121 .hljs-type {
474
+ ._pre_5i2vi_136 .hljs-keyword,
475
+ ._pre_5i2vi_136 .hljs-selector-tag,
476
+ ._pre_5i2vi_136 .hljs-literal,
477
+ ._pre_5i2vi_136 .hljs-type {
463
478
  color: #d73a49;
464
479
  }
465
480
 
466
- ._pre_2dv2g_121 .hljs-string,
467
- ._pre_2dv2g_121 .hljs-meta .hljs-string,
468
- ._pre_2dv2g_121 .hljs-regexp {
481
+ ._pre_5i2vi_136 .hljs-string,
482
+ ._pre_5i2vi_136 .hljs-meta .hljs-string,
483
+ ._pre_5i2vi_136 .hljs-regexp {
469
484
  color: #032f62;
470
485
  }
471
486
 
472
- ._pre_2dv2g_121 .hljs-number,
473
- ._pre_2dv2g_121 .hljs-built_in,
474
- ._pre_2dv2g_121 .hljs-builtin-name {
487
+ ._pre_5i2vi_136 .hljs-number,
488
+ ._pre_5i2vi_136 .hljs-built_in,
489
+ ._pre_5i2vi_136 .hljs-builtin-name {
475
490
  color: #005cc5;
476
491
  }
477
492
 
478
- ._pre_2dv2g_121 .hljs-title,
479
- ._pre_2dv2g_121 .hljs-function .hljs-title,
480
- ._pre_2dv2g_121 .hljs-section {
493
+ ._pre_5i2vi_136 .hljs-title,
494
+ ._pre_5i2vi_136 .hljs-function .hljs-title,
495
+ ._pre_5i2vi_136 .hljs-section {
481
496
  color: #6f42c1;
482
497
  }
483
498
 
484
- ._pre_2dv2g_121 .hljs-attr,
485
- ._pre_2dv2g_121 .hljs-attribute,
486
- ._pre_2dv2g_121 .hljs-variable,
487
- ._pre_2dv2g_121 .hljs-template-variable {
499
+ ._pre_5i2vi_136 .hljs-attr,
500
+ ._pre_5i2vi_136 .hljs-attribute,
501
+ ._pre_5i2vi_136 .hljs-variable,
502
+ ._pre_5i2vi_136 .hljs-template-variable {
488
503
  color: #e36209;
489
504
  }
490
505
 
491
- ._pre_2dv2g_121 .hljs-tag {
506
+ ._pre_5i2vi_136 .hljs-tag {
492
507
  color: #22863a;
493
508
  }
494
509
  /* 顶部操作栏:横跨宽度、内容居中、细线灰图标。配色映射到可覆盖的 --tmr-* 变量。 */
@@ -1035,3 +1050,84 @@
1035
1050
  transition: none;
1036
1051
  }
1037
1052
  }
1053
+ /* 评论锚定样式(编辑会话专属,只读态不渲染)。
1054
+ 全部走 :global + --tmr-* 变量,与库其它样式约定一致。 */
1055
+
1056
+ /* 评论锚定:仅黄色边框,无背景填充(不打扰正文阅读)。 */
1057
+ .tmr-comment {
1058
+ border-radius: 3px;
1059
+ padding: 0 1px;
1060
+ cursor: default;
1061
+ box-shadow: 0 0 0 1.5px var(--tmr-comment-ring, rgba(219, 171, 10, 0.75));
1062
+ box-decoration-break: clone;
1063
+ -webkit-box-decoration-break: clone;
1064
+ transition: box-shadow 0.12s ease;
1065
+ }
1066
+
1067
+ .tmr-comment:hover {
1068
+ box-shadow: 0 0 0 2px var(--tmr-comment-ring, rgba(219, 171, 10, 0.9));
1069
+ }
1070
+
1071
+ /* active:侧栏点评论后的强调态(加粗边框,仍无背景) */
1072
+ .tmr-comment.tmr-comment-active {
1073
+ box-shadow: 0 0 0 2.5px var(--tmr-comment-ring, rgba(191, 121, 0, 0.95));
1074
+ }
1075
+
1076
+ /* active 评论所在 block 的外框 */
1077
+ .tmr-comment-block-active {
1078
+ box-shadow: 0 0 0 3px var(--tmr-comment-ring, rgba(219, 171, 10, 0.55));
1079
+ border-radius: 4px;
1080
+ }
1081
+
1082
+ /* block 左缘 gutter 气泡(Decoration.widget,side:-1 前置) */
1083
+ .tmr-comment-gutter {
1084
+ position: absolute;
1085
+ left: -30px;
1086
+ top: 50%;
1087
+ transform: translateY(-50%);
1088
+ min-width: 18px;
1089
+ height: 18px;
1090
+ padding: 0 4px;
1091
+ box-sizing: border-box;
1092
+ display: inline-flex;
1093
+ align-items: center;
1094
+ justify-content: center;
1095
+ border-radius: 999px;
1096
+ background: var(--tmr-comment-gutter-bg, #f4b400);
1097
+ color: #fff;
1098
+ font-size: 11px;
1099
+ font-weight: 600;
1100
+ line-height: 1;
1101
+ cursor: pointer;
1102
+ user-select: none;
1103
+ }
1104
+
1105
+ .tmr-comment-gutter:hover {
1106
+ background: var(--tmr-comment-gutter-bg-hover, #dd9f00);
1107
+ }
1108
+
1109
+ ._popoverAnchor_1ceh7_57 {
1110
+ position: fixed;
1111
+ width: 0;
1112
+ height: 0;
1113
+ pointer-events: none;
1114
+ }
1115
+
1116
+ ._popoverContent_1ceh7_64 {
1117
+ min-width: 320px;
1118
+ max-width: 420px;
1119
+ background: var(--tmr-popover-bg, #fff);
1120
+ border: 1px solid var(--tmr-border, #e4e2dd);
1121
+ border-radius: 8px;
1122
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
1123
+ padding: 12px 14px;
1124
+ font-family: var(--tmr-body-font, inherit);
1125
+ font-size: 13px;
1126
+ line-height: 1.55;
1127
+ color: var(--tmr-text, #363737);
1128
+ outline: none;
1129
+ }
1130
+
1131
+ ._popoverContent_1ceh7_64 .tmr-popover-arrow {
1132
+ fill: var(--tmr-popover-bg, #fff);
1133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiptap-markdown-react",
3
- "version": "0.6.3",
3
+ "version": "0.7.1",
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, zero Ant Design.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,260 +0,0 @@
1
- import { Node, mergeAttributes } from "@tiptap/core";
2
- import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
3
- import Highlight from "@tiptap/extension-highlight";
4
- import Image from "@tiptap/extension-image";
5
- import Subscript from "@tiptap/extension-subscript";
6
- import Superscript from "@tiptap/extension-superscript";
7
- import { TableKit } from "@tiptap/extension-table";
8
- import TaskItem from "@tiptap/extension-task-item";
9
- import TaskList from "@tiptap/extension-task-list";
10
- import { TextStyle, Color, FontSize } from "@tiptap/extension-text-style";
11
- import StarterKit from "@tiptap/starter-kit";
12
- import { createLowlight, common } from "lowlight";
13
- import { jsx } from "react/jsx-runtime";
14
- function escapeAttr(value) {
15
- return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16
- }
17
- function enrichMarkdownCitations(markdown, sources) {
18
- if (!sources.length) return markdown;
19
- return markdown.replace(/\[\^(\d+)\]/g, (match, num) => {
20
- const source = sources.find((s) => s.index === num);
21
- if (!source) return match;
22
- const attrs = [`class="citation-ref"`, `data-index="${num}"`];
23
- if (source.url) attrs.push(`data-url="${escapeAttr(source.url)}"`);
24
- if (source.title) attrs.push(`data-title="${escapeAttr(source.title)}"`);
25
- if (source.url) {
26
- return `<span ${attrs.join(" ")}><a href="${escapeAttr(source.url)}" title="${escapeAttr(source.title || "")}" target="_blank" rel="noopener">${num}</a></span>`;
27
- }
28
- return `<span ${attrs.join(" ")}>${num}</span>`;
29
- });
30
- }
31
- function patchCitationNode(node, byIndex) {
32
- var _a, _b, _c, _d;
33
- if (node.type === "citationRef") {
34
- const index = String(((_a = node.attrs) == null ? void 0 : _a.index) ?? "");
35
- const source = byIndex.get(index);
36
- if (!source) return node;
37
- return {
38
- ...node,
39
- attrs: {
40
- ...node.attrs,
41
- index,
42
- url: source.url ?? ((_b = node.attrs) == null ? void 0 : _b.url) ?? null,
43
- title: source.title ?? ((_c = node.attrs) == null ? void 0 : _c.title) ?? null
44
- }
45
- };
46
- }
47
- if (!((_d = node.content) == null ? void 0 : _d.length)) return node;
48
- return {
49
- ...node,
50
- content: node.content.map((child) => patchCitationNode(child, byIndex))
51
- };
52
- }
53
- function applyCitationSources(doc, sources) {
54
- if (!sources.length) return doc;
55
- const byIndex = new Map(sources.map((s) => [s.index, s]));
56
- return patchCitationNode(doc, byIndex);
57
- }
58
- const CitationRef = Node.create({
59
- name: "citationRef",
60
- group: "inline",
61
- inline: true,
62
- atom: true,
63
- selectable: true,
64
- // 高于普通链接,确保 `[^1]` 不被拆成残缺 link
65
- priority: 1e3,
66
- addOptions() {
67
- return { HTMLAttributes: {} };
68
- },
69
- addAttributes() {
70
- return {
71
- index: {
72
- default: null,
73
- parseHTML: (element) => element.getAttribute("data-index"),
74
- renderHTML: (attributes) => {
75
- if (!attributes.index) return {};
76
- return { "data-index": attributes.index };
77
- }
78
- },
79
- url: {
80
- default: null,
81
- parseHTML: (element) => element.getAttribute("data-url"),
82
- renderHTML: (attributes) => {
83
- if (!attributes.url) return {};
84
- return { "data-url": attributes.url };
85
- }
86
- },
87
- title: {
88
- default: null,
89
- parseHTML: (element) => element.getAttribute("data-title"),
90
- renderHTML: (attributes) => {
91
- if (!attributes.title) return {};
92
- return { "data-title": attributes.title };
93
- }
94
- }
95
- };
96
- },
97
- parseHTML() {
98
- return [{ tag: "span.citation-ref" }];
99
- },
100
- renderHTML({ node, HTMLAttributes }) {
101
- const index = String(node.attrs.index ?? "");
102
- const url = node.attrs.url;
103
- const title = node.attrs.title || "";
104
- const attrs = mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
105
- class: "citation-ref"
106
- });
107
- if (url) {
108
- return [
109
- "span",
110
- attrs,
111
- [
112
- "a",
113
- {
114
- href: url,
115
- title,
116
- target: "_blank",
117
- rel: "noopener noreferrer"
118
- },
119
- index
120
- ]
121
- ];
122
- }
123
- return ["span", attrs, index];
124
- },
125
- renderMarkdown(node) {
126
- var _a;
127
- return `[^${((_a = node == null ? void 0 : node.attrs) == null ? void 0 : _a.index) ?? ""}]`;
128
- },
129
- parseMarkdown: (token, helpers) => {
130
- return helpers.createNode("citationRef", {
131
- index: String(token.index ?? ""),
132
- url: token.url ?? null,
133
- title: token.title ?? null
134
- });
135
- },
136
- markdownTokenizer: {
137
- name: "citationRef",
138
- level: "inline",
139
- start(src) {
140
- const match = /\[\^\d+\]/.exec(src);
141
- return (match == null ? void 0 : match.index) ?? -1;
142
- },
143
- tokenize(src) {
144
- const match = /^\[\^(\d+)\]/.exec(src);
145
- if (!match) return void 0;
146
- return {
147
- type: "citationRef",
148
- raw: match[0],
149
- index: match[1]
150
- };
151
- }
152
- },
153
- addCommands() {
154
- return {
155
- insertCitationRef: (attrs) => ({ commands }) => commands.insertContent({
156
- type: this.name,
157
- attrs: {
158
- index: attrs.index,
159
- url: attrs.url ?? null,
160
- title: attrs.title ?? null
161
- }
162
- })
163
- };
164
- }
165
- });
166
- const lowlight = createLowlight(common);
167
- const pureCodeBlock = CodeBlockLowlight.configure({ lowlight });
168
- const pureImage = Image.configure({ inline: false });
169
- const baseExtensions = [
170
- // 禁用 StarterKit 内置 codeBlock,统一改用带 lowlight 的代码块(由调用方注入)
171
- StarterKit.configure({ codeBlock: false }),
172
- TextStyle,
173
- Color.configure({ types: [TextStyle.name] }),
174
- // 正文字号:官方 FontSize(v3 起并入 text-style 包),以内联样式挂在 TextStyle
175
- // 的 <span> 上(如 style="font-size: 16px"),与 Color 同基座,三端共用。
176
- FontSize.configure({ types: [TextStyle.name] }),
177
- Highlight.configure({ multicolor: true }),
178
- Superscript,
179
- Subscript,
180
- TableKit.configure({
181
- table: {
182
- resizable: true,
183
- // SSR/renderHTML 默认不包 wrapper;阅读页无 NodeView 时宽表会被挤扁。
184
- // 与编辑器 TableView 的 `.tableWrapper` 对齐,静态 HTML 也可 overflow-x。
185
- renderWrapper: true
186
- }
187
- }),
188
- TaskList,
189
- TaskItem.configure({ nested: true })
190
- ];
191
- const editorScroll = "_editorScroll_q3j4s_4";
192
- const editorContent = "_editorContent_q3j4s_8";
193
- const styles = {
194
- editorScroll,
195
- editorContent
196
- };
197
- function baseSlug(text) {
198
- return text.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^\w一-龥-]/g, "").replace(/^-+|-+$/g, "") || "section";
199
- }
200
- function makeTocGetId() {
201
- const seen = /* @__PURE__ */ new Map();
202
- return (content) => {
203
- const base = baseSlug(content);
204
- const n = (seen.get(base) ?? 0) + 1;
205
- seen.set(base, n);
206
- return n === 1 ? base : `${base}-${n}`;
207
- };
208
- }
209
- function ReportContent({ html, className, ...rest }) {
210
- return /* @__PURE__ */ jsx(
211
- "div",
212
- {
213
- ...rest,
214
- className: className ? `${styles.editorContent} ${className}` : styles.editorContent,
215
- dangerouslySetInnerHTML: { __html: html }
216
- }
217
- );
218
- }
219
- const MAX_LEVEL = 6;
220
- function headingText(node) {
221
- if (!node.content) return "";
222
- return node.content.map((c) => c.type === "text" ? c.text ?? "" : "").join("").trim();
223
- }
224
- function extractToc(doc, lockedTitles = []) {
225
- const locked = new Set(lockedTitles.map((t) => t.trim()));
226
- const items = [];
227
- const walk = (node) => {
228
- var _a, _b, _c, _d;
229
- const level = (_a = node.attrs) == null ? void 0 : _a.level;
230
- if (node.type === "heading" && typeof level === "number" && level <= MAX_LEVEL) {
231
- const text = headingText(node);
232
- const id = ((_b = node.attrs) == null ? void 0 : _b["data-toc-id"]) ?? ((_c = node.attrs) == null ? void 0 : _c.id);
233
- if (text && id) {
234
- items.push({
235
- id,
236
- level,
237
- text,
238
- locked: locked.has(text) || void 0
239
- });
240
- }
241
- }
242
- (_d = node.content) == null ? void 0 : _d.forEach(walk);
243
- };
244
- walk(doc);
245
- return items;
246
- }
247
- export {
248
- CitationRef as C,
249
- ReportContent as R,
250
- pureImage as a,
251
- baseExtensions as b,
252
- applyCitationSources as c,
253
- extractToc as d,
254
- enrichMarkdownCitations as e,
255
- lowlight as l,
256
- makeTocGetId as m,
257
- pureCodeBlock as p,
258
- styles as s
259
- };
260
- //# sourceMappingURL=extractToc-DknI9ylT.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extractToc-DknI9ylT.js","sources":["../src/citationUtils.ts","../src/CitationRef.ts","../src/extensions.ts","../src/toc/tocSlug.ts","../src/ReportContent.tsx","../src/toc/extractToc.ts"],"sourcesContent":["import type { JSONContent } from '@tiptap/core';\n\nexport interface SourceRef {\n /** 与 markdown `[^n]` 中的 n 对齐(字符串,如 `\"1\"`)。 */\n index: string;\n url?: string;\n title?: string;\n /** 原文片段等;库本身不渲染 Popover,留给消费方。 */\n excerpt?: string;\n}\n\nfunction escapeAttr(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/**\n * 将 markdown 中能匹配到 `sources` 的 `[^n]` 换成带 data-* 的\n * `<span class=\"citation-ref\">`(**不是** `<sup>`,避免被 Superscript 吃掉、\n * 也避免视觉上标)。未匹配的 `[^n]` 原样保留,留给 CitationRef tokenizer。\n *\n * 浏览器端 @tiptap/markdown 可解析内联 HTML;server 端无 DOMParser 时请改用\n * {@link applyCitationSources}(先 parse 再补 attrs)。\n */\nexport function enrichMarkdownCitations(\n markdown: string,\n sources: SourceRef[],\n): string {\n if (!sources.length) return markdown;\n\n return markdown.replace(/\\[\\^(\\d+)\\]/g, (match, num: string) => {\n const source = sources.find((s) => s.index === num);\n if (!source) return match;\n\n const attrs = [`class=\"citation-ref\"`, `data-index=\"${num}\"`];\n if (source.url) attrs.push(`data-url=\"${escapeAttr(source.url)}\"`);\n if (source.title) attrs.push(`data-title=\"${escapeAttr(source.title)}\"`);\n\n if (source.url) {\n return `<span ${attrs.join(' ')}><a href=\"${escapeAttr(source.url)}\" title=\"${escapeAttr(source.title || '')}\" target=\"_blank\" rel=\"noopener\">${num}</a></span>`;\n }\n return `<span ${attrs.join(' ')}>${num}</span>`;\n });\n}\n\nfunction patchCitationNode(\n node: JSONContent,\n byIndex: Map<string, SourceRef>,\n): JSONContent {\n if (node.type === 'citationRef') {\n const index = String(node.attrs?.index ?? '');\n const source = byIndex.get(index);\n if (!source) return node;\n return {\n ...node,\n attrs: {\n ...node.attrs,\n index,\n url: source.url ?? node.attrs?.url ?? null,\n title: source.title ?? node.attrs?.title ?? null,\n },\n };\n }\n\n if (!node.content?.length) return node;\n return {\n ...node,\n content: node.content.map((child) => patchCitationNode(child, byIndex)),\n };\n}\n\n/**\n * 在已 parse 的 Tiptap JSON 上,按 `sources` 给 `citationRef` 节点补 url/title。\n * SSR / 无 DOMParser 环境的首选路径。\n */\nexport function applyCitationSources(\n doc: JSONContent,\n sources: SourceRef[],\n): JSONContent {\n if (!sources.length) return doc;\n const byIndex = new Map(sources.map((s) => [s.index, s]));\n return patchCitationNode(doc, byIndex);\n}\n","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 CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';\nimport Highlight from '@tiptap/extension-highlight';\nimport Image from '@tiptap/extension-image';\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 { Color, FontSize, TextStyle } from '@tiptap/extension-text-style';\n// AnyExtension 从 @tiptap/react 取(它 re-export 自 core),避免新增 @tiptap/core 直接依赖\nimport type { AnyExtension } from '@tiptap/react';\nimport StarterKit from '@tiptap/starter-kit';\nimport { common, createLowlight } from 'lowlight';\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/** 纯版代码块(无 React 视图):server / 预览用,产出带高亮 class 的静态结构。 */\nexport const pureCodeBlock = CodeBlockLowlight.configure({ lowlight });\n\n/**\n * 纯版块级图片(无删除快捷键):server / 预览用。\n * inline:false(官方默认)——研报里图片均为大图独占一行,块级图片可直接作为 doc\n * 顶层子节点,避免「inline image 裸挂 doc 顶层」被 generateTocIds 严格校验判非法。\n */\nexport const pureImage = Image.configure({ inline: false });\n\n/**\n * 三处共用的纯 schema 扩展——**不含 CodeBlock / Image / CitationRef**(见上方边界说明)。\n * 编辑器:`[...baseExtensions, 增强CodeBlock, 增强Image, createCitationRef(), Markdown]`\n * server/预览:`[...baseExtensions, pureCodeBlock, pureImage, CitationRef, …]`\n */\nexport const baseExtensions: AnyExtension[] = [\n // 禁用 StarterKit 内置 codeBlock,统一改用带 lowlight 的代码块(由调用方注入)\n StarterKit.configure({ codeBlock: false }),\n TextStyle,\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 Superscript,\n Subscript,\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];\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","import type { HTMLAttributes } from 'react';\nimport styles from './styles/content.module.css';\n\nexport interface ReportContentProps extends HTMLAttributes<HTMLDivElement> {\n /** `renderReportHtml(...).html` 产出的正文 HTML 字符串。 */\n html: string;\n}\n\n/**\n * 只读静态正文渲染(RSC / SSR 安全,无 client 代码、无编辑器实例)。\n *\n * 把 `renderReportHtml` 产出的 HTML 注入容器,并套上与编辑器 / 只读预览**同一个\n * 规范正文类**,保证「编辑所见 = 预览所见 = 发布后读者所见」。\n * 用于阅读页首屏直出(SEO 可见),无需 JS 即可显示。\n */\nexport function ReportContent({ html, className, ...rest }: ReportContentProps) {\n return (\n <div\n {...rest}\n className={\n className ? `${styles.editorContent} ${className}` : styles.editorContent\n }\n dangerouslySetInnerHTML={{ __html: html }}\n />\n );\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":[],"mappings":"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"}