@atri-editor/core 0.4.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @atri-editor/core
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - cd42814: 修复任务列表勾选框与文字错位
8
+
9
+ 任务项里的正文段落带着 `0.5em` 上下外边距,放进 flex 行后会把文字压到勾选框下面;现在任务项内的段落不再吃外边距,由行高对齐。同一类问题还有表格:宿主页面的正文样式常把 `table` 改成块级元素,从而绕开横向滚动容器与固定列宽,现在表格显式声明 `display: table`。
10
+
11
+ ## 0.5.0
12
+
13
+ ### Minor Changes
14
+
15
+ - c69bd5b: 新增 `getMarkdownLosses()` 与 `hasLossyContent()`
16
+
17
+ 序列化器对没有 `renderMarkdown` 钩子的类型是静默丢弃,`getMarkdown()` 的返回值里看不出少了什么。现在可以在导出之前问一遍:返回 `{ kind: 'node' | 'mark' | 'attribute', type, attribute?, count }` 的数组。会进报告的有段落与标题对齐、合并单元格与拖过的列宽(pipe table 表达不了,合并会退化成一格有内容一格空着)、`inlineStyles: 'drop'` 下的颜色与上下标,以及没有 markdown 钩子的第三方节点。`count` 按连续区间合并,一个被加粗切成三段的红色短语算一处。
18
+
3
19
  ## 0.4.0
4
20
 
5
21
  ### Minor Changes
@@ -2,7 +2,7 @@
2
2
  * AtriEditor - 编辑器主类
3
3
  */
4
4
  import type { Editor, JSONContent } from '@tiptap/core';
5
- import type { AtriEditorOptions, IAtriEditor, InsertAttachmentOptions, InsertImageOptions, InsertTableOptions, MediaKind, SetContentOptions, AtriAIConfig, AtriNodeViewConfig } from './types';
5
+ import type { AtriEditorOptions, IAtriEditor, InsertAttachmentOptions, InsertImageOptions, InsertTableOptions, MarkdownLoss, MediaKind, SetContentOptions, AtriAIConfig, AtriNodeViewConfig } from './types';
6
6
  import { ThemeManager } from './core/ThemeManager';
7
7
  import { I18nManager } from './core/I18nManager';
8
8
  import { ExtensionManager } from './core/ExtensionManager';
