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
package/dist/labels.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  /**
2
- * UI 文案(i18n 注入点)。各组件接收 `labels?: Partial<...>`,与内置英文默认合并。
3
- * 消费方(如中文项目)可传入本地化文案。
2
+ * UI 文案类型与英文默认。语言包在 `src/i18n`:宿主传 `locale`,不传单条文案。
4
3
  */
5
4
  export interface ToolbarLabels {
6
5
  undo: string;
@@ -81,8 +80,12 @@ export interface ToolbarLabels {
81
80
  /** 非 Markdown 文件导入失败(onError 的 source === 'import')。 */
82
81
  importDocumentFailed: string;
83
82
  blockquote: string;
83
+ /** 折叠块(官方 Details)。工具栏按钮 title / aria-label。 */
84
+ details: string;
84
85
  bulletList: string;
85
86
  orderedList: string;
87
+ /** 有序列表旁的编号格式下拉:触发器 title / aria-label。 */
88
+ numberingFormat: string;
86
89
  taskList: string;
87
90
  more: string;
88
91
  /**
@@ -153,6 +156,7 @@ export interface SlashMenuLabels {
153
156
  orderedList: string;
154
157
  taskList: string;
155
158
  blockquote: string;
159
+ details: string;
156
160
  codeBlock: string;
157
161
  divider: string;
158
162
  table: string;
@@ -171,6 +175,30 @@ export interface ChartLabels {
171
175
  }
172
176
  export declare const defaultChartLabels: ChartLabels;
173
177
  export declare const defaultToolbarLabels: ToolbarLabels;
178
+ /**
179
+ * 块拖拽手柄和它的菜单。悬停块时出现在左侧,拖动重排,点击出菜单。
180
+ */
181
+ export interface BlockDragLabels {
182
+ /** 拖拽手柄的 title / aria-label。 */
183
+ dragHandle: string;
184
+ /** 菜单 aria-label。 */
185
+ menuLabel: string;
186
+ /** 「转成」分组标题。 */
187
+ turnInto: string;
188
+ paragraph: string;
189
+ headingLabel: (level: number) => string;
190
+ bulletList: string;
191
+ orderedList: string;
192
+ taskList: string;
193
+ blockquote: string;
194
+ codeBlock: string;
195
+ copy: string;
196
+ duplicate: string;
197
+ resetFormatting: string;
198
+ downloadImage: string;
199
+ delete: string;
200
+ }
201
+ export declare const defaultBlockDragLabels: BlockDragLabels;
174
202
  export declare const defaultSlashMenuLabels: SlashMenuLabels;
175
203
  /** 快捷键抽屉面板(键位 + Markdown 触发写法对照)文案。 */
176
204
  export interface ShortcutLabels {
@@ -211,8 +239,32 @@ export interface ShortcutLabels {
211
239
  alignJustify: string;
212
240
  /** 图片上传占位块(Mod+Shift+I)。 */
213
241
  imageUpload: string;
242
+ /** 智能标点:直引号收成弯引号。 */
243
+ smartQuote: string;
244
+ /** 智能标点:`...` 收成省略号。 */
245
+ ellipsis: string;
246
+ /** 智能标点:`--` 收成破折号。 */
247
+ emDash: string;
248
+ /** 表情:`:smile:` 这类短码。 */
249
+ emoji: string;
214
250
  }
215
251
  export declare const defaultShortcutLabels: ShortcutLabels;
252
+ /** 全文统计(官方 CharacterCount)文案。 */
253
+ export interface CharacterCountLabels {
254
+ /** 统计条的无障碍名。 */
255
+ label: string;
256
+ /** 字符数,如 "128 characters"。 */
257
+ characters: (count: number) => string;
258
+ /** 词数,如 "24 words"。 */
259
+ words: (count: number) => string;
260
+ }
261
+ export declare const defaultCharacterCountLabels: CharacterCountLabels;
262
+ /** 表情建议列表(键入 `:` 唤起)文案。 */
263
+ export interface EmojiSuggestionLabels {
264
+ /** 弹窗 aria-label。 */
265
+ menuLabel: string;
266
+ }
267
+ export declare const defaultEmojiSuggestionLabels: EmojiSuggestionLabels;
216
268
  /** 链接编辑浮层(`<LinkPopover>`)文案。 */
217
269
  export interface LinkPopoverLabels {
218
270
  /** 输入框占位与无障碍名,也是浮层的 aria-label。 */
@@ -244,6 +296,8 @@ export interface CodeBlockLabels {
244
296
  expand: string;
245
297
  /** 只读态:收起已展开的代码块。 */
246
298
  collapse: string;
299
+ /** 语言选择器的 aria-label。 */
300
+ language: string;
247
301
  }
248
302
  export declare const defaultCodeBlockLabels: CodeBlockLabels;
249
303
  export interface CommentLabels {
@@ -0,0 +1,67 @@
1
+ import { Editor } from '@tiptap/core';
2
+ import { ResolvedPos } from '@tiptap/pm/model';
3
+ /**
4
+ * 有序列表的编号格式。id 与下拉预览对齐 Tiptap Numbering Format Dropdown:
5
+ * https://tiptap.dev/docs/ui-components/components/numbering-format-dropdown-menu
6
+ *
7
+ * 格式只记在「这一层编号阶梯」最外层的 orderedList 上(`data-numbering-format`)。
8
+ * 嵌套的 ol 不再单独记格式,屏幕上的 1. / a. / i. 由 CSS 计数器按深度画出来。
9
+ * 官方实现在 `@tiptap-pro/extension-convert-kit`,这里不引 Pro 包,schema 约定与它对齐。
10
+ */
11
+ export declare const NUMBERING_FORMAT_IDS: readonly ["decimal", "decimal-paren", "decimal-nested", "upper-alpha", "lower-alpha", "upper-roman", "lower-roman", "decimal-zero"];
12
+ export type NumberingFormat = (typeof NUMBERING_FORMAT_IDS)[number];
13
+ /** 菜单项的无障碍名,也是官方 `getFormatLabel` 的预览串。 */
14
+ export declare const NUMBERING_FORMAT_LABELS: Record<NumberingFormat, string>;
15
+ /** 下拉里每张小卡片的五行预览(深度 1–3),与官方 demo 的 marker 一致。 */
16
+ export declare const NUMBERING_FORMAT_PREVIEWS: Record<NumberingFormat, {
17
+ depth: 1 | 2 | 3;
18
+ marker: string;
19
+ }[]>;
20
+ export declare function isNumberingFormat(value: unknown): value is NumberingFormat;
21
+ /** `li::before` 的 content 值(不含 `content:` 前缀)。 */
22
+ export declare function numberingMarkerContent(format: NumberingFormat, depth: number): string;
23
+ /**
24
+ * 编号阶梯的正文 CSS。挂在 `.editorContent` 下,压过通用 `ol { list-style: decimal }`。
25
+ * 由测试盯住:改层级定义后要同步 `content.module.css` 里夹在标记注释之间的这段。
26
+ */
27
+ export declare function buildNumberingFormatCss(): string;
28
+ export declare const NUMBERING_FORMAT_CSS: string;
29
+ /**
30
+ * 从光标向外找「本层编号阶梯」最外层的 orderedList。
31
+ * 中途碰到无序 / 任务列表就停——另一种列表会把阶梯切断,里面的 ol 自己是最外层。
32
+ * 返回的是 `$from` 的深度,不在有序列表里则为 null。
33
+ */
34
+ export declare function numberingListDepth($pos: ResolvedPos): number | null;
35
+ declare module '@tiptap/core' {
36
+ interface Commands<ReturnType> {
37
+ numberingFormat: {
38
+ /**
39
+ * 把当前编号阶梯最外层列表改成指定格式。不在有序列表里时返回 false。
40
+ * 传 null 清除格式(回到浏览器默认的 1. 2. 3.)。
41
+ */
42
+ setOrderedListNumberingFormat: (format: NumberingFormat | null) => ReturnType;
43
+ /**
44
+ * 不在有序列表里:先开列表再套上格式。
45
+ * 已经在本层阶梯里:与 `toggleOrderedList` 一样把列表关掉。
46
+ */
47
+ toggleOrderedListWithFormat: (format: NumberingFormat) => ReturnType;
48
+ };
49
+ }
50
+ }
51
+ /**
52
+ * StarterKit 的 OrderedList 加上 `numberingFormat`。节点名仍是 orderedList,
53
+ * 所以要在 StarterKit 里关掉内置那份,避免 Duplicate extension names。
54
+ */
55
+ export declare const OrderedListWithNumbering: import('@tiptap/core').Node<import('@tiptap/extension-list').OrderedListOptions, any>;
56
+ /** 光标所在编号阶梯的格式;不在有序列表里,或列表没设格式时为 null。 */
57
+ export declare function readCurrentNumberingFormat(editor: {
58
+ state: {
59
+ selection: {
60
+ $from: ResolvedPos;
61
+ };
62
+ };
63
+ }): NumberingFormat | null;
64
+ /**
65
+ * 工具栏「选一个编号格式」:已经在有序列表里就改最外层,否则新开一个带该格式的列表。
66
+ */
67
+ export declare function applyNumberingFormat(editor: Editor, format: NumberingFormat): boolean;
@@ -0,0 +1 @@
1
+ export {};
package/dist/reader.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-B2QmL4wi.js";
3
- import { R as R2, a as a2, e, b as b2 } from "./ReportContent-B8jIzhy3.js";
2
+ import { C, a, R, b, f, m, r, s } from "./scrollToTocHeading-kPgsn3cu.js";
3
+ import { R as R2, a as a2, e, b as b2 } from "./ReportContent-w08GFm8v.js";
4
4
  export {
5
5
  C as ChartMount,
6
6
  a as CitationInteractive,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from "react/jsx-runtime";
3
3
  import { useRef, useEffect } from "react";
4
- import { R as ReportContent, p as parseChartFenceBody } from "./ReportContent-B8jIzhy3.js";
4
+ import { R as ReportContent, p as parseChartFenceBody } from "./ReportContent-w08GFm8v.js";
5
5
  import { Chart, CategoryScale, LinearScale, PointElement, LineElement, BarElement, ArcElement, LineController, BarController, PieController, DoughnutController, Filler, Legend, Tooltip } from "chart.js";
6
6
  function toNumber(value) {
7
7
  if (typeof value === "number" && !Number.isNaN(value)) return value;
@@ -493,4 +493,4 @@ export {
493
493
  readCitationAttrs as r,
494
494
  scrollToTocHeading as s
495
495
  };
496
- //# sourceMappingURL=scrollToTocHeading-B2QmL4wi.js.map
496
+ //# sourceMappingURL=scrollToTocHeading-kPgsn3cu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scrollToTocHeading-B2QmL4wi.js","sources":["../src/chart/mapData.ts","../src/chart/theme.ts","../src/chart/renderChart.ts","../src/citationDom.ts","../src/components/CitationInteractive.tsx","../src/components/ReportContentInteractive.tsx","../src/components/ChartMount.tsx","../src/components/ReportContentWithCharts.tsx","../src/toc/scrollToTocHeading.ts"],"sourcesContent":["import type { ChartConfig, ChartPayload } from './types';\n\nexport interface ChartJsPoint {\n x: string | number;\n y: number;\n category?: string;\n type?: string;\n}\n\nfunction toNumber(value: unknown): number {\n if (typeof value === 'number' && !Number.isNaN(value)) return value;\n if (typeof value === 'string') {\n const n = Number(value.replace(/,/g, ''));\n if (!Number.isNaN(n)) return n;\n }\n return 0;\n}\n\n/**\n * Map table rows to flat chart points for one config.\n * colorLegend → series `type`; groupBy stored as category (no UI filter in v1).\n */\nexport function mapChartDataItems(\n config: ChartConfig,\n dataSource: Record<string, unknown>[],\n): ChartJsPoint[] {\n const xKey = config.x!;\n const yKey = config.y!;\n const legendKey = config.colorLegend;\n const groupKey = config.groupBy;\n\n let rows = [...dataSource];\n const sortKey = config.sortBy;\n if (sortKey) {\n rows.sort((a, b) => {\n const av = a[sortKey];\n const bv = b[sortKey];\n if (typeof av === 'number' && typeof bv === 'number') return av - bv;\n return String(av ?? '').localeCompare(String(bv ?? ''), undefined, {\n numeric: true,\n });\n });\n }\n\n return rows.map((row) => {\n const point: ChartJsPoint = {\n x: row[xKey] as string | number,\n y: toNumber(row[yKey]),\n };\n if (legendKey) point.type = String(row[legendKey] ?? '');\n if (groupKey) point.category = String(row[groupKey] ?? '');\n return point;\n });\n}\n\nexport interface BuiltChartData {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n }[];\n isCartesian: boolean;\n}\n\n/** Build Chart.js labels/datasets for one active config. */\nexport function buildChartJsData(\n config: ChartConfig,\n payload: Pick<ChartPayload, 'dataSource'>,\n): BuiltChartData {\n const points = mapChartDataItems(config, payload.dataSource);\n const type = config.chartType;\n const isCartesian = !['pie', 'donut'].includes(type);\n\n if (!isCartesian) {\n return {\n labels: points.map((p) => String(p.x)),\n datasets: [\n {\n label: config.title || config.y || 'value',\n data: points.map((p) => p.y),\n },\n ],\n isCartesian: false,\n };\n }\n\n const seriesKeys = new Set<string>();\n for (const p of points) {\n seriesKeys.add(p.type || config.title || config.y || 'series');\n }\n const seriesList = [...seriesKeys];\n const labelSet: string[] = [];\n for (const p of points) {\n const lab = String(p.x);\n if (!labelSet.includes(lab)) labelSet.push(lab);\n }\n\n const datasets = seriesList.map((series) => ({\n label: series,\n data: labelSet.map((lab) => {\n const hit = points.find(\n (p) =>\n String(p.x) === lab &&\n (p.type || config.title || config.y || 'series') === series,\n );\n return hit ? hit.y : 0;\n }),\n }));\n\n return { labels: labelSet, datasets, isCartesian: true };\n}\n","import type { ChartTheme } from './types';\n\nconst DEFAULT_PALETTE = [\n '#3b82f6',\n '#10b981',\n '#f59e0b',\n '#ef4444',\n '#8b5cf6',\n '#06b6d4',\n '#ec4899',\n '#84cc16',\n];\n\nfunction readCssVar(\n el: HTMLElement | null,\n name: string,\n fallback: string,\n): string {\n if (!el || typeof getComputedStyle === 'undefined') return fallback;\n const v = getComputedStyle(el).getPropertyValue(name).trim();\n return v || fallback;\n}\n\n/** Resolve theme from --tmr-* CSS variables + optional host override. */\nexport function resolveChartTheme(\n host: HTMLElement | null,\n override?: ChartTheme | null,\n): Required<\n Pick<\n ChartTheme,\n | 'backgroundColor'\n | 'textColor'\n | 'gridColor'\n | 'borderColor'\n | 'fontFamily'\n | 'palette'\n >\n> {\n const base = {\n backgroundColor: readCssVar(host, '--tmr-bg', '#ffffff'),\n textColor: readCssVar(host, '--tmr-fg', '#1f2937'),\n gridColor: readCssVar(host, '--tmr-border', '#e5e7eb'),\n borderColor: readCssVar(host, '--tmr-border', '#e5e7eb'),\n fontFamily: readCssVar(\n host,\n '--tmr-font',\n 'ui-sans-serif, system-ui, sans-serif',\n ),\n palette: DEFAULT_PALETTE,\n };\n if (!override) return base;\n return {\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n textColor: override.textColor ?? base.textColor,\n gridColor: override.gridColor ?? base.gridColor,\n borderColor: override.borderColor ?? base.borderColor,\n fontFamily: override.fontFamily ?? base.fontFamily,\n palette:\n override.palette && override.palette.length > 0\n ? override.palette\n : base.palette,\n };\n}\n","import {\n ArcElement,\n BarController,\n BarElement,\n CategoryScale,\n Chart,\n DoughnutController,\n Filler,\n Legend,\n LineController,\n LineElement,\n LinearScale,\n PieController,\n PointElement,\n Tooltip,\n type ChartConfiguration,\n type ChartType,\n} from 'chart.js';\nimport { buildChartJsData } from './mapData';\nimport { resolveChartTheme } from './theme';\nimport type { ChartConfig, ChartPayload, ChartTheme } from './types';\n\nlet registered = false;\n\nfunction ensureRegister() {\n if (registered) return;\n if (typeof window === 'undefined') return;\n Chart.register(\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n BarElement,\n ArcElement,\n LineController,\n BarController,\n PieController,\n DoughnutController,\n Filler,\n Legend,\n Tooltip,\n );\n registered = true;\n}\n\nfunction toChartJsType(chartType: string): ChartType {\n switch (chartType) {\n case 'bar':\n return 'bar';\n case 'column':\n return 'bar';\n case 'line':\n return 'line';\n case 'area':\n return 'line';\n case 'pie':\n return 'pie';\n case 'donut':\n return 'doughnut';\n default:\n return 'bar';\n }\n}\n\nexport interface RenderChartOptions {\n canvas: HTMLCanvasElement;\n config: ChartConfig;\n payload: Pick<ChartPayload, 'dataSource' | 'columns'>;\n theme?: ChartTheme | null;\n /** Existing instance to update in place (streaming). */\n chart?: Chart | null;\n}\n\nexport function renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart,\n}: RenderChartOptions): Chart | null {\n if (typeof window === 'undefined') return null;\n ensureRegister();\n\n const host = canvas.parentElement;\n const colors = resolveChartTheme(host, theme);\n const built = buildChartJsData(config, payload);\n const jsType = toChartJsType(config.chartType);\n const isBarHorizontal = config.chartType === 'bar';\n const isArea = config.chartType === 'area';\n\n const datasets = built.datasets.map((ds, i) => {\n const color = colors.palette[i % colors.palette.length];\n if (!built.isCartesian) {\n return {\n ...ds,\n backgroundColor: built.labels.map(\n (_, j) => colors.palette[j % colors.palette.length],\n ),\n borderWidth: 0,\n };\n }\n return {\n ...ds,\n backgroundColor: isArea ? `${color}33` : color,\n borderColor: color,\n borderWidth: 2,\n fill: isArea,\n tension: 0.25,\n };\n });\n\n const configuration: ChartConfiguration = {\n type: jsType,\n data: {\n labels: built.labels,\n datasets,\n },\n options: {\n indexAxis: isBarHorizontal ? 'y' : 'x',\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n display: built.datasets.length > 1 || !built.isCartesian,\n labels: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n },\n title: { display: false },\n tooltip: {\n titleFont: { family: colors.fontFamily },\n bodyFont: { family: colors.fontFamily },\n },\n },\n scales: built.isCartesian\n ? {\n x: {\n ticks: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n grid: { color: colors.gridColor },\n border: { color: colors.borderColor },\n },\n y: {\n ticks: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n grid: { color: colors.gridColor },\n border: { color: colors.borderColor },\n },\n }\n : undefined,\n },\n };\n\n if (chart) {\n (chart.config as { type: ChartType }).type = jsType;\n chart.data.labels = configuration.data.labels;\n chart.data.datasets = configuration.data.datasets as never;\n chart.options = configuration.options as never;\n chart.update('none');\n return chart;\n }\n\n return new Chart(canvas, configuration);\n}\n\nexport function destroyChart(chart: Chart | null | undefined) {\n chart?.destroy();\n}\n","/**\n * 从事件目标向上找到 `.citation-ref`(且必须在 root 内)。\n * SSR 阅读页事件委托与单测共用。\n */\nexport function findCitationRefElement(\n target: EventTarget | null,\n root: ParentNode,\n): HTMLElement | null {\n let node: Node | null = null;\n if (target instanceof Element) node = target;\n else if (target instanceof Text) node = target.parentElement;\n else if (target instanceof Node) node = target.parentElement;\n if (!(node instanceof Element)) return null;\n const el = node.closest('.citation-ref');\n if (!(el instanceof HTMLElement)) return null;\n if (!root.contains(el)) return null;\n return el;\n}\n\n/** 从圆标 DOM 读取 attrs(与 CitationRef renderHTML 的 data-* 对齐)。 */\nexport function readCitationAttrs(el: HTMLElement): {\n index: string;\n url: string | null;\n title: string | null;\n} {\n return {\n index: el.getAttribute('data-index') || el.textContent?.trim() || '',\n url: el.getAttribute('data-url'),\n title: el.getAttribute('data-title'),\n };\n}\n","'use client';\n\nimport { useEffect, useRef, type RefObject } from 'react';\nimport {\n findCitationRefElement,\n readCitationAttrs,\n} from '../citationDom';\nimport type {\n OnCitationEnter,\n OnCitationLeave,\n} from '../citationTypes';\n\nexport interface CitationInteractiveProps {\n /**\n * 包含 `ReportContent` HTML 的根节点(其内应有 `.citation-ref`)。\n * 用同一 ref 包住 ReportContent 即可。\n */\n containerRef: RefObject<HTMLElement | null>;\n /** 点击圆标。宿主据此 setState 打开自己的 Popover。 */\n onCitationEnter: OnCitationEnter;\n /**\n * 点正文非圆标处 / 再点同一圆标 / Escape。\n * 库立即回调;浮层开关由宿主管。\n */\n onCitationLeave: OnCitationLeave;\n}\n\n/**\n * SSR 阅读页脚注增强:只做 **click** 事件委托,不持有 open 状态。\n *\n * ```tsx\n * <CitationInteractive\n * containerRef={ref}\n * onCitationEnter={setActive}\n * onCitationLeave={() => setActive(null)}\n * />\n * ```\n */\nexport function CitationInteractive({\n containerRef,\n onCitationEnter,\n onCitationLeave,\n}: CitationInteractiveProps) {\n const enterRef = useRef(onCitationEnter);\n const leaveRef = useRef(onCitationLeave);\n enterRef.current = onCitationEnter;\n leaveRef.current = onCitationLeave;\n\n useEffect(() => {\n const root = containerRef.current;\n if (!root) return;\n\n let currentEl: HTMLElement | null = null;\n\n const emitEnter = (el: HTMLElement) => {\n currentEl = el;\n const attrs = readCitationAttrs(el);\n enterRef.current({ index: attrs.index, attrs, anchorEl: el });\n };\n\n const emitLeave = () => {\n if (!currentEl) return;\n currentEl = null;\n leaveRef.current();\n };\n\n const ACTIVE_ATTR = 'data-tmr-citation-active';\n\n const onClick = (e: MouseEvent) => {\n const el = findCitationRefElement(e.target, root);\n if (el) {\n // 捕获阶段就取消默认,避免圆标内 <a> 跳转\n e.preventDefault();\n e.stopPropagation();\n // 仅当该圆标仍处于打开态时再点才关闭(宿主可能已外部关闭,attr 已清)\n if (el === currentEl && el.hasAttribute(ACTIVE_ATTR)) {\n emitLeave();\n return;\n }\n emitEnter(el);\n return;\n }\n emitLeave();\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') emitLeave();\n };\n\n root.addEventListener('click', onClick, true);\n document.addEventListener('keydown', onKeyDown);\n\n return () => {\n root.removeEventListener('click', onClick, true);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [containerRef]);\n\n return null;\n}\n","'use client';\n\nimport { useRef, type ComponentProps } from 'react';\nimport type { OnCitationEnter, OnCitationLeave } from '../citationTypes';\nimport { ReportContent } from '../ReportContent';\nimport { CitationInteractive } from './CitationInteractive';\n\nexport interface ReportContentInteractiveProps\n extends Omit<ComponentProps<typeof ReportContent>, 'ref'> {\n /** 点击圆标:宿主 setState 打开自己的 Popover。 */\n onCitationEnter: OnCitationEnter;\n /** 点外部 / 再点圆标 / Escape:宿主关闭。 */\n onCitationLeave: OnCitationLeave;\n}\n\n/**\n * SSR HTML 阅读 + 脚注 click 委托的便捷封装。\n * 内部:`ReportContent` + `CitationInteractive`(只报事件,仅 click)。\n */\nexport function ReportContentInteractive({\n onCitationEnter,\n onCitationLeave,\n className,\n html,\n ...rest\n}: ReportContentInteractiveProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n return (\n <div ref={ref} className={className}>\n <ReportContent html={html} {...rest} />\n <CitationInteractive\n containerRef={ref}\n onCitationEnter={onCitationEnter}\n onCitationLeave={onCitationLeave}\n />\n </div>\n );\n}\n","'use client';\n\nimport type { Chart as ChartJs } from 'chart.js';\nimport { useEffect, useRef, type RefObject } from 'react';\nimport { parseChartFenceBody } from '../chart/parse';\nimport { destroyChart, renderOrUpdateChart } from '../chart/renderChart';\nimport type { ChartTheme } from '../chart/types';\nimport '../styles/chart.css';\n\nexport interface ChartMountProps {\n containerRef: RefObject<HTMLElement | null>;\n chartTheme?: ChartTheme | null;\n /** Re-scan when this changes (e.g. html string). */\n html?: string;\n}\n\nfunction hydrateOne(\n el: HTMLElement,\n theme: ChartTheme | null | undefined,\n registry: Map<HTMLElement, ChartJs>,\n) {\n const raw = el.getAttribute('data-chart');\n const payload = parseChartFenceBody(raw ?? '');\n if (!payload?.config.length) return;\n\n let host = el.querySelector('.tmr-chart-canvas-host') as HTMLElement | null;\n if (!host) {\n host = document.createElement('div');\n host.className = 'tmr-chart-canvas-host';\n el.appendChild(host);\n }\n host.classList.remove('tmr-chart-skeleton');\n\n let canvas = host.querySelector('canvas');\n if (!canvas) {\n canvas = document.createElement('canvas');\n host.innerHTML = '';\n host.appendChild(canvas);\n }\n\n const config = payload.config[0];\n const height = config.height ?? 320;\n host.style.height = `${height}px`;\n\n if (payload.config.length > 1 && !el.querySelector('.tmr-chart-tabs')) {\n const tabs = document.createElement('div');\n tabs.className = 'tmr-chart-tabs';\n tabs.setAttribute('role', 'tablist');\n payload.config.forEach((c, i) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tmr-chart-tab';\n btn.setAttribute('role', 'tab');\n btn.dataset.active = i === 0 ? 'true' : 'false';\n btn.textContent = c.title?.trim() || `${c.chartType} ${i + 1}`;\n btn.addEventListener('click', () => {\n tabs.querySelectorAll('.tmr-chart-tab').forEach((b, j) => {\n (b as HTMLElement).dataset.active = j === i ? 'true' : 'false';\n });\n const existing = registry.get(el);\n destroyChart(existing);\n const next = renderOrUpdateChart({\n canvas: canvas!,\n config: payload.config[i],\n payload,\n theme,\n chart: null,\n });\n if (next) registry.set(el, next);\n const titleEl = el.querySelector('.tmr-chart-title');\n if (titleEl && payload.config[i].title) {\n titleEl.textContent = String(payload.config[i].title);\n titleEl.classList.remove('tmr-chart-title--empty');\n }\n });\n tabs.appendChild(btn);\n });\n el.insertBefore(tabs, host);\n }\n\n const existing = registry.get(el);\n const chart = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: existing ?? null,\n });\n if (chart) registry.set(el, chart);\n}\n\n/**\n * Hydrate SSR chart placeholders inside a container (reading page).\n */\nexport function ChartMount({\n containerRef,\n chartTheme,\n html,\n}: ChartMountProps) {\n const registryRef = useRef(new Map<HTMLElement, ChartJs>());\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const registry = registryRef.current;\n registry.forEach((chart) => destroyChart(chart));\n registry.clear();\n\n container\n .querySelectorAll<HTMLElement>('div[data-type=\"chart\"]')\n .forEach((el) => hydrateOne(el, chartTheme, registry));\n\n return () => {\n registry.forEach((chart) => destroyChart(chart));\n registry.clear();\n };\n }, [containerRef, chartTheme, html]);\n\n return null;\n}\n\n/** Imperative helper for hosts that prefer not to use the component. */\nexport function mountChartsInContainer(\n container: HTMLElement,\n chartTheme?: ChartTheme | null,\n): () => void {\n const registry = new Map<HTMLElement, ChartJs>();\n container\n .querySelectorAll<HTMLElement>('div[data-type=\"chart\"]')\n .forEach((el) => hydrateOne(el, chartTheme, registry));\n return () => {\n registry.forEach((c) => destroyChart(c));\n registry.clear();\n };\n}\n","'use client';\n\nimport { useRef, type ComponentProps } from 'react';\nimport type { ChartTheme } from '../chart/types';\nimport type { OnCitationEnter, OnCitationLeave } from '../citationTypes';\nimport { ReportContent } from '../ReportContent';\nimport { ChartMount } from './ChartMount';\nimport { CitationInteractive } from './CitationInteractive';\n\nexport interface ReportContentWithChartsProps\n extends Omit<ComponentProps<typeof ReportContent>, 'ref'> {\n onCitationEnter?: OnCitationEnter;\n onCitationLeave?: OnCitationLeave;\n chartTheme?: ChartTheme | null;\n}\n\n/**\n * SSR HTML reading surface with Chart.js hydration (+ optional citation clicks).\n */\nexport function ReportContentWithCharts({\n onCitationEnter,\n onCitationLeave,\n chartTheme,\n className,\n html,\n ...rest\n}: ReportContentWithChartsProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n return (\n <div ref={ref} className={className}>\n <ReportContent html={html} {...rest} />\n <ChartMount\n containerRef={ref}\n chartTheme={chartTheme}\n html={html}\n />\n {onCitationEnter && onCitationLeave ? (\n <CitationInteractive\n containerRef={ref}\n onCitationEnter={onCitationEnter}\n onCitationLeave={onCitationLeave}\n />\n ) : null}\n </div>\n );\n}\n","/**\n * 目录点击 → 平滑滚到对应标题。\n *\n * 不依赖浏览器 `scrollTo({behavior:'smooth'})` / `scrollIntoView({behavior:'smooth'})`——\n * 在 flex + overflow 嵌套布局下(父级 `overflow:hidden`、自身 `flex:1; overflow-y:auto`),\n * Chrome 的 compositor 驱动 smooth scroll 会静默失效。\n *\n * 改用 `requestAnimationFrame` + easeOutCubic 缓动,直接操作 `scrollTop`,\n * 主线程一次性 400ms 动画,点击触发的单次滚动无感知性能差异。\n *\n * 尊重 `prefers-reduced-motion: reduce`——此时瞬间跳转,无动画。\n */\n\n/** 缓动:easeOutCubic。t ∈ [0, 1]。 */\nfunction easeOutCubic(t: number): number {\n return 1 - (1 - t) * (1 - t) * (1 - t);\n}\n\n/**\n * 平滑滚动(或瞬间跳转)到指定 `data-toc-id` 的标题。\n *\n * @param headingId - TOC item 的 id,对应 DOM 上 `data-toc-id` 属性值\n * @param scrollContainer - 滚动容器(如 `.scrollArea`)\n * @param options - `duration`:动画时长 ms,默认 400\n */\nexport function scrollToTocHeading(\n headingId: string,\n scrollContainer: HTMLElement,\n options?: { duration?: number },\n): void {\n const el = scrollContainer.querySelector<HTMLElement>(\n `[data-toc-id=\"${CSS.escape(headingId)}\"]`,\n );\n if (!el) return;\n\n const startTop = scrollContainer.scrollTop;\n const rootRect = scrollContainer.getBoundingClientRect();\n const elRect = el.getBoundingClientRect();\n const targetTop = startTop + (elRect.top - rootRect.top);\n\n // prefers-reduced-motion:瞬间跳转\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n scrollContainer.scrollTop = targetTop;\n return;\n }\n\n // 手动平滑滚动\n const duration = options?.duration ?? 400;\n const start = performance.now();\n const animate = () => {\n const t = Math.min((performance.now() - start) / duration, 1);\n scrollContainer.scrollTop = startTop + (targetTop - startTop) * easeOutCubic(t);\n if (t < 1) requestAnimationFrame(animate);\n };\n requestAnimationFrame(animate);\n}\n"],"names":["existing"],"mappings":"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"}
1
+ {"version":3,"file":"scrollToTocHeading-kPgsn3cu.js","sources":["../src/chart/mapData.ts","../src/chart/theme.ts","../src/chart/renderChart.ts","../src/citationDom.ts","../src/components/CitationInteractive.tsx","../src/components/ReportContentInteractive.tsx","../src/components/ChartMount.tsx","../src/components/ReportContentWithCharts.tsx","../src/toc/scrollToTocHeading.ts"],"sourcesContent":["import type { ChartConfig, ChartPayload } from './types';\n\nexport interface ChartJsPoint {\n x: string | number;\n y: number;\n category?: string;\n type?: string;\n}\n\nfunction toNumber(value: unknown): number {\n if (typeof value === 'number' && !Number.isNaN(value)) return value;\n if (typeof value === 'string') {\n const n = Number(value.replace(/,/g, ''));\n if (!Number.isNaN(n)) return n;\n }\n return 0;\n}\n\n/**\n * Map table rows to flat chart points for one config.\n * colorLegend → series `type`; groupBy stored as category (no UI filter in v1).\n */\nexport function mapChartDataItems(\n config: ChartConfig,\n dataSource: Record<string, unknown>[],\n): ChartJsPoint[] {\n const xKey = config.x!;\n const yKey = config.y!;\n const legendKey = config.colorLegend;\n const groupKey = config.groupBy;\n\n let rows = [...dataSource];\n const sortKey = config.sortBy;\n if (sortKey) {\n rows.sort((a, b) => {\n const av = a[sortKey];\n const bv = b[sortKey];\n if (typeof av === 'number' && typeof bv === 'number') return av - bv;\n return String(av ?? '').localeCompare(String(bv ?? ''), undefined, {\n numeric: true,\n });\n });\n }\n\n return rows.map((row) => {\n const point: ChartJsPoint = {\n x: row[xKey] as string | number,\n y: toNumber(row[yKey]),\n };\n if (legendKey) point.type = String(row[legendKey] ?? '');\n if (groupKey) point.category = String(row[groupKey] ?? '');\n return point;\n });\n}\n\nexport interface BuiltChartData {\n labels: string[];\n datasets: {\n label: string;\n data: number[];\n }[];\n isCartesian: boolean;\n}\n\n/** Build Chart.js labels/datasets for one active config. */\nexport function buildChartJsData(\n config: ChartConfig,\n payload: Pick<ChartPayload, 'dataSource'>,\n): BuiltChartData {\n const points = mapChartDataItems(config, payload.dataSource);\n const type = config.chartType;\n const isCartesian = !['pie', 'donut'].includes(type);\n\n if (!isCartesian) {\n return {\n labels: points.map((p) => String(p.x)),\n datasets: [\n {\n label: config.title || config.y || 'value',\n data: points.map((p) => p.y),\n },\n ],\n isCartesian: false,\n };\n }\n\n const seriesKeys = new Set<string>();\n for (const p of points) {\n seriesKeys.add(p.type || config.title || config.y || 'series');\n }\n const seriesList = [...seriesKeys];\n const labelSet: string[] = [];\n for (const p of points) {\n const lab = String(p.x);\n if (!labelSet.includes(lab)) labelSet.push(lab);\n }\n\n const datasets = seriesList.map((series) => ({\n label: series,\n data: labelSet.map((lab) => {\n const hit = points.find(\n (p) =>\n String(p.x) === lab &&\n (p.type || config.title || config.y || 'series') === series,\n );\n return hit ? hit.y : 0;\n }),\n }));\n\n return { labels: labelSet, datasets, isCartesian: true };\n}\n","import type { ChartTheme } from './types';\n\nconst DEFAULT_PALETTE = [\n '#3b82f6',\n '#10b981',\n '#f59e0b',\n '#ef4444',\n '#8b5cf6',\n '#06b6d4',\n '#ec4899',\n '#84cc16',\n];\n\nfunction readCssVar(\n el: HTMLElement | null,\n name: string,\n fallback: string,\n): string {\n if (!el || typeof getComputedStyle === 'undefined') return fallback;\n const v = getComputedStyle(el).getPropertyValue(name).trim();\n return v || fallback;\n}\n\n/** Resolve theme from --tmr-* CSS variables + optional host override. */\nexport function resolveChartTheme(\n host: HTMLElement | null,\n override?: ChartTheme | null,\n): Required<\n Pick<\n ChartTheme,\n | 'backgroundColor'\n | 'textColor'\n | 'gridColor'\n | 'borderColor'\n | 'fontFamily'\n | 'palette'\n >\n> {\n const base = {\n backgroundColor: readCssVar(host, '--tmr-bg', '#ffffff'),\n textColor: readCssVar(host, '--tmr-fg', '#1f2937'),\n gridColor: readCssVar(host, '--tmr-border', '#e5e7eb'),\n borderColor: readCssVar(host, '--tmr-border', '#e5e7eb'),\n fontFamily: readCssVar(\n host,\n '--tmr-font',\n 'ui-sans-serif, system-ui, sans-serif',\n ),\n palette: DEFAULT_PALETTE,\n };\n if (!override) return base;\n return {\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n textColor: override.textColor ?? base.textColor,\n gridColor: override.gridColor ?? base.gridColor,\n borderColor: override.borderColor ?? base.borderColor,\n fontFamily: override.fontFamily ?? base.fontFamily,\n palette:\n override.palette && override.palette.length > 0\n ? override.palette\n : base.palette,\n };\n}\n","import {\n ArcElement,\n BarController,\n BarElement,\n CategoryScale,\n Chart,\n DoughnutController,\n Filler,\n Legend,\n LineController,\n LineElement,\n LinearScale,\n PieController,\n PointElement,\n Tooltip,\n type ChartConfiguration,\n type ChartType,\n} from 'chart.js';\nimport { buildChartJsData } from './mapData';\nimport { resolveChartTheme } from './theme';\nimport type { ChartConfig, ChartPayload, ChartTheme } from './types';\n\nlet registered = false;\n\nfunction ensureRegister() {\n if (registered) return;\n if (typeof window === 'undefined') return;\n Chart.register(\n CategoryScale,\n LinearScale,\n PointElement,\n LineElement,\n BarElement,\n ArcElement,\n LineController,\n BarController,\n PieController,\n DoughnutController,\n Filler,\n Legend,\n Tooltip,\n );\n registered = true;\n}\n\nfunction toChartJsType(chartType: string): ChartType {\n switch (chartType) {\n case 'bar':\n return 'bar';\n case 'column':\n return 'bar';\n case 'line':\n return 'line';\n case 'area':\n return 'line';\n case 'pie':\n return 'pie';\n case 'donut':\n return 'doughnut';\n default:\n return 'bar';\n }\n}\n\nexport interface RenderChartOptions {\n canvas: HTMLCanvasElement;\n config: ChartConfig;\n payload: Pick<ChartPayload, 'dataSource' | 'columns'>;\n theme?: ChartTheme | null;\n /** Existing instance to update in place (streaming). */\n chart?: Chart | null;\n}\n\nexport function renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart,\n}: RenderChartOptions): Chart | null {\n if (typeof window === 'undefined') return null;\n ensureRegister();\n\n const host = canvas.parentElement;\n const colors = resolveChartTheme(host, theme);\n const built = buildChartJsData(config, payload);\n const jsType = toChartJsType(config.chartType);\n const isBarHorizontal = config.chartType === 'bar';\n const isArea = config.chartType === 'area';\n\n const datasets = built.datasets.map((ds, i) => {\n const color = colors.palette[i % colors.palette.length];\n if (!built.isCartesian) {\n return {\n ...ds,\n backgroundColor: built.labels.map(\n (_, j) => colors.palette[j % colors.palette.length],\n ),\n borderWidth: 0,\n };\n }\n return {\n ...ds,\n backgroundColor: isArea ? `${color}33` : color,\n borderColor: color,\n borderWidth: 2,\n fill: isArea,\n tension: 0.25,\n };\n });\n\n const configuration: ChartConfiguration = {\n type: jsType,\n data: {\n labels: built.labels,\n datasets,\n },\n options: {\n indexAxis: isBarHorizontal ? 'y' : 'x',\n responsive: true,\n maintainAspectRatio: false,\n plugins: {\n legend: {\n display: built.datasets.length > 1 || !built.isCartesian,\n labels: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n },\n title: { display: false },\n tooltip: {\n titleFont: { family: colors.fontFamily },\n bodyFont: { family: colors.fontFamily },\n },\n },\n scales: built.isCartesian\n ? {\n x: {\n ticks: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n grid: { color: colors.gridColor },\n border: { color: colors.borderColor },\n },\n y: {\n ticks: {\n color: colors.textColor,\n font: { family: colors.fontFamily },\n },\n grid: { color: colors.gridColor },\n border: { color: colors.borderColor },\n },\n }\n : undefined,\n },\n };\n\n if (chart) {\n (chart.config as { type: ChartType }).type = jsType;\n chart.data.labels = configuration.data.labels;\n chart.data.datasets = configuration.data.datasets as never;\n chart.options = configuration.options as never;\n chart.update('none');\n return chart;\n }\n\n return new Chart(canvas, configuration);\n}\n\nexport function destroyChart(chart: Chart | null | undefined) {\n chart?.destroy();\n}\n","/**\n * 从事件目标向上找到 `.citation-ref`(且必须在 root 内)。\n * SSR 阅读页事件委托与单测共用。\n */\nexport function findCitationRefElement(\n target: EventTarget | null,\n root: ParentNode,\n): HTMLElement | null {\n let node: Node | null = null;\n if (target instanceof Element) node = target;\n else if (target instanceof Text) node = target.parentElement;\n else if (target instanceof Node) node = target.parentElement;\n if (!(node instanceof Element)) return null;\n const el = node.closest('.citation-ref');\n if (!(el instanceof HTMLElement)) return null;\n if (!root.contains(el)) return null;\n return el;\n}\n\n/** 从圆标 DOM 读取 attrs(与 CitationRef renderHTML 的 data-* 对齐)。 */\nexport function readCitationAttrs(el: HTMLElement): {\n index: string;\n url: string | null;\n title: string | null;\n} {\n return {\n index: el.getAttribute('data-index') || el.textContent?.trim() || '',\n url: el.getAttribute('data-url'),\n title: el.getAttribute('data-title'),\n };\n}\n","'use client';\n\nimport { useEffect, useRef, type RefObject } from 'react';\nimport {\n findCitationRefElement,\n readCitationAttrs,\n} from '../citationDom';\nimport type {\n OnCitationEnter,\n OnCitationLeave,\n} from '../citationTypes';\n\nexport interface CitationInteractiveProps {\n /**\n * 包含 `ReportContent` HTML 的根节点(其内应有 `.citation-ref`)。\n * 用同一 ref 包住 ReportContent 即可。\n */\n containerRef: RefObject<HTMLElement | null>;\n /** 点击圆标。宿主据此 setState 打开自己的 Popover。 */\n onCitationEnter: OnCitationEnter;\n /**\n * 点正文非圆标处 / 再点同一圆标 / Escape。\n * 库立即回调;浮层开关由宿主管。\n */\n onCitationLeave: OnCitationLeave;\n}\n\n/**\n * SSR 阅读页脚注增强:只做 **click** 事件委托,不持有 open 状态。\n *\n * ```tsx\n * <CitationInteractive\n * containerRef={ref}\n * onCitationEnter={setActive}\n * onCitationLeave={() => setActive(null)}\n * />\n * ```\n */\nexport function CitationInteractive({\n containerRef,\n onCitationEnter,\n onCitationLeave,\n}: CitationInteractiveProps) {\n const enterRef = useRef(onCitationEnter);\n const leaveRef = useRef(onCitationLeave);\n enterRef.current = onCitationEnter;\n leaveRef.current = onCitationLeave;\n\n useEffect(() => {\n const root = containerRef.current;\n if (!root) return;\n\n let currentEl: HTMLElement | null = null;\n\n const emitEnter = (el: HTMLElement) => {\n currentEl = el;\n const attrs = readCitationAttrs(el);\n enterRef.current({ index: attrs.index, attrs, anchorEl: el });\n };\n\n const emitLeave = () => {\n if (!currentEl) return;\n currentEl = null;\n leaveRef.current();\n };\n\n const ACTIVE_ATTR = 'data-tmr-citation-active';\n\n const onClick = (e: MouseEvent) => {\n const el = findCitationRefElement(e.target, root);\n if (el) {\n // 捕获阶段就取消默认,避免圆标内 <a> 跳转\n e.preventDefault();\n e.stopPropagation();\n // 仅当该圆标仍处于打开态时再点才关闭(宿主可能已外部关闭,attr 已清)\n if (el === currentEl && el.hasAttribute(ACTIVE_ATTR)) {\n emitLeave();\n return;\n }\n emitEnter(el);\n return;\n }\n emitLeave();\n };\n\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') emitLeave();\n };\n\n root.addEventListener('click', onClick, true);\n document.addEventListener('keydown', onKeyDown);\n\n return () => {\n root.removeEventListener('click', onClick, true);\n document.removeEventListener('keydown', onKeyDown);\n };\n }, [containerRef]);\n\n return null;\n}\n","'use client';\n\nimport { useRef, type ComponentProps } from 'react';\nimport type { OnCitationEnter, OnCitationLeave } from '../citationTypes';\nimport { ReportContent } from '../ReportContent';\nimport { CitationInteractive } from './CitationInteractive';\n\nexport interface ReportContentInteractiveProps\n extends Omit<ComponentProps<typeof ReportContent>, 'ref'> {\n /** 点击圆标:宿主 setState 打开自己的 Popover。 */\n onCitationEnter: OnCitationEnter;\n /** 点外部 / 再点圆标 / Escape:宿主关闭。 */\n onCitationLeave: OnCitationLeave;\n}\n\n/**\n * SSR HTML 阅读 + 脚注 click 委托的便捷封装。\n * 内部:`ReportContent` + `CitationInteractive`(只报事件,仅 click)。\n */\nexport function ReportContentInteractive({\n onCitationEnter,\n onCitationLeave,\n className,\n html,\n ...rest\n}: ReportContentInteractiveProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n return (\n <div ref={ref} className={className}>\n <ReportContent html={html} {...rest} />\n <CitationInteractive\n containerRef={ref}\n onCitationEnter={onCitationEnter}\n onCitationLeave={onCitationLeave}\n />\n </div>\n );\n}\n","'use client';\n\nimport type { Chart as ChartJs } from 'chart.js';\nimport { useEffect, useRef, type RefObject } from 'react';\nimport { parseChartFenceBody } from '../chart/parse';\nimport { destroyChart, renderOrUpdateChart } from '../chart/renderChart';\nimport type { ChartTheme } from '../chart/types';\nimport '../styles/chart.css';\n\nexport interface ChartMountProps {\n containerRef: RefObject<HTMLElement | null>;\n chartTheme?: ChartTheme | null;\n /** Re-scan when this changes (e.g. html string). */\n html?: string;\n}\n\nfunction hydrateOne(\n el: HTMLElement,\n theme: ChartTheme | null | undefined,\n registry: Map<HTMLElement, ChartJs>,\n) {\n const raw = el.getAttribute('data-chart');\n const payload = parseChartFenceBody(raw ?? '');\n if (!payload?.config.length) return;\n\n let host = el.querySelector('.tmr-chart-canvas-host') as HTMLElement | null;\n if (!host) {\n host = document.createElement('div');\n host.className = 'tmr-chart-canvas-host';\n el.appendChild(host);\n }\n host.classList.remove('tmr-chart-skeleton');\n\n let canvas = host.querySelector('canvas');\n if (!canvas) {\n canvas = document.createElement('canvas');\n host.innerHTML = '';\n host.appendChild(canvas);\n }\n\n const config = payload.config[0];\n const height = config.height ?? 320;\n host.style.height = `${height}px`;\n\n if (payload.config.length > 1 && !el.querySelector('.tmr-chart-tabs')) {\n const tabs = document.createElement('div');\n tabs.className = 'tmr-chart-tabs';\n tabs.setAttribute('role', 'tablist');\n payload.config.forEach((c, i) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tmr-chart-tab';\n btn.setAttribute('role', 'tab');\n btn.dataset.active = i === 0 ? 'true' : 'false';\n btn.textContent = c.title?.trim() || `${c.chartType} ${i + 1}`;\n btn.addEventListener('click', () => {\n tabs.querySelectorAll('.tmr-chart-tab').forEach((b, j) => {\n (b as HTMLElement).dataset.active = j === i ? 'true' : 'false';\n });\n const existing = registry.get(el);\n destroyChart(existing);\n const next = renderOrUpdateChart({\n canvas: canvas!,\n config: payload.config[i],\n payload,\n theme,\n chart: null,\n });\n if (next) registry.set(el, next);\n const titleEl = el.querySelector('.tmr-chart-title');\n if (titleEl && payload.config[i].title) {\n titleEl.textContent = String(payload.config[i].title);\n titleEl.classList.remove('tmr-chart-title--empty');\n }\n });\n tabs.appendChild(btn);\n });\n el.insertBefore(tabs, host);\n }\n\n const existing = registry.get(el);\n const chart = renderOrUpdateChart({\n canvas,\n config,\n payload,\n theme,\n chart: existing ?? null,\n });\n if (chart) registry.set(el, chart);\n}\n\n/**\n * Hydrate SSR chart placeholders inside a container (reading page).\n */\nexport function ChartMount({\n containerRef,\n chartTheme,\n html,\n}: ChartMountProps) {\n const registryRef = useRef(new Map<HTMLElement, ChartJs>());\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const registry = registryRef.current;\n registry.forEach((chart) => destroyChart(chart));\n registry.clear();\n\n container\n .querySelectorAll<HTMLElement>('div[data-type=\"chart\"]')\n .forEach((el) => hydrateOne(el, chartTheme, registry));\n\n return () => {\n registry.forEach((chart) => destroyChart(chart));\n registry.clear();\n };\n }, [containerRef, chartTheme, html]);\n\n return null;\n}\n\n/** Imperative helper for hosts that prefer not to use the component. */\nexport function mountChartsInContainer(\n container: HTMLElement,\n chartTheme?: ChartTheme | null,\n): () => void {\n const registry = new Map<HTMLElement, ChartJs>();\n container\n .querySelectorAll<HTMLElement>('div[data-type=\"chart\"]')\n .forEach((el) => hydrateOne(el, chartTheme, registry));\n return () => {\n registry.forEach((c) => destroyChart(c));\n registry.clear();\n };\n}\n","'use client';\n\nimport { useRef, type ComponentProps } from 'react';\nimport type { ChartTheme } from '../chart/types';\nimport type { OnCitationEnter, OnCitationLeave } from '../citationTypes';\nimport { ReportContent } from '../ReportContent';\nimport { ChartMount } from './ChartMount';\nimport { CitationInteractive } from './CitationInteractive';\n\nexport interface ReportContentWithChartsProps\n extends Omit<ComponentProps<typeof ReportContent>, 'ref'> {\n onCitationEnter?: OnCitationEnter;\n onCitationLeave?: OnCitationLeave;\n chartTheme?: ChartTheme | null;\n}\n\n/**\n * SSR HTML reading surface with Chart.js hydration (+ optional citation clicks).\n */\nexport function ReportContentWithCharts({\n onCitationEnter,\n onCitationLeave,\n chartTheme,\n className,\n html,\n ...rest\n}: ReportContentWithChartsProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n return (\n <div ref={ref} className={className}>\n <ReportContent html={html} {...rest} />\n <ChartMount\n containerRef={ref}\n chartTheme={chartTheme}\n html={html}\n />\n {onCitationEnter && onCitationLeave ? (\n <CitationInteractive\n containerRef={ref}\n onCitationEnter={onCitationEnter}\n onCitationLeave={onCitationLeave}\n />\n ) : null}\n </div>\n );\n}\n","/**\n * 目录点击 → 平滑滚到对应标题。\n *\n * 不依赖浏览器 `scrollTo({behavior:'smooth'})` / `scrollIntoView({behavior:'smooth'})`——\n * 在 flex + overflow 嵌套布局下(父级 `overflow:hidden`、自身 `flex:1; overflow-y:auto`),\n * Chrome 的 compositor 驱动 smooth scroll 会静默失效。\n *\n * 改用 `requestAnimationFrame` + easeOutCubic 缓动,直接操作 `scrollTop`,\n * 主线程一次性 400ms 动画,点击触发的单次滚动无感知性能差异。\n *\n * 尊重 `prefers-reduced-motion: reduce`——此时瞬间跳转,无动画。\n */\n\n/** 缓动:easeOutCubic。t ∈ [0, 1]。 */\nfunction easeOutCubic(t: number): number {\n return 1 - (1 - t) * (1 - t) * (1 - t);\n}\n\n/**\n * 平滑滚动(或瞬间跳转)到指定 `data-toc-id` 的标题。\n *\n * @param headingId - TOC item 的 id,对应 DOM 上 `data-toc-id` 属性值\n * @param scrollContainer - 滚动容器(如 `.scrollArea`)\n * @param options - `duration`:动画时长 ms,默认 400\n */\nexport function scrollToTocHeading(\n headingId: string,\n scrollContainer: HTMLElement,\n options?: { duration?: number },\n): void {\n const el = scrollContainer.querySelector<HTMLElement>(\n `[data-toc-id=\"${CSS.escape(headingId)}\"]`,\n );\n if (!el) return;\n\n const startTop = scrollContainer.scrollTop;\n const rootRect = scrollContainer.getBoundingClientRect();\n const elRect = el.getBoundingClientRect();\n const targetTop = startTop + (elRect.top - rootRect.top);\n\n // prefers-reduced-motion:瞬间跳转\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {\n scrollContainer.scrollTop = targetTop;\n return;\n }\n\n // 手动平滑滚动\n const duration = options?.duration ?? 400;\n const start = performance.now();\n const animate = () => {\n const t = Math.min((performance.now() - start) / duration, 1);\n scrollContainer.scrollTop = startTop + (targetTop - startTop) * easeOutCubic(t);\n if (t < 1) requestAnimationFrame(animate);\n };\n requestAnimationFrame(animate);\n}\n"],"names":["existing"],"mappings":"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"}
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
- import { s as stabilizeMarkdown, p as prepareChartMarkdown, b as baseExtensions, a as pureCodeBlock, c as pureImage, d as pureChart, C as CitationRef, m as makeTocGetId, r as renderMathElementHtml, e as extractToc } from "./extractToc-CGrBMGvM.js";
2
- import { f, g, l, h, i, j } from "./extractToc-CGrBMGvM.js";
3
- import { a as applyCitationSources } from "./ReportContent-B8jIzhy3.js";
4
- import { R, e, s } from "./ReportContent-B8jIzhy3.js";
1
+ import { s as stabilizeMarkdown, p as prepareChartMarkdown, b as baseExtensions, a as pureCodeBlock, c as pureImage, d as pureChart, C as CitationRef, m as makeTocGetId, r as renderMathElementHtml, e as extractToc } from "./extractToc-Cr470fBy.js";
2
+ import { f, g, l, h, i, j } from "./extractToc-Cr470fBy.js";
3
+ import { a as applyCitationSources } from "./ReportContent-w08GFm8v.js";
4
+ import { R, e, s } from "./ReportContent-w08GFm8v.js";
5
5
  import { TableOfContents, generateTocIds } from "@tiptap/extension-table-of-contents";
6
6
  import { MarkdownManager } from "@tiptap/markdown";
7
7
  import { renderToHTMLString } from "@tiptap/static-renderer";
@@ -1,13 +1,13 @@
1
- import { ShortcutLabels } from '../labels';
1
+ import { LocaleCode } from '../i18n';
2
2
  export interface ShortcutPanelProps {
3
3
  open: boolean;
4
4
  onClose: () => void;
5
- /** 文案覆盖,与默认英文合并。 */
6
- labels?: Partial<ShortcutLabels>;
5
+ /** 内置语言,默认英文。 */
6
+ locale?: LocaleCode;
7
7
  }
8
8
  /**
9
9
  * 快捷键抽屉(语雀式):右侧滑出的三列对照表——格式 / 快捷键 / Markdown。
10
10
  * 数据来自 buildShortcutGroups(键位与 input rule 均为库内真实行为)。
11
11
  * 定位 fixed 贴视口右缘;Esc 关闭。
12
12
  */
13
- export declare function ShortcutPanel({ open, onClose, labels }: ShortcutPanelProps): import("react").JSX.Element | null;
13
+ export declare function ShortcutPanel({ open, onClose, locale, }: ShortcutPanelProps): import("react").JSX.Element | null;
@@ -1,4 +1,4 @@
1
- import { ShortcutLabels } from '../labels';
1
+ import { LocaleCode } from '../i18n';
2
2
  /**
3
3
  * 快捷键面板数据模型。keys 里的 'Mod' / 'Alt' 按平台渲染
4
4
  * (macOS: Cmd / Opt;其他: Ctrl / Alt)。
@@ -29,4 +29,4 @@ export interface ShortcutGroup {
29
29
  * addKeyboardShortcuts 默认值,markdown 触发来自对应 input rule
30
30
  * (上标/下标/链接在本库无默认键位与 input rule,故不列)。
31
31
  */
32
- export declare function buildShortcutGroups(labels: ShortcutLabels): ShortcutGroup[];
32
+ export declare function buildShortcutGroups(locale?: LocaleCode): ShortcutGroup[];
@@ -1,11 +1,8 @@
1
1
  import { Extension } from '@tiptap/core';
2
- import { SlashMenuLabels } from '../labels';
3
2
  import { SlashMenuItem } from './types';
4
3
  export interface SlashMenuOptions {
5
4
  /** 追加的宿主自定义命令项(排在默认项之后)。 */
6
5
  items?: SlashMenuItem[];
7
- /** 弹窗文案,与默认英文文案合并。 */
8
- labels?: Partial<SlashMenuLabels>;
9
6
  }
10
7
  /**
11
8
  * 斜杠菜单:键入 `/` 唤起块级插入弹窗。
@@ -1,4 +1,4 @@
1
- import { SlashMenuLabels } from '../labels';
1
+ import { LocaleCode } from '../i18n';
2
2
  import { SlashMenuItem } from './types';
3
3
  /**
4
4
  * 默认斜杠命令项:全部是「可序列化为 markdown」的块级操作。
@@ -7,6 +7,6 @@ import { SlashMenuItem } from './types';
7
7
  * 图标沿用工具栏下拉菜单的文字字形语言(`{ }` / `√x` / `∑` / `—` / `❝`),
8
8
  * 三组(文本 / 列表 / 高级)在弹窗里分节展示。
9
9
  */
10
- export declare function createDefaultSlashMenuItems(labels?: SlashMenuLabels): SlashMenuItem[];
10
+ export declare function createDefaultSlashMenuItems(locale?: LocaleCode): SlashMenuItem[];
11
11
  /** 按 title / aliases 做小写 includes 过滤;空 query 返回全部。 */
12
12
  export declare function filterSlashItems(items: SlashMenuItem[], query: string): SlashMenuItem[];