tiptap-markdown-react 0.8.3 → 0.8.5

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/math.d.ts CHANGED
@@ -9,6 +9,8 @@ type MathClickListener = (payload: MathClickPayload) => void;
9
9
  export declare function subscribeMathClick(listener: MathClickListener): () => void;
10
10
  /** KaTeX HTML 片段(SSR / 预览弹层)。失败时回退为转义原文。 */
11
11
  export declare function renderMathHtml(latex: string, displayMode: boolean): string;
12
+ /** 把公式画进已有节点(编辑态原地预览,避免再叠一份 overlay)。 */
13
+ export declare function renderMathInto(el: HTMLElement, latex: string, displayMode: boolean): void;
12
14
  export declare function renderMathElementHtml(latex: string, displayMode: boolean): string;
13
15
  /**
14
16
  * 行内公式:markdown 为 `$$latex$$`(单行、无换行)。
@@ -20,11 +20,26 @@ import { TocItem } from './toc/extractToc';
20
20
  export interface RenderedReport {
21
21
  html: string;
22
22
  toc: TocItem[];
23
+ /**
24
+ * 管线是否成功。空 markdown 也是 ok。
25
+ * parse / render 抛错时为 false;调用方可保留上一帧 HTML。
26
+ */
27
+ ok: boolean;
23
28
  }
24
29
  export interface RenderReportHtmlOptions {
25
30
  /** 被付费墙锁住的章节标题(TOC 标 locked)。 */
26
31
  lockedTitles?: string[];
27
32
  /** 脚注来源,按 index 对齐 `[^n]`。 */
28
33
  sources?: SourceRef[];
34
+ /**
35
+ * 是否注入标题锚点并返回 toc。默认 true(`/p` 阅读页)。
36
+ * 卡片预览传 false,跳过 generateTocIds。
37
+ */
38
+ includeToc?: boolean;
39
+ /**
40
+ * 流式半成品:补未闭合代码围栏。默认 false。
41
+ * 完整落库稿不要开,以免改已发布 HTML。
42
+ */
43
+ stabilize?: boolean;
29
44
  }
30
45
  export declare function renderReportHtml(markdown: string, lockedTitlesOrOptions?: string[] | RenderReportHtmlOptions): RenderedReport;
@@ -0,0 +1 @@
1
+ export {};
package/dist/server.d.ts CHANGED
@@ -9,5 +9,6 @@ export { mapCommentAnchors, mergeCommentIntervals, blockTextHash, type CommentSe
9
9
  export { applyCitationSources, enrichMarkdownCitations, type SourceRef, } from './citationUtils';
10
10
  export { ReportContent, type ReportContentProps } from './ReportContent';
11
11
  export { renderReportHtml, type RenderedReport, type RenderReportHtmlOptions, } from './renderReportHtml';
12
+ export { stabilizeMarkdown } from './stabilizeMarkdown';
12
13
  export { extractToc, type TocItem } from './toc/extractToc';
13
14
  export { makeTocGetId } from './toc/tocSlug';
package/dist/server.js CHANGED
@@ -1,5 +1,5 @@
1
- import { h as applyCitationSources, b as baseExtensions, p as pureCodeBlock, f as pureImage, C as CitationRef, d as makeTocGetId, k as renderMathElementHtml, j as extractToc } from "./extractToc-CMvSKha8.js";
2
- import { c, R, i, e, l, a, m } from "./extractToc-CMvSKha8.js";
1
+ import { k as stabilizeMarkdown, h as applyCitationSources, b as baseExtensions, p as pureCodeBlock, f as pureImage, C as CitationRef, d as makeTocGetId, n as renderMathElementHtml, j as extractToc } from "./extractToc-bgvj5gGC.js";
2
+ import { c, R, i, e, l, a, m } from "./extractToc-bgvj5gGC.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";
@@ -12,15 +12,62 @@ const sharedManager = new MarkdownManager({
12
12
  TableOfContents
13
13
  ]
14
14
  });