@@ -69,6 +69,18 @@ export declare class AtriEditor implements IAtriEditor {
69
69
  * 获取 Markdown 内容
70
70
  */
71
71
  getMarkdown(): string;
72
+ /**
73
+ * 这一次 getMarkdown() 会丢掉哪些内容
74
+ *
75
+ * 序列化器对没钩子的类型是静默丢弃,所以"导出完看不出少了什么"是常态。接入方在保存前
76
+ * 拿它决定要不要提示用户,配 `markdown.inlineStyles: 'drop'` 时尤其需要——那个开关
77
+ * 就是把样式导出成最纯粹的 CommonMark,代价是丢内容。
78
+ */
79
+ getMarkdownLosses(): MarkdownLoss[];
80
+ /**
81
+ * 当前内容里有没有导出 Markdown 时会丢的东西
82
+ */
83
+ hasLossyContent(): boolean;
72
84
  /**
73
85
  * 设置内容
74
86
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AtriEditor.d.ts","sourceRoot":"","sources":["../src/AtriEditor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AtriEditor.d.ts","sourceRoot":"","sources":["../src/AtriEditor.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * AtriEditorElement - Web Component 封装
3
3
  */
4
4
  import { AtriEditor } from './AtriEditor';
5
- import type { AtriEditorOptions, InsertAttachmentOptions, InsertImageOptions, InsertTableOptions, MediaKind } from './types';
5
+ import type { AtriEditorOptions, InsertAttachmentOptions, InsertImageOptions, InsertTableOptions, MarkdownLoss, MediaKind } from './types';
6
6
  /**
7
7
  * SSR / 纯 Node 安全基类:类声明会在模块加载时求值 extends 后的表达式,
8
8
  * 直接 `extends HTMLElement` 会让无 DOM 的环境(Next/Nuxt 服务端、vitest node 池)
@@ -60,6 +60,17 @@ export declare class AtriEditorElement extends AtriEditorBase {
60
60
  * 获取 Markdown 内容
61
61
  */
62
62
  getMarkdown(): string;
63
+ /**
64
+ * 这一次 getMarkdown() 会丢掉哪些内容
65
+ *
66
+ * 元素还没初始化时是 null 而不是空数组——"没什么可丢"和"还没建起来"是两件事,
67
+ * 混在一起会让接入方把没就绪当成安全。
68
+ */
69
+ getMarkdownLosses(): MarkdownLoss[] | null;
70
+ /**
71
+ * 当前内容里有没有导出 Markdown 时会丢的东西
72
+ */
73
+ hasLossyContent(): boolean;
63
74
  /**
64
75
  * 设置内容
65
76
  */
@@ -1 +1 @@
1
- {"version":3,"file":"AtriEditorElement.d.ts","sourceRoot":"","sources":["../src/AtriEditorElement.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EACV,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACV,MAAM,SAAS,CAAC;AAIjB;;;;;GAKG;AACH,QAAA,MAAM,cAAc,EAAE,OAAO,WACmE,CAAC;AAEjG;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAS1C;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;IACnD,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,QAAQ,CAAkC;IAClD,gCAAgC;IAChC,OAAO,CAAC,aAAa,CAAK;IAC1B,sBAAsB;IACtB,OAAO,CAAC,eAAe,CAAuB;IAC9C,gCAAgC;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,cAEC;IAED,iBAAiB,IAAI,IAAI,CAIxB;IAED,oBAAoB,IAAI,IAAI,CAS3B;IAED;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAMd;IAED,OAAO,CAAC,cAAc;IAStB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAyB7F;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAIpD;IAED,OAAO,CAAC,UAAU;IAoDlB;;OAEG;IACH,SAAS,IAAI,UAAU,GAAG,IAAI,CAE7B;IAED;;OAEG;IACH,OAAO,IAAI,MAAM,CAEhB;IAED;;OAEG;IACH,OAAO,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED;;OAEG;IACH,WAAW,IAAI,MAAM,CAEpB;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhF;IAED;;OAEG;IACH,YAAY,IAAI,IAAI,CAEnB;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAE7C;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAEvD;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAE9C;IAED;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;IAED;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExC;IAED;;OAEG;IACH,iBAAiB,IAAI,OAAO,CAE3B;IAED;;OAEG;IACH,KAAK,IAAI,IAAI,CAEZ;CACF"}
1
+ {"version":3,"file":"AtriEditorElement.d.ts","sourceRoot":"","sources":["../src/AtriEditorElement.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,KAAK,EACV,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,SAAS,EACV,MAAM,SAAS,CAAC;AAIjB;;;;;GAKG;AACH,QAAA,MAAM,cAAc,EAAE,OAAO,WACmE,CAAC;AAEjG;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAS1C;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,cAAc;IACnD,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,QAAQ,CAAkC;IAClD,gCAAgC;IAChC,OAAO,CAAC,aAAa,CAAK;IAC1B,sBAAsB;IACtB,OAAO,CAAC,eAAe,CAAuB;IAC9C,gCAAgC;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,MAAM,KAAK,kBAAkB,IAAI,MAAM,EAAE,CAExC;IAED,cAEC;IAED,iBAAiB,IAAI,IAAI,CAIxB;IAED,oBAAoB,IAAI,IAAI,CAS3B;IAED;;;;;OAKG;IACH,OAAO,IAAI,IAAI,CAMd;IAED,OAAO,CAAC,cAAc;IAStB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAyB7F;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAIpD;IAED,OAAO,CAAC,UAAU;IAoDlB;;OAEG;IACH,SAAS,IAAI,UAAU,GAAG,IAAI,CAE7B;IAED;;OAEG;IACH,OAAO,IAAI,MAAM,CAEhB;IAED;;OAEG;IACH,OAAO,IAAI,MAAM,GAAG,IAAI,CAEvB;IAED;;OAEG;IACH,WAAW,IAAI,MAAM,CAEpB;IAED;;;;;OAKG;IACH,iBAAiB,IAAI,YAAY,EAAE,GAAG,IAAI,CAEzC;IAED;;OAEG;IACH,eAAe,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhF;IAED;;OAEG;IACH,YAAY,IAAI,IAAI,CAEnB;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAE7C;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CAEvD;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAE9C;IAED;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;IAED;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAExC;IAED;;OAEG;IACH,iBAAiB,IAAI,OAAO,CAE3B;IAED;;OAEG;IACH,KAAK,IAAI,IAAI,CAEZ;CACF"}
@@ -2,7 +2,7 @@
2
2
  * MarkdownService - Markdown 解析/序列化服务
3
3
  */
4
4
  import { type Editor, type JSONContent } from '@tiptap/core';
5
- import type { AtriMarkdownConfig } from '../types';
5
+ import type { AtriMarkdownConfig, MarkdownLoss } from '../types';
6
6
  export declare class MarkdownService {
7
7
  private editor;
8
8
  private config;
@@ -34,6 +34,17 @@ export declare class MarkdownService {
34
34
  * Markdown 转 JSON
35
35
  */
36
36
  markdownToJSON(markdown: string): JSONContent;
37
+ /**
38
+ * 这一趟 getMarkdown() 会丢掉什么,判据见 markdown-losses.ts
39
+ *
40
+ * Markdown 关闭时返回空数组:那时 getMarkdown() 走的是整篇 HTML 的降级转换,
41
+ * 不按类型分派,也就没有"哪个类型没有 renderer"可问。
42
+ */
43
+ getLosses(): MarkdownLoss[];
44
+ /**
45
+ * 有没有内容在导出 Markdown 时会丢,命名对齐 hasPendingUploads()
46
+ */
47
+ hasLossyContent(): boolean;
37
48
  /**
38
49
  * 是否启用
39
50
  */
@@ -1 +1 @@
1
- {"version":3,"file":"MarkdownService.d.ts","sourceRoot":"","sources":["../../src/core/MarkdownService.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAqB;IAEnC,YAAY,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,kBAAuB,EAM1D;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;;;OAIG;IACH,WAAW,IAAI,MAAM,CAMpB;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,IAAI,CAMpD;IAED;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUvC;IAED;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnC;IAED;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAe5C;IAED;;OAEG;IACH,SAAS,IAAI,OAAO,CAEnB;CACF"}
1
+ {"version":3,"file":"MarkdownService.d.ts","sourceRoot":"","sources":["../../src/core/MarkdownService.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAIjE,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAqB;IAEnC,YAAY,MAAM,EAAE,MAAM,EAAE,MAAM,GAAE,kBAAuB,EAM1D;IAED;;OAEG;IACH,OAAO,KAAK,OAAO,GAElB;IAED;;;;OAIG;IACH,WAAW,IAAI,MAAM,CAMpB;IAED;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,IAAI,CAMpD;IAED;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUvC;IAED;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASnC;IAED;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAe5C;IAED;;;;;OAKG;IACH,SAAS,IAAI,YAAY,EAAE,CAO1B;IAED;;OAEG;IACH,eAAe,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,SAAS,IAAI,OAAO,CAEnB;CACF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Markdown 丢失报告
3
+ *
4
+ * Tiptap 的序列化器对"没有 renderMarkdown 钩子的类型"是静默丢弃:不抛错、不降级成 HTML、
5
+ * 不留任何痕迹(MarkdownManager 的 renderNodeToMarkdown 在查不到 handler 时 return "",
6
+ * getMarkOpening 同理)。所以接入方只看 getMarkdown() 的返回值,是看不出这一趟导出丢了东西的。
7
+ * 这里做的事就是把这件事变成一次可查询的内省。
8
+ *
9
+ * 判据是"能力"而不是"内容 diff":diff 会被良性的归一化骗到——空段落在导出时被补成
10
+ * ` `(序列化器自己就有 isEmptyOutput 来认这种占位),markdown 转义又会改写文本字节,
11
+ * 任何一条都能凭空报出丢失。能力判据是确定的:类型有没有 renderer,正是序列化器自己要做的
12
+ * 判断,我们只是替它先算一遍。
13
+ */
14
+ import { type Editor } from '@tiptap/core';
15
+ import type { MarkdownLoss } from '../types';
16
+ export interface CollectLossesOptions {
17
+ /** 与 markdown.inlineStyles 一致 */
18
+ inlineStyles: 'html' | 'drop';
19
+ }
20
+ /**
21
+ * 走一遍当前文档,报告 `getMarkdown()` 会丢掉什么。
22
+ *
23
+ * 只统计文档里真实出现的类型,所以空文档的返回值恒为 `[]`,与装了哪些扩展无关。
24
+ */
25
+ export declare function collectMarkdownLosses(editor: Editor, options: CollectLossesOptions): MarkdownLoss[];
26
+ //# sourceMappingURL=markdown-losses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-losses.d.ts","sourceRoot":"","sources":["../../src/core/markdown-losses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAqB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAgF7C,MAAM,WAAW,oBAAoB;IACnC,iCAAiC;IACjC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,GAC5B,YAAY,EAAE,CAgFhB"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Node, mergeAttributes, Extension, isNodeSelection, Editor, getHTMLFromFragment, elementFromString, getTextBetween } from "@tiptap/core";
1
+ import { Node, mergeAttributes, Extension, isNodeSelection, Editor, getExtensionField, getHTMLFromFragment, elementFromString, getTextBetween } from "@tiptap/core";
2
2
  import StarterKit from "@tiptap/starter-kit";
3
3
  import { Markdown } from "@tiptap/markdown";
4
4
  import { Placeholder } from "@tiptap/extensions";
@@ -1664,6 +1664,100 @@ const markdown = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
1664
1664
  simpleHtmlToMarkdown,
1665
1665
  simpleMarkdownToHtml
1666
1666
  }, Symbol.toStringTag, { value: "Module" }));
1667
+ const RENDERED_BY_PARENT = ["tableRow", "tableHeader", "tableCell"];
1668
+ const LOSSY_ATTRIBUTES = {
1669
+ paragraph: ["textAlign"],
1670
+ heading: ["textAlign"],
1671
+ tableCell: ["colspan", "rowspan", "colwidth"],
1672
+ tableHeader: ["colspan", "rowspan", "colwidth"]
1673
+ };
1674
+ const LOSSY_ATTRIBUTES_WHEN_STYLES_DROPPED = {
1675
+ highlight: ["color"]
1676
+ };
1677
+ const RENDERING_NEUTRAL_VALUES = {
1678
+ textAlign: ["left"]
1679
+ };
1680
+ function isSignificant(value, defaultValue, attribute) {
1681
+ var _a;
1682
+ if (value === defaultValue || value === null || value === void 0) return false;
1683
+ if (Array.isArray(value)) {
1684
+ return value.some((item) => typeof item === "number" && item > 0);
1685
+ }
1686
+ if (typeof value === "string") {
1687
+ if (value.trim() === "") return false;
1688
+ if ((_a = RENDERING_NEUTRAL_VALUES[attribute]) == null ? void 0 : _a.includes(value)) return false;
1689
+ }
1690
+ return true;
1691
+ }
1692
+ function buildRenderableTypes(editor) {
1693
+ const schemaTypes = /* @__PURE__ */ new Set([
1694
+ ...Object.keys(editor.schema.nodes),
1695
+ ...Object.keys(editor.schema.marks)
1696
+ ]);
1697
+ const renderable = /* @__PURE__ */ new Set();
1698
+ for (const extension of editor.extensionManager.extensions) {
1699
+ if (!schemaTypes.has(extension.name)) continue;
1700
+ if (getExtensionField(extension, "renderMarkdown")) renderable.add(extension.name);
1701
+ }
1702
+ return renderable;
1703
+ }
1704
+ function collectMarkdownLosses(editor, options) {
1705
+ const renderable = buildRenderableTypes(editor);
1706
+ const nodes = /* @__PURE__ */ new Map();
1707
+ const marks = /* @__PURE__ */ new Map();
1708
+ const attributes = /* @__PURE__ */ new Map();
1709
+ const countAttribute = (type, attribute, count) => {
1710
+ const key = `${type}/${attribute}`;
1711
+ const entry = attributes.get(key);
1712
+ if (entry) entry.count += count;
1713
+ else attributes.set(key, { loss: { kind: "attribute", type, attribute, count }, count });
1714
+ };
1715
+ let previousMarkNames = /* @__PURE__ */ new Set();
1716
+ const checkAttributes = (owner, attrs, specAttrs) => {
1717
+ var _a;
1718
+ const defaults = specAttrs ?? {};
1719
+ const tables = options.inlineStyles === "drop" ? [LOSSY_ATTRIBUTES, LOSSY_ATTRIBUTES_WHEN_STYLES_DROPPED] : [LOSSY_ATTRIBUTES];
1720
+ for (const table of tables) {
1721
+ for (const attribute of table[owner] ?? []) {
1722
+ if (isSignificant(attrs[attribute], (_a = defaults[attribute]) == null ? void 0 : _a.default, attribute)) {
1723
+ countAttribute(owner, attribute, 1);
1724
+ }
1725
+ }
1726
+ }
1727
+ };
1728
+ editor.state.doc.descendants((node, _position, parent) => {
1729
+ const name = node.type.name;
1730
+ if (name === "text") {
1731
+ const fresh = node.marks.filter((mark) => !previousMarkNames.has(mark.type.name));
1732
+ previousMarkNames = new Set(node.marks.map((mark) => mark.type.name));
1733
+ for (const mark of fresh) {
1734
+ if (!renderable.has(mark.type.name)) {
1735
+ marks.set(mark.type.name, (marks.get(mark.type.name) ?? 0) + 1);
1736
+ }
1737
+ checkAttributes(mark.type.name, mark.attrs, mark.type.spec.attrs);
1738
+ }
1739
+ return;
1740
+ }
1741
+ checkAttributes(name, node.attrs, node.type.spec.attrs);
1742
+ if (parent && !renderable.has(name) && !RENDERED_BY_PARENT.includes(name)) {
1743
+ nodes.set(name, (nodes.get(name) ?? 0) + 1);
1744
+ previousMarkNames = /* @__PURE__ */ new Set();
1745
+ return false;
1746
+ }
1747
+ previousMarkNames = /* @__PURE__ */ new Set();
1748
+ return true;
1749
+ });
1750
+ const byCountThenName = (a, b) => b[1] - a[1] || a[0].localeCompare(b[0]);
1751
+ const ofKind = (kind) => (entry) => ({ kind, type: entry[0], count: entry[1] });
1752
+ const losses = [
1753
+ ...Array.from(nodes.entries()).sort(byCountThenName).map(ofKind("node")),
1754
+ ...Array.from(marks.entries()).sort(byCountThenName).map(ofKind("mark"))
1755
+ ];
1756
+ for (const entry of attributes.values()) {
1757
+ losses.push(entry.loss);
1758
+ }
1759
+ return losses;
1760
+ }
1667
1761
  class MarkdownService {
1668
1762
  constructor(editor, config = {}) {
1669
1763
  this.editor = editor;
@@ -1746,6 +1840,26 @@ class MarkdownService {
1746
1840
  ]
1747
1841
  };
1748
1842
  }
1843
+ /**
1844
+ * 这一趟 getMarkdown() 会丢掉什么,判据见 markdown-losses.ts
1845
+ *
1846
+ * Markdown 关闭时返回空数组:那时 getMarkdown() 走的是整篇 HTML 的降级转换,
1847
+ * 不按类型分派,也就没有"哪个类型没有 renderer"可问。
1848
+ */
1849
+ getLosses() {
1850
+ if (!this.manager) {
1851
+ return [];
1852
+ }
1853
+ return collectMarkdownLosses(this.editor, {
1854
+ inlineStyles: this.config.inlineStyles ?? "html"
1855
+ });
1856
+ }
1857
+ /**
1858
+ * 有没有内容在导出 Markdown 时会丢,命名对齐 hasPendingUploads()
1859
+ */
1860
+ hasLossyContent() {
1861
+ return this.getLosses().length > 0;
1862
+ }
1749
1863
  /**
1750
1864
  * 是否启用
1751
1865
  */
@@ -4949,6 +5063,22 @@ class AtriEditor {
4949
5063
  getMarkdown() {
4950
5064
  return this.markdownService.getMarkdown();
4951
5065
  }
5066
+ /**
5067
+ * 这一次 getMarkdown() 会丢掉哪些内容
5068
+ *
5069
+ * 序列化器对没钩子的类型是静默丢弃,所以"导出完看不出少了什么"是常态。接入方在保存前
5070
+ * 拿它决定要不要提示用户,配 `markdown.inlineStyles: 'drop'` 时尤其需要——那个开关
5071
+ * 就是把样式导出成最纯粹的 CommonMark,代价是丢内容。
5072
+ */
5073
+ getMarkdownLosses() {
5074
+ return this.markdownService.getLosses();
5075
+ }
5076
+ /**
5077
+ * 当前内容里有没有导出 Markdown 时会丢的东西
5078
+ */
5079
+ hasLossyContent() {
5080
+ return this.markdownService.hasLossyContent();
5081
+ }
4952
5082
  /**
4953
5083
  * 设置内容
4954
5084
  */
@@ -5359,6 +5489,23 @@ class AtriEditorElement extends AtriEditorBase {
5359
5489
  var _a;
5360
5490
  return ((_a = this.editor) == null ? void 0 : _a.getMarkdown()) || "";
5361
5491
  }
5492
+ /**
5493
+ * 这一次 getMarkdown() 会丢掉哪些内容
5494
+ *
5495
+ * 元素还没初始化时是 null 而不是空数组——"没什么可丢"和"还没建起来"是两件事,
5496
+ * 混在一起会让接入方把没就绪当成安全。
5497
+ */
5498
+ getMarkdownLosses() {
5499
+ var _a;
5500
+ return ((_a = this.editor) == null ? void 0 : _a.getMarkdownLosses()) ?? null;
5501
+ }
5502
+ /**
5503
+ * 当前内容里有没有导出 Markdown 时会丢的东西
5504
+ */
5505
+ hasLossyContent() {
5506
+ var _a;
5507
+ return ((_a = this.editor) == null ? void 0 : _a.hasLossyContent()) ?? false;
5508
+ }
5362
5509
  /**
5363
5510
  * 设置内容
5364
5511
  */