15
+ function htmlFromJson(json) {
16
+ const extensions = [
17
+ ...baseExtensions,
18
+ pureCodeBlock,
19
+ pureImage,
20
+ CitationRef,
21
+ TableOfContents.configure({ getId: makeTocGetId() })
22
+ ];
23
+ return renderToHTMLString({
24
+ extensions,
25
+ content: json,
26
+ options: {
27
+ nodeMapping: {
28
+ inlineMath: ({ node }) => {
29
+ var _a;
30
+ return renderMathElementHtml(String(((_a = node.attrs) == null ? void 0 : _a.latex) ?? ""), false);
31
+ },
32
+ blockMath: ({ node }) => {
33
+ var _a;
34
+ return renderMathElementHtml(String(((_a = node.attrs) == null ? void 0 : _a.latex) ?? ""), true);
35
+ }
36
+ }
37
+ }
38
+ });
39
+ }
15
40
  function renderReportHtml(markdown, lockedTitlesOrOptions = []) {
16
- if (!(markdown == null ? void 0 : markdown.trim())) return { html: "", toc: [] };
41
+ if (!(markdown == null ? void 0 : markdown.trim())) return { html: "", toc: [], ok: true };
17
42
  const options = Array.isArray(lockedTitlesOrOptions) ? { lockedTitles: lockedTitlesOrOptions } : lockedTitlesOrOptions;
18
43
  const lockedTitles = options.lockedTitles ?? [];
19
44
  const sources = options.sources ?? [];
20
- const json = applyCitationSources(
21
- sharedManager.parse(markdown),
22
- sources
23
- );
45
+ const includeToc = options.includeToc !== false;
46
+ const input = options.stabilize ? stabilizeMarkdown(markdown) : markdown;
47
+ let json;
48
+ try {
49
+ json = applyCitationSources(
50
+ sharedManager.parse(input),
51
+ sources
52
+ );
53
+ } catch (e2) {
54
+ console.error(
55
+ "[renderReportHtml] markdown parse failed:",
56
+ e2.message
57
+ );
58
+ return { html: "", toc: [], ok: false };
59
+ }
60
+ if (!includeToc) {
61
+ try {
62
+ return { html: htmlFromJson(json), toc: [], ok: true };
63
+ } catch (e2) {
64
+ console.error(
65
+ "[renderReportHtml] render failed (no toc):",
66
+ e2.message
67
+ );
68
+ return { html: "", toc: [], ok: false };
69
+ }
70
+ }
24
71
  const extensions = [
25
72
  ...baseExtensions,
26
73
  pureCodeBlock,
@@ -46,13 +93,21 @@ function renderReportHtml(markdown, lockedTitlesOrOptions = []) {
46
93
  }
47
94
  }
48
95
  });
49
- return { html, toc: extractToc(jsonWithIds, lockedTitles) };
96
+ return { html, toc: extractToc(jsonWithIds, lockedTitles), ok: true };
50
97
  } catch (e2) {
51
98
  console.error(
52
- "[renderReportHtml] Tiptap pipeline failed, falling back to empty content:",
99
+ "[renderReportHtml] TOC pipeline failed, rendering without heading ids:",
53
100
  e2.message
54
101
  );
55
- return { html: "", toc: [] };
102
+ try {
103
+ return { html: htmlFromJson(json), toc: [], ok: true };
104
+ } catch (e22) {
105
+ console.error(
106
+ "[renderReportHtml] Tiptap pipeline failed:",
107
+ e22.message
108
+ );
109
+ return { html: "", toc: [], ok: false };
110
+ }
56
111
  }
57
112
  }
58
113
  export {
@@ -70,6 +125,7 @@ export {
70
125
  m as mergeCommentIntervals,
71
126
  pureCodeBlock,
72
127
  pureImage,
73
- renderReportHtml
128
+ renderReportHtml,
129
+ stabilizeMarkdown
74
130
  };
75
131
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../src/renderReportHtml.ts"],"sourcesContent":["import {\n generateTocIds,\n TableOfContents,\n} from '@tiptap/extension-table-of-contents';\nimport type { JSONContent } from '@tiptap/core';\nimport { MarkdownManager } from '@tiptap/markdown';\nimport { renderToHTMLString } from '@tiptap/static-renderer';\nimport {\n applyCitationSources,\n type SourceRef,\n} from './citationUtils';\nimport { CitationRef } from './CitationRef';\nimport { baseExtensions, pureCodeBlock, pureImage } from './extensions';\nimport { renderMathElementHtml } from './math';\nimport { extractToc, type TocItem } from './toc/extractToc';\nimport { makeTocGetId } from './toc/tocSlug';\n\n/**\n * server 端把 markdown 渲成 HTML 字符串 + 目录(纯函数,无 editor / 无 window)。\n *\n * 走官方管线 `MarkdownManager.parse → generateTocIds → renderToHTMLString`,可在\n * Server Component / ISR 里直接跑,正文 HTML + 锚点 id 进静态产物,兑现 SEO / 首屏。\n *\n * 扩展集与编辑器同源(base + 纯版 CodeBlock/Image)+ TableOfContents。TOC 扩展在 v3\n * 会扩展 Heading schema 使 id 渲染进 HTML;`generateTocIds` 是官方纯函数(无 editor /\n * 无 window,专为「renderToHTMLString 前在 server 注入锚点」设计)。\n * 锚点用 slug + 去重(makeTocGetId),跨 SSR / ISR 稳定、可分享。\n *\n * `[^n]` 由 CitationRef tokenizer 解析;`sources` 经 {@link applyCitationSources}\n * 补 url/title(不依赖 DOMParser,避免 server 内联 HTML 失效)。\n *\n * 已知边界:官方包解析内联 HTML 依赖 window.DOMParser,server 端无 window 会把\n * 内联 HTML(如 <u>)转义为字面文本。\n */\nexport interface RenderedReport {\n html: string;\n toc: TocItem[];\n}\n\nexport interface RenderReportHtmlOptions {\n /** 被付费墙锁住的章节标题(TOC 标 locked)。 */\n lockedTitles?: string[];\n /** 脚注来源,按 index 对齐 `[^n]`。 */\n sources?: SourceRef[];\n}\n\n// [perf] 模块级复用单个 MarkdownManager。每次 `new MarkdownManager` 会让底层 marked\n// 全局累积扩展,parse 逐次变慢。parse 只用 schema、与 TOC 的 getId 无关,可跨调用\n// 安全复用;getId 相关的锚点注入放在 generateTocIds 阶段、用每篇新建的 extensions 处理。\nconst sharedManager = new MarkdownManager({\n extensions: [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n CitationRef,\n TableOfContents,\n ],\n});\n\nexport function renderReportHtml(\n markdown: string,\n lockedTitlesOrOptions: string[] | RenderReportHtmlOptions = [],\n): RenderedReport {\n if (!markdown?.trim()) return { html: '', toc: [] };\n\n const options: RenderReportHtmlOptions = Array.isArray(lockedTitlesOrOptions)\n ? { lockedTitles: lockedTitlesOrOptions }\n : lockedTitlesOrOptions;\n const lockedTitles = options.lockedTitles ?? [];\n const sources = options.sources ?? [];\n\n const json = applyCitationSources(\n sharedManager.parse(markdown) as JSONContent,\n sources,\n );\n\n // getId 是有状态去重闭包,每篇必须重置,否则锚点 id 跨调用串号。这份 extensions\n // 只喂 generateTocIds / renderToHTMLString——schema 与 sharedManager 一致(仅 getId\n // 配置不同,不影响 schema),故对 sharedManager.parse 出的 json 兼容。\n const extensions = [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n CitationRef,\n TableOfContents.configure({ getId: makeTocGetId() }),\n ];\n try {\n // 给 heading 注入 id / data-toc-id(server 端,renderToHTMLString 前)。\n const jsonWithIds = generateTocIds(json, extensions);\n const html = renderToHTMLString({\n extensions,\n content: jsonWithIds,\n options: {\n nodeMapping: {\n inlineMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), false),\n blockMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), true),\n },\n },\n });\n return { html, toc: extractToc(jsonWithIds, lockedTitles) };\n } catch (e) {\n // 某些 markdown 经 parse 产出的 JSON 可能在 heading 内嵌套 block 级子节点,\n // 导致 generateTocIds 的 setNodeMarkup 校验失败。单篇异常不应拖垮整个构建,\n // 降级返回空内容。\n console.error(\n '[renderReportHtml] Tiptap pipeline failed, falling back to empty content:',\n (e as Error).message,\n );\n return { html: '', toc: [] };\n }\n}\n"],"names":["e"],"mappings":";;;;;AAiDA,MAAM,gBAAgB,IAAI,gBAAgB;AAAA,EACxC,YAAY;AAAA,IACV,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ,CAAC;AAEM,SAAS,iBACd,UACA,wBAA4D,IAC5C;AAChB,MAAI,EAAC,qCAAU,QAAQ,QAAO,EAAE,MAAM,IAAI,KAAK,GAAC;AAEhD,QAAM,UAAmC,MAAM,QAAQ,qBAAqB,IACxE,EAAE,cAAc,0BAChB;AACJ,QAAM,eAAe,QAAQ,gBAAgB,CAAA;AAC7C,QAAM,UAAU,QAAQ,WAAW,CAAA;AAEnC,QAAM,OAAO;AAAA,IACX,cAAc,MAAM,QAAQ;AAAA,IAC5B;AAAA,EAAA;AAMF,QAAM,aAAa;AAAA,IACjB,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,UAAU,EAAE,OAAO,aAAA,GAAgB;AAAA,EAAA;AAErD,MAAI;AAEF,UAAM,cAAc,eAAe,MAAM,UAAU;AACnD,UAAM,OAAO,mBAAmB;AAAA,MAC9B;AAAA,MACA,SAAS;AAAA,MACT,SAAS;AAAA,QACP,aAAa;AAAA,UACX,YAAY,CAAC,EAAE,KAAA,MAAK;;AAClB,yCAAsB,SAAO,UAAK,UAAL,mBAAY,UAAS,EAAE,GAAG,KAAK;AAAA;AAAA,UAC9D,WAAW,CAAC,EAAE,KAAA,MAAK;;AACjB,yCAAsB,SAAO,UAAK,UAAL,mBAAY,UAAS,EAAE,GAAG,IAAI;AAAA;AAAA,QAAA;AAAA,MAC/D;AAAA,IACF,CACD;AACD,WAAO,EAAE,MAAM,KAAK,WAAW,aAAa,YAAY,EAAA;AAAA,EAC1D,SAASA,IAAG;AAIV,YAAQ;AAAA,MACN;AAAA,MACCA,GAAY;AAAA,IAAA;AAEf,WAAO,EAAE,MAAM,IAAI,KAAK,CAAA,EAAC;AAAA,EAC3B;AACF;"}
1
+ {"version":3,"file":"server.js","sources":["../src/renderReportHtml.ts"],"sourcesContent":["import {\n generateTocIds,\n TableOfContents,\n} from '@tiptap/extension-table-of-contents';\nimport type { JSONContent } from '@tiptap/core';\nimport { MarkdownManager } from '@tiptap/markdown';\nimport { renderToHTMLString } from '@tiptap/static-renderer';\nimport {\n applyCitationSources,\n type SourceRef,\n} from './citationUtils';\nimport { CitationRef } from './CitationRef';\nimport { baseExtensions, pureCodeBlock, pureImage } from './extensions';\nimport { renderMathElementHtml } from './math';\nimport { stabilizeMarkdown } from './stabilizeMarkdown';\nimport { extractToc, type TocItem } from './toc/extractToc';\nimport { makeTocGetId } from './toc/tocSlug';\n\n/**\n * server 端把 markdown 渲成 HTML 字符串 + 目录(纯函数,无 editor / 无 window)。\n *\n * 走官方管线 `MarkdownManager.parse → generateTocIds → renderToHTMLString`,可在\n * Server Component / ISR 里直接跑,正文 HTML + 锚点 id 进静态产物,兑现 SEO / 首屏。\n *\n * 扩展集与编辑器同源(base + 纯版 CodeBlock/Image)+ TableOfContents。TOC 扩展在 v3\n * 会扩展 Heading schema 使 id 渲染进 HTML;`generateTocIds` 是官方纯函数(无 editor /\n * 无 window,专为「renderToHTMLString 前在 server 注入锚点」设计)。\n * 锚点用 slug + 去重(makeTocGetId),跨 SSR / ISR 稳定、可分享。\n *\n * `[^n]` 由 CitationRef tokenizer 解析;`sources` 经 {@link applyCitationSources}\n * 补 url/title(不依赖 DOMParser,避免 server 内联 HTML 失效)。\n *\n * 已知边界:官方包解析内联 HTML 依赖 window.DOMParser,server 端无 window 会把\n * 内联 HTML(如 <u>)转义为字面文本。\n */\nexport interface RenderedReport {\n html: string;\n toc: TocItem[];\n /**\n * 管线是否成功。空 markdown 也是 ok。\n * parse / render 抛错时为 false;调用方可保留上一帧 HTML。\n */\n ok: boolean;\n}\n\nexport interface RenderReportHtmlOptions {\n /** 被付费墙锁住的章节标题(TOC 标 locked)。 */\n lockedTitles?: string[];\n /** 脚注来源,按 index 对齐 `[^n]`。 */\n sources?: SourceRef[];\n /**\n * 是否注入标题锚点并返回 toc。默认 true(`/p` 阅读页)。\n * 卡片预览传 false,跳过 generateTocIds。\n */\n includeToc?: boolean;\n /**\n * 流式半成品:补未闭合代码围栏。默认 false。\n * 完整落库稿不要开,以免改已发布 HTML。\n */\n stabilize?: boolean;\n}\n\n// [perf] 模块级复用单个 MarkdownManager。每次 `new MarkdownManager` 会让底层 marked\n// 全局累积扩展,parse 逐次变慢。parse 只用 schema、与 TOC 的 getId 无关,可跨调用\n// 安全复用;getId 相关的锚点注入放在 generateTocIds 阶段、用每篇新建的 extensions 处理。\nconst sharedManager = new MarkdownManager({\n extensions: [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n CitationRef,\n TableOfContents,\n ],\n});\n\nfunction htmlFromJson(json: JSONContent): string {\n const extensions = [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n CitationRef,\n TableOfContents.configure({ getId: makeTocGetId() }),\n ];\n return renderToHTMLString({\n extensions,\n content: json,\n options: {\n nodeMapping: {\n inlineMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), false),\n blockMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), true),\n },\n },\n });\n}\n\nexport function renderReportHtml(\n markdown: string,\n lockedTitlesOrOptions: string[] | RenderReportHtmlOptions = [],\n): RenderedReport {\n if (!markdown?.trim()) return { html: '', toc: [], ok: true };\n\n const options: RenderReportHtmlOptions = Array.isArray(lockedTitlesOrOptions)\n ? { lockedTitles: lockedTitlesOrOptions }\n : lockedTitlesOrOptions;\n const lockedTitles = options.lockedTitles ?? [];\n const sources = options.sources ?? [];\n const includeToc = options.includeToc !== false;\n const input = options.stabilize ? stabilizeMarkdown(markdown) : markdown;\n\n let json: JSONContent;\n try {\n json = applyCitationSources(\n sharedManager.parse(input) as JSONContent,\n sources,\n );\n } catch (e) {\n console.error(\n '[renderReportHtml] markdown parse failed:',\n (e as Error).message,\n );\n return { html: '', toc: [], ok: false };\n }\n\n if (!includeToc) {\n try {\n return { html: htmlFromJson(json), toc: [], ok: true };\n } catch (e) {\n console.error(\n '[renderReportHtml] render failed (no toc):',\n (e as Error).message,\n );\n return { html: '', toc: [], ok: false };\n }\n }\n\n // getId 是有状态去重闭包,每篇必须重置,否则锚点 id 跨调用串号。这份 extensions\n // 只喂 generateTocIds / renderToHTMLString——schema 与 sharedManager 一致(仅 getId\n // 配置不同,不影响 schema),故对 sharedManager.parse 出的 json 兼容。\n const extensions = [\n ...baseExtensions,\n pureCodeBlock,\n pureImage,\n CitationRef,\n TableOfContents.configure({ getId: makeTocGetId() }),\n ];\n try {\n const jsonWithIds = generateTocIds(json, extensions);\n const html = renderToHTMLString({\n extensions,\n content: jsonWithIds,\n options: {\n nodeMapping: {\n inlineMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), false),\n blockMath: ({ node }) =>\n renderMathElementHtml(String(node.attrs?.latex ?? ''), true),\n },\n },\n });\n return { html, toc: extractToc(jsonWithIds, lockedTitles), ok: true };\n } catch (e) {\n // 某些 markdown 经 parse 产出的 JSON 可能在 heading 内嵌套 block 级子节点,\n // 导致 generateTocIds 的 setNodeMarkup 校验失败。降级为无 TOC 仍产出正文。\n console.error(\n '[renderReportHtml] TOC pipeline failed, rendering without heading ids:',\n (e as Error).message,\n );\n try {\n return { html: htmlFromJson(json), toc: [], ok: true };\n } catch (e2) {\n console.error(\n '[renderReportHtml] Tiptap pipeline failed:',\n (e2 as Error).message,\n );\n return { html: '', toc: [], ok: false };\n }\n }\n}\n"],"names":["e","e2"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 给流式半成品 markdown 补闭合围栏,避免未结束的 ``` 把后文吞进 code。
3
+ * 完整稿不要调用(ISR / 已落库卡)。
4
+ */
5
+ export declare function stabilizeMarkdown(markdown: string): string;
@@ -0,0 +1 @@
1
+ export {};
package/dist/style.css CHANGED
@@ -328,9 +328,10 @@
328
328
  color: #c0392b;
329
329
  }
330
330
 
331
- /* 编辑中:占位仍在,视觉交给浮层预览,避免正文公式与预览叠两份 */
331
+ /* 编辑中:原文留在文档里,只加高亮;输入盒在下方,避免第二份 KaTeX 字号/行盒对不齐 */
332
332
  .tiptap-mathematics-render.tmr-math-editing {
333
- visibility: hidden;
333
+ background: #fff3ec;
334
+ border-radius: 4px;
334
335
  }
335
336
  /* 代码块 NodeView:白底、细边框、顶部 header 放语言选择(Radix 下拉)+ 删除。 */
336
337
  ._wrapper_5i2vi_2 {
@@ -532,7 +533,7 @@
532
533
  color: #22863a;
533
534
  }
534
535
  /* 顶部操作栏:横跨宽度、内容居中、细线灰图标。配色映射到可覆盖的 --tmr-* 变量。 */
535
- ._toolbar_w3tos_2 {
536
+ ._toolbar_16b09_2 {
536
537
  --sb-accent: var(--tmr-accent, #ff6719);
537
538
  --sb-text: var(--tmr-text, #363737);
538
539
  --sb-muted: var(--tmr-toolbar-muted, #6b6b6b);
@@ -545,7 +546,7 @@
545
546
  z-index: 8;
546
547
  }
547
548
 
548
- ._inner_w3tos_15 {
549
+ ._inner_16b09_15 {
549
550
  display: flex;
550
551
  align-items: center;
551
552
  justify-content: safe center;
@@ -557,7 +558,7 @@
557
558
  overflow-x: auto;
558
559
  }
559
560
 
560
- ._btn_w3tos_27 {
561
+ ._btn_16b09_27 {
561
562
  display: inline-flex;
562
563
  align-items: center;
563
564
  justify-content: center;
@@ -575,28 +576,28 @@
575
576
  transition: background 0.15s, color 0.15s;
576
577
  }
577
578
 
578
- ._btn_w3tos_27:hover:not(:disabled) {
579
+ ._btn_16b09_27:hover:not(:disabled) {
579
580
  background: #f3f3f3;
580
581
  color: var(--sb-text);
581
582
  }
582
583
 
583
- ._btnActive_w3tos_50 {
584
+ ._btnActive_16b09_50 {
584
585
  color: var(--sb-accent);
585
586
  background: #fff3ec;
586
587
  }
587
588
 
588
- ._btnActive_w3tos_50:hover {
589
+ ._btnActive_16b09_50:hover {
589
590
  color: var(--sb-accent);
590
591
  background: #ffe8da;
591
592
  }
592
593
 
593
- ._btn_w3tos_27:disabled {
594
+ ._btn_16b09_27:disabled {
594
595
  opacity: 0.3;
595
596
  cursor: not-allowed;
596
597
  }
597
598
 
598
599
  /* 表内浮动工具条(BubbleMenu portal 到 body,拿不到 .toolbar 变量,故写死配色) */
599
- ._tableBubble_w3tos_66 {
600
+ ._tableBubble_16b09_66 {
600
601
  display: flex;
601
602
  align-items: center;
602
603
  gap: 2px;
@@ -608,7 +609,7 @@
608
609
  }
609
610
 
610
611
  /* 文字型图标(引用等) */
611
- ._txtIcon_w3tos_78 {
612
+ ._txtIcon_16b09_78 {
612
613
  font-family: 'SF Pro Display', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
613
614
  font-size: 16px;
614
615
  font-weight: 600;
@@ -616,7 +617,7 @@
616
617
  }
617
618
 
618
619
  /* 文字颜色 / 高亮图标:字母 + 底部当前色条 */
619
- ._colorIcon_w3tos_86 {
620
+ ._colorIcon_16b09_86 {
620
621
  display: inline-flex;
621
622
  flex-direction: column;
622
623
  align-items: center;
@@ -624,20 +625,20 @@
624
625
  line-height: 1;
625
626
  }
626
627
 
627
- ._colorIconGlyph_w3tos_94 {
628
+ ._colorIconGlyph_16b09_94 {
628
629
  font-family: 'SF Pro Display', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
629
630
  font-size: 15px;
630
631
  font-weight: 600;
631
632
  }
632
633
 
633
- ._colorIconBar_w3tos_100 {
634
+ ._colorIconBar_16b09_100 {
634
635
  width: 16px;
635
636
  height: 3px;
636
637
  border-radius: 1.5px;
637
638
  }
638
639
 
639
640
  /* A▾ 上标/下标下拉触发器 */
640
- ._scriptTrigger_w3tos_107 {
641
+ ._scriptTrigger_16b09_107 {
641
642
  display: inline-flex;
642
643
  align-items: center;
643
644
  gap: 3px;
@@ -652,12 +653,12 @@
652
653
  transition: background 0.15s, color 0.15s;
653
654
  }
654
655
 
655
- ._scriptTrigger_w3tos_107:hover {
656
+ ._scriptTrigger_16b09_107:hover {
656
657
  background: #f3f3f3;
657
658
  color: var(--sb-text);
658
659
  }
659
660
 
660
- ._scriptTriggerGlyph_w3tos_127 {
661
+ ._scriptTriggerGlyph_16b09_127 {
661
662
  font-family: 'SF Pro Display', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
662
663
  font-size: 16px;
663
664
  font-weight: 600;
@@ -665,7 +666,7 @@
665
666
  text-underline-offset: 2px;
666
667
  }
667
668
 
668
- ._divider_w3tos_135 {
669
+ ._divider_16b09_135 {
669
670
  width: 1px;
670
671
  height: 20px;
671
672
  margin: 0 8px;
@@ -674,7 +675,7 @@
674
675
  }
675
676
 
676
677
  /* ── Style / Size / More 下拉触发器 ── */
677
- ._styleTrigger_w3tos_144 {
678
+ ._styleTrigger_16b09_144 {
678
679
  display: inline-flex;
679
680
  align-items: center;
680
681
  justify-content: space-between;
@@ -694,16 +695,16 @@
694
695
  transition: background 0.15s;
695
696
  }
696
697
 
697
- ._styleTrigger_w3tos_144:hover:not(:disabled) {
698
+ ._styleTrigger_16b09_144:hover:not(:disabled) {
698
699
  background: #f3f3f3;
699
700
  }
700
701
 
701
- ._styleTrigger_w3tos_144:disabled {
702
+ ._styleTrigger_16b09_144:disabled {
702
703
  opacity: 0.3;
703
704
  cursor: not-allowed;
704
705
  }
705
706
 
706
- ._styleTriggerLabel_w3tos_173 {
707
+ ._styleTriggerLabel_16b09_173 {
707
708
  flex: 1;
708
709
  text-align: left;
709
710
  overflow: hidden;
@@ -711,19 +712,19 @@
711
712
  text-overflow: ellipsis;
712
713
  }
713
714
 
714
- ._styleTriggerCaret_w3tos_181 {
715
+ ._styleTriggerCaret_16b09_181 {
715
716
  color: var(--sb-muted);
716
717
  flex: none;
717
718
  }
718
719
 
719
720
  /* 下拉项:图标 + 文字 */
720
- ._styleItem_w3tos_187 {
721
+ ._styleItem_16b09_187 {
721
722
  display: inline-flex;
722
723
  align-items: center;
723
724
  gap: 12px;
724
725
  }
725
726
 
726
- ._styleIcon_w3tos_193 {
727
+ ._styleIcon_16b09_193 {
727
728
  display: inline-flex;
728
729
  justify-content: center;
729
730
  align-items: center;
@@ -733,19 +734,19 @@
733
734
  }
734
735
 
735
736
  /* 上标 / 下标图标 */
736
- ._scriptGlyph_w3tos_203 {
737
+ ._scriptGlyph_16b09_203 {
737
738
  display: inline-block;
738
739
  text-align: center;
739
740
  font-family: 'SF Pro Display', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
740
741
  }
741
742
 
742
- ._scriptGlyph_w3tos_203 sup,
743
- ._scriptGlyph_w3tos_203 sub {
743
+ ._scriptGlyph_16b09_203 sup,
744
+ ._scriptGlyph_16b09_203 sub {
744
745
  font-size: 0.7em;
745
746
  }
746
747
 
747
748
  /* ── Radix 下拉菜单面板(替代 antd .ant-dropdown-menu) ── */
748
- ._menu_w3tos_215 {
749
+ ._menu_16b09_215 {
749
750
  min-width: 200px;
750
751
  padding: 6px;
751
752
  background: #fff;
@@ -756,7 +757,7 @@
756
757
  z-index: 1000;
757
758
  }
758
759
 
759
- ._menuItem_w3tos_226 {
760
+ ._menuItem_16b09_226 {
760
761
  display: flex;
761
762
  align-items: center;
762
763
  width: 100%;
@@ -772,52 +773,52 @@
772
773
  outline: none;
773
774
  }
774
775
 
775
- ._menuItem_w3tos_226:hover:not(:disabled) {
776
+ ._menuItem_16b09_226:hover:not(:disabled) {
776
777
  background: #f3f3f3;
777
778
  }
778
779
 
779
- ._menuItem_w3tos_226:disabled {
780
+ ._menuItem_16b09_226:disabled {
780
781
  opacity: 0.35;
781
782
  cursor: not-allowed;
782
783
  }
783
784
 
784
785
  /* 选中态:品牌色高亮 */
785
- ._menuItemSelected_w3tos_252 {
786
+ ._menuItemSelected_16b09_252 {
786
787
  background: #fff3ec;
787
788
  color: var(--sb-accent);
788
789
  }
789
790
 
790
- ._menuItemSelected_w3tos_252 ._styleIcon_w3tos_193 {
791
+ ._menuItemSelected_16b09_252 ._styleIcon_16b09_193 {
791
792
  color: var(--sb-accent);
792
793
  }
793
794
 
794
- ._menuItemSelected_w3tos_252:hover:not(:disabled) {
795
+ ._menuItemSelected_16b09_252:hover:not(:disabled) {
795
796
  background: #ffe8da;
796
797
  }
797
798
 
798
799
  /* Radix Popover 内容(承载 ColorPalette),面板自带阴影,这里只兜底 z-index */
799
- ._popoverContent_w3tos_266 {
800
+ ._popoverContent_16b09_266 {
800
801
  z-index: 1000;
801
802
  }
802
803
 
803
- ._mathLayer_w3tos_270 {
804
+ ._mathLayer_16b09_270 {
804
805
  position: absolute;
805
806
  z-index: 6;
806
807
  }
807
808
 
808
- ._mathStack_w3tos_275 {
809
+ ._mathStack_16b09_275 {
809
810
  display: flex;
810
811
  flex-direction: column;
811
812
  align-items: flex-start;
812
813
  gap: 8px;
813
814
  }
814
815
 
815
- ._mathStackBlock_w3tos_282 {
816
+ ._mathStackBlock_16b09_282 {
816
817
  align-items: stretch;
817
818
  width: 100%;
818
819
  }
819
820
 
820
- ._mathHint_w3tos_287 {
821
+ ._mathHint_16b09_287 {
821
822
  display: inline-flex;
822
823
  align-items: center;
823
824
  gap: 6px;
@@ -829,19 +830,19 @@
829
830
  line-height: 1.4;
830
831
  }
831
832
 
832
- ._mathHintBlock_w3tos_299 {
833
+ ._mathHintBlock_16b09_299 {
833
834
  width: 100%;
834
835
  padding: 10px 14px;
835
836
  border-radius: 8px;
836
837
  }
837
838
 
838
- ._mathHintIcon_w3tos_305 {
839
+ ._mathHintIcon_16b09_305 {
839
840
  font-family: ui-serif, Georgia, 'Times New Roman', serif;
840
841
  font-size: 12px;
841
842
  opacity: 0.85;
842
843
  }
843
844
 
844
- ._mathPreviewInline_w3tos_311 {
845
+ ._mathPreviewInline_16b09_311 {
845
846
  display: inline-flex;
846
847
  max-width: min(440px, calc(100vw - 24px));
847
848
  padding: 4px 10px;
@@ -849,25 +850,9 @@
849
850
  border-radius: 6px;
850
851
  background: #fff3ec;
851
852
  color: var(--tmr-text, #363737);
852
- /* KaTeX 1.21em 相对此字号;默认对齐 .editorContent,标题内公式由节点 computed size 覆盖 */
853
- font-family: var(
854
- --tmr-body-font,
855
- Spectral,
856
- serif,
857
- system-ui,
858
- -apple-system,
859
- BlinkMacSystemFont,
860
- 'Segoe UI',
861
- Roboto,
862
- Helvetica,
863
- Arial,
864
- sans-serif
865
- );
866
- font-size: var(--tmr-font-size, 19px);
867
- line-height: 1;
868
853
  }
869
854
 
870
- ._mathPreviewBlock_w3tos_337 {
855
+ ._mathPreviewBlock_16b09_321 {
871
856
  width: 100%;
872
857
  min-height: 48px;
873
858
  padding: 14px 16px;
@@ -876,28 +861,13 @@
876
861
  background: var(--tmr-code-bg, #f4f4f4);
877
862
  text-align: center;
878
863
  color: var(--tmr-text, #363737);
879
- font-family: var(
880
- --tmr-body-font,
881
- Spectral,
882
- serif,
883
- system-ui,
884
- -apple-system,
885
- BlinkMacSystemFont,
886
- 'Segoe UI',
887
- Roboto,
888
- Helvetica,
889
- Arial,
890
- sans-serif
891
- );
892
- font-size: var(--tmr-font-size, 19px);
893
- line-height: 1;
894
864
  }
895
865
 
896
- ._mathPreviewBlock_w3tos_337 .katex-display {
866
+ ._mathPreviewBlock_16b09_321 .katex-display {
897
867
  margin: 0;
898
868
  }
899
869
 
900
- ._mathField_w3tos_367 {
870
+ ._mathField_16b09_336 {
901
871
  display: flex;
902
872
  align-items: center;
903
873
  gap: 8px;
@@ -909,14 +879,14 @@
909
879
  box-shadow: 0 4px 16px rgb(0 0 0 / 12%);
910
880
  }
911
881
 
912
- ._mathFieldBlock_w3tos_379 {
882
+ ._mathFieldBlock_16b09_348 {
913
883
  align-items: flex-start;
914
884
  width: 100%;
915
885
  border-radius: 12px;
916
886
  padding: 10px 10px 10px 14px;
917
887
  }
918
888
 
919
- ._mathInput_w3tos_386 {
889
+ ._mathInput_16b09_355 {
920
890
  flex: 1;
921
891
  min-width: 0;
922
892
  margin: 0;
@@ -930,11 +900,11 @@
930
900
  resize: none;
931
901
  }
932
902
 
933
- ._mathInput_w3tos_386:focus {
903
+ ._mathInput_16b09_355:focus {
934
904
  outline: none;
935
905
  }
936
906
 
937
- ._mathDone_w3tos_404 {
907
+ ._mathDone_16b09_373 {
938
908
  display: inline-flex;
939
909
  align-items: center;
940
910
  gap: 4px;
@@ -950,16 +920,16 @@
950
920
  cursor: pointer;
951
921
  }
952
922
 
953
- ._mathDone_w3tos_404:hover:not(:disabled) {
923
+ ._mathDone_16b09_373:hover:not(:disabled) {
954
924
  filter: brightness(0.95);
955
925
  }
956
926
 
957
- ._mathDone_w3tos_404:disabled {
927
+ ._mathDone_16b09_373:disabled {
958
928
  opacity: 0.35;
959
929
  cursor: not-allowed;
960
930
  }
961
931
 
962
- ._mathDoneKbd_w3tos_429 {
932
+ ._mathDoneKbd_16b09_398 {
963
933
  font-size: 11px;
964
934
  font-weight: 500;
965
935
  opacity: 0.85;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiptap-markdown-react",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
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",