@maxoyed/ode-core 0.0.1 → 0.2.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.
package/README.md CHANGED
@@ -28,6 +28,7 @@ editor.chain().focus().setOfficialRole("title").run();
28
28
 
29
29
  - `@maxoyed/ode-core/spec` — GB/T 9704-2012 版式规范(纯数据,零依赖)
30
30
  - `@maxoyed/ode-core/pagination` — headless 分页引擎(纯函数)
31
+ - `@maxoyed/ode-core/validate` — 合规校验(`validateDocument`,纯函数)
31
32
  - `@maxoyed/ode-core/docx` — docx 导入/导出(`toDocxBlob` / `fromDocx`)
32
33
 
33
34
  ```ts
@@ -40,6 +41,7 @@ import { toDocxBlob, fromDocx } from "@maxoyed/ode-core/docx";
40
41
  - 公文版式渲染与编辑(红头、标题、各级标题、正文、署名、版记、页码…)
41
42
  - 精确分页:headless 引擎 + 编辑器内联实时分页(行级跨页断行)+ 打印 / 导出 PDF
42
43
  - docx 往返:命名样式无损 · 表格(含合并单元格)· 图片 · 印章 · 版记线
44
+ - 合规校验 `validateDocument`:按 GB/T 9704 检查要素完整性/顺序/格式
43
45
  - 字体插槽 `registerFont`:开源字体兜底 + 用户授权字体注入
44
46
 
45
47
  ## 字体与版权
@@ -0,0 +1,80 @@
1
+ // src/validate/validate.ts
2
+ function textOf(node) {
3
+ if (node.type === "text") return node.text ?? "";
4
+ return (node.content ?? []).map(textOf).join("");
5
+ }
6
+ function toBlocks(doc) {
7
+ const top = (doc.type === "doc" ? doc.content : [doc]) ?? [];
8
+ return top.map((node, index) => ({
9
+ index,
10
+ type: node.type ?? "",
11
+ role: node.attrs?.officialRole ?? null,
12
+ text: textOf(node).trim()
13
+ }));
14
+ }
15
+ var DEFAULT_REQUIRED = ["title", "body"];
16
+ var DEFAULT_RECOMMENDED = ["mainRecipient", "signature", "dateline"];
17
+ var MISSING_MESSAGE = {
18
+ title: "\u7F3A\u5C11\u6807\u9898",
19
+ body: "\u7F3A\u5C11\u6B63\u6587",
20
+ mainRecipient: "\u7F3A\u5C11\u4E3B\u9001\u673A\u5173",
21
+ signature: "\u7F3A\u5C11\u53D1\u6587\u673A\u5173\u7F72\u540D",
22
+ dateline: "\u7F3A\u5C11\u6210\u6587\u65E5\u671F"
23
+ };
24
+ var MISSING_CODE = {
25
+ title: "MISSING_TITLE",
26
+ body: "MISSING_BODY",
27
+ mainRecipient: "MISSING_MAIN_RECIPIENT",
28
+ signature: "MISSING_SIGNATURE",
29
+ dateline: "MISSING_DATELINE"
30
+ };
31
+ function hasElement(blocks, role) {
32
+ return blocks.some((b) => b.role === role && b.text.length > 0);
33
+ }
34
+ function validateDocument(doc, options = {}) {
35
+ const required = options.required ?? DEFAULT_REQUIRED;
36
+ const recommended = options.recommended ?? DEFAULT_RECOMMENDED;
37
+ const blocks = toBlocks(doc);
38
+ const issues = [];
39
+ const nonEmpty = blocks.filter((b) => b.text.length > 0 || b.type === "table" || b.type === "image");
40
+ if (nonEmpty.length === 0) {
41
+ issues.push({ level: "error", code: "EMPTY_DOCUMENT", message: "\u6587\u6863\u4E3A\u7A7A" });
42
+ return issues;
43
+ }
44
+ for (const role of required) {
45
+ if (!hasElement(blocks, role)) {
46
+ issues.push({ level: "error", code: MISSING_CODE[role] ?? "MISSING_BODY", message: MISSING_MESSAGE[role] ?? `\u7F3A\u5C11\u8981\u7D20 ${role}` });
47
+ }
48
+ }
49
+ for (const role of recommended) {
50
+ if (!hasElement(blocks, role)) {
51
+ issues.push({ level: "warn", code: MISSING_CODE[role] ?? "MISSING_SIGNATURE", message: MISSING_MESSAGE[role] ?? `\u5EFA\u8BAE\u8865\u5145 ${role}` });
52
+ }
53
+ }
54
+ const title = blocks.find((b) => b.role === "title" && b.text.length > 0);
55
+ if (title && /[。!?,、;:]$/.test(title.text)) {
56
+ issues.push({ level: "warn", code: "TITLE_TRAILING_PUNCT", message: "\u6807\u9898\u4E0D\u5E94\u4EE5\u6807\u70B9\u7B26\u53F7\u7ED3\u5C3E", blockIndex: title.index });
57
+ }
58
+ const docNumber = blocks.find((b) => b.role === "docNumber" && b.text.length > 0);
59
+ if (docNumber && !/〔\s*\d{4}\s*〕.*号/.test(docNumber.text)) {
60
+ issues.push({ level: "warn", code: "DOC_NUMBER_FORMAT", message: "\u53D1\u6587\u5B57\u53F7\u683C\u5F0F\u5EFA\u8BAE\u4E3A\u300C\u673A\u5173\u4EE3\u5B57\u3014\u5E74\u4EFD\u3015\u5E8F\u53F7 \u53F7\u300D", blockIndex: docNumber.index });
61
+ }
62
+ const dateline = blocks.find((b) => b.role === "dateline" && b.text.length > 0);
63
+ if (dateline && !/\d{4}\s*年\s*\d{1,2}\s*月\s*\d{1,2}\s*日/.test(dateline.text)) {
64
+ issues.push({ level: "warn", code: "DATELINE_FORMAT", message: "\u6210\u6587\u65E5\u671F\u5E94\u4F7F\u7528\u963F\u62C9\u4F2F\u6570\u5B57\uFF0C\u5F62\u5982\u300C2026\u5E746\u670813\u65E5\u300D", blockIndex: dateline.index });
65
+ }
66
+ const sigIdx = blocks.find((b) => b.role === "signature" && b.text.length > 0)?.index;
67
+ if (sigIdx !== void 0 && dateline && dateline.index < sigIdx) {
68
+ issues.push({ level: "warn", code: "DATELINE_BEFORE_SIGNATURE", message: "\u6210\u6587\u65E5\u671F\u5E94\u6392\u5728\u53D1\u6587\u673A\u5173\u7F72\u540D\u4E4B\u540E", blockIndex: dateline.index });
69
+ }
70
+ return issues;
71
+ }
72
+ function isValid(doc, options) {
73
+ return validateDocument(doc, options).every((i) => i.level !== "error");
74
+ }
75
+
76
+ export {
77
+ validateDocument,
78
+ isValid
79
+ };
80
+ //# sourceMappingURL=chunk-VDLZ23IA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/validate/validate.ts"],"sourcesContent":["/**\n * 公文合规校验器(headless,纯函数,零 DOM)。\n *\n * 依 GB/T 9704-2012 对一篇公文(Tiptap/ProseMirror JSON)做结构与格式校验,\n * 返回问题列表。当前规则集面向下行文(如「通知」),可通过 options 调整必备要素。\n */\nimport type { JSONContent } from \"@tiptap/core\";\nimport type { OfficialElement } from \"../spec/elements\";\n\nexport type IssueLevel = \"error\" | \"warn\";\n\nexport type IssueCode =\n | \"EMPTY_DOCUMENT\"\n | \"MISSING_TITLE\"\n | \"MISSING_BODY\"\n | \"MISSING_MAIN_RECIPIENT\"\n | \"MISSING_SIGNATURE\"\n | \"MISSING_DATELINE\"\n | \"TITLE_TRAILING_PUNCT\"\n | \"DOC_NUMBER_FORMAT\"\n | \"DATELINE_FORMAT\"\n | \"DATELINE_BEFORE_SIGNATURE\";\n\nexport interface Issue {\n level: IssueLevel;\n code: IssueCode;\n message: string;\n /** 相关块在 doc.content 中的下标(若适用) */\n blockIndex?: number;\n}\n\nexport interface ValidateOptions {\n /** 必备要素(缺失记为 error);缺省为 [\"title\", \"body\"] */\n required?: OfficialElement[];\n /** 建议要素(缺失记为 warn);缺省为 [\"mainRecipient\", \"signature\", \"dateline\"] */\n recommended?: OfficialElement[];\n}\n\ninterface Block {\n index: number;\n type: string;\n role: OfficialElement | null;\n text: string;\n}\n\nfunction textOf(node: JSONContent): string {\n if (node.type === \"text\") return node.text ?? \"\";\n return (node.content ?? []).map(textOf).join(\"\");\n}\n\nfunction toBlocks(doc: JSONContent): Block[] {\n const top = (doc.type === \"doc\" ? doc.content : [doc]) ?? [];\n return top.map((node, index) => ({\n index,\n type: node.type ?? \"\",\n role: (node.attrs?.officialRole as OfficialElement | undefined) ?? null,\n text: textOf(node).trim(),\n }));\n}\n\nconst DEFAULT_REQUIRED: OfficialElement[] = [\"title\", \"body\"];\nconst DEFAULT_RECOMMENDED: OfficialElement[] = [\"mainRecipient\", \"signature\", \"dateline\"];\n\nconst MISSING_MESSAGE: Partial<Record<OfficialElement, string>> = {\n title: \"缺少标题\",\n body: \"缺少正文\",\n mainRecipient: \"缺少主送机关\",\n signature: \"缺少发文机关署名\",\n dateline: \"缺少成文日期\",\n};\n\nconst MISSING_CODE: Partial<Record<OfficialElement, IssueCode>> = {\n title: \"MISSING_TITLE\",\n body: \"MISSING_BODY\",\n mainRecipient: \"MISSING_MAIN_RECIPIENT\",\n signature: \"MISSING_SIGNATURE\",\n dateline: \"MISSING_DATELINE\",\n};\n\n/** 某要素是否“存在且有内容”。 */\nfunction hasElement(blocks: Block[], role: OfficialElement): boolean {\n return blocks.some((b) => b.role === role && b.text.length > 0);\n}\n\n/** 校验一篇公文,返回问题列表(空数组表示通过)。 */\nexport function validateDocument(doc: JSONContent, options: ValidateOptions = {}): Issue[] {\n const required = options.required ?? DEFAULT_REQUIRED;\n const recommended = options.recommended ?? DEFAULT_RECOMMENDED;\n const blocks = toBlocks(doc);\n const issues: Issue[] = [];\n\n const nonEmpty = blocks.filter((b) => b.text.length > 0 || b.type === \"table\" || b.type === \"image\");\n if (nonEmpty.length === 0) {\n issues.push({ level: \"error\", code: \"EMPTY_DOCUMENT\", message: \"文档为空\" });\n return issues;\n }\n\n // 必备 / 建议要素\n for (const role of required) {\n if (!hasElement(blocks, role)) {\n issues.push({ level: \"error\", code: MISSING_CODE[role] ?? \"MISSING_BODY\", message: MISSING_MESSAGE[role] ?? `缺少要素 ${role}` });\n }\n }\n for (const role of recommended) {\n if (!hasElement(blocks, role)) {\n issues.push({ level: \"warn\", code: MISSING_CODE[role] ?? \"MISSING_SIGNATURE\", message: MISSING_MESSAGE[role] ?? `建议补充 ${role}` });\n }\n }\n\n // 标题不应以句末标点结尾\n const title = blocks.find((b) => b.role === \"title\" && b.text.length > 0);\n if (title && /[。!?,、;:]$/.test(title.text)) {\n issues.push({ level: \"warn\", code: \"TITLE_TRAILING_PUNCT\", message: \"标题不应以标点符号结尾\", blockIndex: title.index });\n }\n\n // 发文字号格式:应形如「○府〔2026〕1 号」(含〔四位年〕与“号”)\n const docNumber = blocks.find((b) => b.role === \"docNumber\" && b.text.length > 0);\n if (docNumber && !/〔\\s*\\d{4}\\s*〕.*号/.test(docNumber.text)) {\n issues.push({ level: \"warn\", code: \"DOC_NUMBER_FORMAT\", message: \"发文字号格式建议为「机关代字〔年份〕序号 号」\", blockIndex: docNumber.index });\n }\n\n // 成文日期:应使用阿拉伯数字的「YYYY年M月D日」\n const dateline = blocks.find((b) => b.role === \"dateline\" && b.text.length > 0);\n if (dateline && !/\\d{4}\\s*年\\s*\\d{1,2}\\s*月\\s*\\d{1,2}\\s*日/.test(dateline.text)) {\n issues.push({ level: \"warn\", code: \"DATELINE_FORMAT\", message: \"成文日期应使用阿拉伯数字,形如「2026年6月13日」\", blockIndex: dateline.index });\n }\n\n // 成文日期应在发文机关署名之后\n const sigIdx = blocks.find((b) => b.role === \"signature\" && b.text.length > 0)?.index;\n if (sigIdx !== undefined && dateline && dateline.index < sigIdx) {\n issues.push({ level: \"warn\", code: \"DATELINE_BEFORE_SIGNATURE\", message: \"成文日期应排在发文机关署名之后\", blockIndex: dateline.index });\n }\n\n return issues;\n}\n\n/** 便捷方法:是否通过(无 error 级问题)。 */\nexport function isValid(doc: JSONContent, options?: ValidateOptions): boolean {\n return validateDocument(doc, options).every((i) => i.level !== \"error\");\n}\n"],"mappings":";AA6CA,SAAS,OAAO,MAA2B;AACzC,MAAI,KAAK,SAAS,OAAQ,QAAO,KAAK,QAAQ;AAC9C,UAAQ,KAAK,WAAW,CAAC,GAAG,IAAI,MAAM,EAAE,KAAK,EAAE;AACjD;AAEA,SAAS,SAAS,KAA2B;AAC3C,QAAM,OAAO,IAAI,SAAS,QAAQ,IAAI,UAAU,CAAC,GAAG,MAAM,CAAC;AAC3D,SAAO,IAAI,IAAI,CAAC,MAAM,WAAW;AAAA,IAC/B;AAAA,IACA,MAAM,KAAK,QAAQ;AAAA,IACnB,MAAO,KAAK,OAAO,gBAAgD;AAAA,IACnE,MAAM,OAAO,IAAI,EAAE,KAAK;AAAA,EAC1B,EAAE;AACJ;AAEA,IAAM,mBAAsC,CAAC,SAAS,MAAM;AAC5D,IAAM,sBAAyC,CAAC,iBAAiB,aAAa,UAAU;AAExF,IAAM,kBAA4D;AAAA,EAChE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,eAAe;AAAA,EACf,WAAW;AAAA,EACX,UAAU;AACZ;AAEA,IAAM,eAA4D;AAAA,EAChE,OAAO;AAAA,EACP,MAAM;AAAA,EACN,eAAe;AAAA,EACf,WAAW;AAAA,EACX,UAAU;AACZ;AAGA,SAAS,WAAW,QAAiB,MAAgC;AACnE,SAAO,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,KAAK,SAAS,CAAC;AAChE;AAGO,SAAS,iBAAiB,KAAkB,UAA2B,CAAC,GAAY;AACzF,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,cAAc,QAAQ,eAAe;AAC3C,QAAM,SAAS,SAAS,GAAG;AAC3B,QAAM,SAAkB,CAAC;AAEzB,QAAM,WAAW,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,SAAS,KAAK,EAAE,SAAS,WAAW,EAAE,SAAS,OAAO;AACnG,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,KAAK,EAAE,OAAO,SAAS,MAAM,kBAAkB,SAAS,2BAAO,CAAC;AACvE,WAAO;AAAA,EACT;AAGA,aAAW,QAAQ,UAAU;AAC3B,QAAI,CAAC,WAAW,QAAQ,IAAI,GAAG;AAC7B,aAAO,KAAK,EAAE,OAAO,SAAS,MAAM,aAAa,IAAI,KAAK,gBAAgB,SAAS,gBAAgB,IAAI,KAAK,4BAAQ,IAAI,GAAG,CAAC;AAAA,IAC9H;AAAA,EACF;AACA,aAAW,QAAQ,aAAa;AAC9B,QAAI,CAAC,WAAW,QAAQ,IAAI,GAAG;AAC7B,aAAO,KAAK,EAAE,OAAO,QAAQ,MAAM,aAAa,IAAI,KAAK,qBAAqB,SAAS,gBAAgB,IAAI,KAAK,4BAAQ,IAAI,GAAG,CAAC;AAAA,IAClI;AAAA,EACF;AAGA,QAAM,QAAQ,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,KAAK,SAAS,CAAC;AACxE,MAAI,SAAS,aAAa,KAAK,MAAM,IAAI,GAAG;AAC1C,WAAO,KAAK,EAAE,OAAO,QAAQ,MAAM,wBAAwB,SAAS,sEAAe,YAAY,MAAM,MAAM,CAAC;AAAA,EAC9G;AAGA,QAAM,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,KAAK,SAAS,CAAC;AAChF,MAAI,aAAa,CAAC,mBAAmB,KAAK,UAAU,IAAI,GAAG;AACzD,WAAO,KAAK,EAAE,OAAO,QAAQ,MAAM,qBAAqB,SAAS,yIAA2B,YAAY,UAAU,MAAM,CAAC;AAAA,EAC3H;AAGA,QAAM,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,KAAK,SAAS,CAAC;AAC9E,MAAI,YAAY,CAAC,wCAAwC,KAAK,SAAS,IAAI,GAAG;AAC5E,WAAO,KAAK,EAAE,OAAO,QAAQ,MAAM,mBAAmB,SAAS,mIAA+B,YAAY,SAAS,MAAM,CAAC;AAAA,EAC5H;AAGA,QAAM,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,eAAe,EAAE,KAAK,SAAS,CAAC,GAAG;AAChF,MAAI,WAAW,UAAa,YAAY,SAAS,QAAQ,QAAQ;AAC/D,WAAO,KAAK,EAAE,OAAO,QAAQ,MAAM,6BAA6B,SAAS,8FAAmB,YAAY,SAAS,MAAM,CAAC;AAAA,EAC1H;AAEA,SAAO;AACT;AAGO,SAAS,QAAQ,KAAkB,SAAoC;AAC5E,SAAO,iBAAiB,KAAK,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,OAAO;AACxE;","names":[]}
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { CHARS_PER_LINE, CHAR_BOX_MM, LINES_PER_PAGE, LINE_HEIGHT_MM, Layout, La
2
2
  import { O as OfficialElement, F as FontRole } from './elements-Bvueu_TD.js';
3
3
  export { C as ChineseFontSizeName, E as ELEMENT_SPEC, a as ElementSpec, b as FONT_CSS_VAR, c as FONT_SIZE_PT, d as FONT_STACK, e as OFFICIAL_RED, P as PT_TO_MM, f as PT_TO_PX, p as ptToMm, g as ptToPx, t as toHalfPoint, h as toPt } from './elements-Bvueu_TD.js';
4
4
  export { BODY_LINE_HEIGHT_PT, BlockRect, DASH, PAGE_NUMBER_OFFSET_MM, Page, PageBreak, PageBreakOptions, PageBreakResult, PageFragment, PageNumberAlign, PageNumberStyle, PaginateOptions, PaginationBlock, TYPE_AREA_HEIGHT_PT, blocksFromDoc, charsPerLineFor, computePageBreaks, countPages, estimateLines, formatPageNumber, lineHeightPtFor, pageNumberAlign, pageNumberStyle, paginate } from './pagination/index.js';
5
+ export { Issue, IssueCode, IssueLevel, ValidateOptions, isValid, validateDocument } from './validate/index.js';
5
6
  import * as _tiptap_core from '@tiptap/core';
6
7
  import { Extension, Extensions, JSONContent, EditorOptions, Editor } from '@tiptap/core';
7
8
  export { Editor, JSONContent } from '@tiptap/core';
@@ -91,12 +92,38 @@ declare function getOfficialExtensions(options?: OfficialExtensionsOptions): Ext
91
92
  /**
92
93
  * 公文模板:返回 Tiptap/ProseMirror JSON 文档内容。
93
94
  * 让编辑器“开箱即默认公文版式”,使用方可直接加载或在此基础上修改。
95
+ *
96
+ * 覆盖常见法定文种:通知、请示、报告、批复、函、通报、会议纪要。
97
+ * 文本均为 ○○○ / ××× 占位,便于按需替换。
94
98
  */
95
99
 
96
- /** 标准红头文件(下行文)骨架模板。 */
100
+ /** 通知(下行文,标准红头文件)。 */
97
101
  declare function redHeadDocumentTemplate(): JSONContent;
102
+ /** 请示(上行文,向上级机关请求指示/批准,含签发人)。 */
103
+ declare function requestTemplate(): JSONContent;
104
+ /** 报告(上行文,向上级汇报工作、反映情况,不要求批复)。 */
105
+ declare function reportTemplate(): JSONContent;
106
+ /** 批复(下行文,答复下级机关请示)。 */
107
+ declare function replyTemplate(): JSONContent;
108
+ /** 函(平行文/不相隶属机关之间商洽、询问、答复)。 */
109
+ declare function letterTemplate(): JSONContent;
110
+ /** 通报(下行文,表彰先进、批评错误、传达情况)。 */
111
+ declare function circularTemplate(): JSONContent;
112
+ /** 会议纪要(记载会议主要情况和议定事项;不加盖印章)。 */
113
+ declare function minutesTemplate(): JSONContent;
98
114
  /** 空白公文(仅一个正文段落)。 */
99
115
  declare function blankDocumentTemplate(): JSONContent;
116
+ interface DocumentTemplate {
117
+ /** 唯一标识 */
118
+ key: string;
119
+ /** 中文文种名 */
120
+ label: string;
121
+ /** 行文方向说明 */
122
+ direction: "上行" | "下行" | "平行" | "—";
123
+ build: () => JSONContent;
124
+ }
125
+ /** 内置文种模板清单,便于在 UI 中列举选择。 */
126
+ declare const documentTemplates: DocumentTemplate[];
100
127
 
101
128
  /**
102
129
  * createOfficialDocumentEditor —— headless 公文编辑器工厂。
@@ -173,4 +200,4 @@ interface PaginatedPreviewOptions {
173
200
  */
174
201
  declare function renderPaginatedPreview(doc: JSONContent, mount: HTMLElement, options?: PaginatedPreviewOptions): number;
175
202
 
176
- export { FontRole, HorizontalRuleVariant, type HrVariant, type OfficialEditorOptions, OfficialElement, type OfficialExtensionsOptions, OfficialImage, OfficialRole, type PaginatedPreviewOptions, Pagination, type PaginationOptions, type RegisterFontOptions, blankDocumentTemplate, buildElementStyles, createOfficialDocumentEditor, getOfficialExtensions, injectOfficialStyles, redHeadDocumentTemplate, registerFont, renderPaginatedPreview };
203
+ export { type DocumentTemplate, FontRole, HorizontalRuleVariant, type HrVariant, type OfficialEditorOptions, OfficialElement, type OfficialExtensionsOptions, OfficialImage, OfficialRole, type PaginatedPreviewOptions, Pagination, type PaginationOptions, type RegisterFontOptions, blankDocumentTemplate, buildElementStyles, circularTemplate, createOfficialDocumentEditor, documentTemplates, getOfficialExtensions, injectOfficialStyles, letterTemplate, minutesTemplate, redHeadDocumentTemplate, registerFont, renderPaginatedPreview, replyTemplate, reportTemplate, requestTemplate };
package/dist/index.js CHANGED
@@ -18,6 +18,10 @@ import {
18
18
  pageNumberStyle,
19
19
  paginate
20
20
  } from "./chunk-OUPZEHJO.js";
21
+ import {
22
+ isValid,
23
+ validateDocument
24
+ } from "./chunk-VDLZ23IA.js";
21
25
  import {
22
26
  CHARS_PER_LINE,
23
27
  CHAR_BOX_MM,
@@ -343,13 +347,17 @@ function p(role, text) {
343
347
  if (text) node.content = [{ type: "text", text }];
344
348
  return node;
345
349
  }
350
+ function hr() {
351
+ return { type: "horizontalRule", attrs: { variant: "reverse" } };
352
+ }
353
+ var DATE = "2026 \u5E74 6 \u6708 13 \u65E5";
346
354
  function redHeadDocumentTemplate() {
347
355
  return {
348
356
  type: "doc",
349
357
  content: [
350
358
  p("issuer", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C\u6587\u4EF6"),
351
359
  p("docNumber", "\u25CB\u5E9C\u30142026\u30151 \u53F7"),
352
- { type: "horizontalRule" },
360
+ hr(),
353
361
  p("title", "\u5173\u4E8E\xD7\xD7\xD7\u5DE5\u4F5C\u7684\u901A\u77E5"),
354
362
  p("mainRecipient", "\u5404\u6709\u5173\u5355\u4F4D\uFF1A"),
355
363
  p("body", "\u6839\u636E\u6709\u5173\u5DE5\u4F5C\u90E8\u7F72\uFF0C\u73B0\u5C31\xD7\xD7\xD7\u5DE5\u4F5C\u901A\u77E5\u5982\u4E0B\u3002"),
@@ -358,13 +366,125 @@ function redHeadDocumentTemplate() {
358
366
  p("headingLevel2", "\uFF08\u4E00\uFF09\u5DE5\u4F5C\u76EE\u6807"),
359
367
  p("body", "\uFF08\u6B64\u5904\u586B\u5199\u6B63\u6587\u5185\u5BB9\u3002\uFF09"),
360
368
  p("signature", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C"),
361
- p("dateline", "2026 \u5E74 6 \u6708 13 \u65E5")
369
+ p("dateline", DATE)
370
+ ]
371
+ };
372
+ }
373
+ function requestTemplate() {
374
+ return {
375
+ type: "doc",
376
+ content: [
377
+ p("issuer", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u5168\u79F0\uFF09"),
378
+ p("docNumber", "\u25CB\u25CB\u30142026\u30151 \u53F7"),
379
+ p("signer", "\u7B7E\u53D1\u4EBA\uFF1A\xD7\xD7\xD7"),
380
+ hr(),
381
+ p("title", "\u5173\u4E8E\xD7\xD7\xD7\u7684\u8BF7\u793A"),
382
+ p("mainRecipient", "\u25CB\u25CB\u25CB\uFF08\u4E3B\u9001\u4E0A\u7EA7\u673A\u5173\uFF09\uFF1A"),
383
+ p("body", "\uFF08\u8BF7\u793A\u7F18\u7531\uFF1A\u8BF4\u660E\u8BF7\u793A\u7684\u7406\u7531\u3001\u4F9D\u636E\u548C\u80CC\u666F\u3002\uFF09"),
384
+ p("body", "\uFF08\u8BF7\u793A\u4E8B\u9879\uFF1A\u63D0\u51FA\u5177\u4F53\u3001\u660E\u786E\u7684\u8BF7\u6C42\u3002\uFF09"),
385
+ p("body", "\u59A5\u5426\uFF0C\u8BF7\u6279\u793A\u3002"),
386
+ p("signature", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u7F72\u540D\uFF09"),
387
+ p("dateline", DATE)
388
+ ]
389
+ };
390
+ }
391
+ function reportTemplate() {
392
+ return {
393
+ type: "doc",
394
+ content: [
395
+ p("issuer", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u5168\u79F0\uFF09"),
396
+ p("docNumber", "\u25CB\u25CB\u30142026\u30151 \u53F7"),
397
+ p("signer", "\u7B7E\u53D1\u4EBA\uFF1A\xD7\xD7\xD7"),
398
+ hr(),
399
+ p("title", "\u5173\u4E8E\xD7\xD7\xD7\u5DE5\u4F5C\u7684\u62A5\u544A"),
400
+ p("mainRecipient", "\u25CB\u25CB\u25CB\uFF08\u4E3B\u9001\u4E0A\u7EA7\u673A\u5173\uFF09\uFF1A"),
401
+ p("body", "\uFF08\u62A5\u544A\u4E8B\u7531\u4E0E\u5DE5\u4F5C\u60C5\u51B5\uFF1A\u8BF4\u660E\u5F00\u5C55\u60C5\u51B5\u3001\u6210\u6548\u3001\u95EE\u9898\u4E0E\u4E0B\u4E00\u6B65\u6253\u7B97\u3002\uFF09"),
402
+ p("body", "\u7279\u6B64\u62A5\u544A\u3002"),
403
+ p("signature", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u7F72\u540D\uFF09"),
404
+ p("dateline", DATE)
405
+ ]
406
+ };
407
+ }
408
+ function replyTemplate() {
409
+ return {
410
+ type: "doc",
411
+ content: [
412
+ p("issuer", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C\u6587\u4EF6"),
413
+ p("docNumber", "\u25CB\u5E9C\u30142026\u30151 \u53F7"),
414
+ hr(),
415
+ p("title", "\u5173\u4E8E\xD7\xD7\xD7\u7684\u6279\u590D"),
416
+ p("mainRecipient", "\u25CB\u25CB\u25CB\uFF08\u8BF7\u793A\u673A\u5173\uFF09\uFF1A"),
417
+ p("body", "\u4F60\u5355\u4F4D\u300A\u5173\u4E8E\xD7\xD7\xD7\u7684\u8BF7\u793A\u300B\uFF08\u25CB\u25CB\u30142026\u3015\u25CB\u53F7\uFF09\u6536\u6089\u3002\u7ECF\u7814\u7A76\uFF0C\u73B0\u6279\u590D\u5982\u4E0B\uFF1A"),
418
+ p("body", "\u4E00\u3001\uFF08\u6279\u590D\u610F\u89C1\u2026\u2026\uFF09"),
419
+ p("body", "\u4E8C\u3001\uFF08\u5176\u4ED6\u8981\u6C42\u2026\u2026\uFF09"),
420
+ p("body", "\u6B64\u590D\u3002"),
421
+ p("signature", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C"),
422
+ p("dateline", DATE)
423
+ ]
424
+ };
425
+ }
426
+ function letterTemplate() {
427
+ return {
428
+ type: "doc",
429
+ content: [
430
+ p("issuer", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u540D\u79F0\uFF09\u51FD"),
431
+ p("docNumber", "\u25CB\u51FD\u30142026\u30151 \u53F7"),
432
+ hr(),
433
+ p("title", "\u5173\u4E8E\xD7\xD7\xD7\u7684\u51FD"),
434
+ p("mainRecipient", "\u25CB\u25CB\u25CB\uFF08\u4E3B\u9001\u673A\u5173\uFF09\uFF1A"),
435
+ p("body", "\uFF08\u53BB\u51FD\u4E8B\u7531\u4E0E\u5546\u6D3D/\u8BE2\u95EE\u4E8B\u9879\uFF1A\u8BF4\u660E\u53D1\u51FD\u7684\u7F18\u7531\u4E0E\u5177\u4F53\u8BF7\u6C42\u3002\uFF09"),
436
+ p("body", "\u7279\u6B64\u51FD\u8FBE\uFF0C\u8BF7\u4E88\u652F\u6301\u3002"),
437
+ p("signature", "\u25CB\u25CB\u25CB\uFF08\u53D1\u6587\u673A\u5173\u7F72\u540D\uFF09"),
438
+ p("dateline", DATE)
439
+ ]
440
+ };
441
+ }
442
+ function circularTemplate() {
443
+ return {
444
+ type: "doc",
445
+ content: [
446
+ p("issuer", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C\u6587\u4EF6"),
447
+ p("docNumber", "\u25CB\u5E9C\u30142026\u30151 \u53F7"),
448
+ hr(),
449
+ p("title", "\u5173\u4E8E\xD7\xD7\xD7\u7684\u901A\u62A5"),
450
+ p("mainRecipient", "\u5404\u6709\u5173\u5355\u4F4D\uFF1A"),
451
+ p("body", "\uFF08\u901A\u62A5\u4E8B\u7531\u4E0E\u60C5\u51B5\uFF1A\u8BF4\u660E\u4E8B\u9879\u7ECF\u8FC7\u3001\u6027\u8D28\u4E0E\u5904\u7406\u610F\u89C1\u3002\uFF09"),
452
+ p("body", "\u7279\u6B64\u901A\u62A5\u3002"),
453
+ p("signature", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C"),
454
+ p("dateline", DATE)
455
+ ]
456
+ };
457
+ }
458
+ function minutesTemplate() {
459
+ return {
460
+ type: "doc",
461
+ content: [
462
+ p("title", "\u25CB\u25CB\u25CB\u5DE5\u4F5C\u4F1A\u8BAE\u7EAA\u8981"),
463
+ p("body", "\u65F6\u95F4\uFF1A2026 \u5E74 6 \u6708 13 \u65E5"),
464
+ p("body", "\u5730\u70B9\uFF1A\u25CB\u25CB\u25CB"),
465
+ p("body", "\u4E3B\u6301\u4EBA\uFF1A\xD7\xD7\xD7\u3000\u3000\u8BB0\u5F55\u4EBA\uFF1A\xD7\xD7\xD7"),
466
+ p("body", "\u51FA\u5E2D\u4EBA\u5458\uFF1A\u2026\u2026"),
467
+ p("body", "\u4F1A\u8BAE\u542C\u53D6\u4E86\xD7\xD7\xD7\u60C5\u51B5\u6C47\u62A5\uFF0C\u7ECF\u7814\u7A76\uFF0C\u8BAE\u5B9A\u4E8B\u9879\u5982\u4E0B\uFF1A"),
468
+ p("headingLevel1", "\u4E00\u3001\uFF08\u8BAE\u5B9A\u4E8B\u9879\u2026\u2026\uFF09"),
469
+ p("body", "\uFF08\u843D\u5B9E\u8981\u6C42\u2026\u2026\uFF09"),
470
+ p("headingLevel1", "\u4E8C\u3001\uFF08\u8BAE\u5B9A\u4E8B\u9879\u2026\u2026\uFF09"),
471
+ p("body", "\uFF08\u843D\u5B9E\u8981\u6C42\u2026\u2026\uFF09")
362
472
  ]
363
473
  };
364
474
  }
365
475
  function blankDocumentTemplate() {
366
476
  return { type: "doc", content: [p("body", "")] };
367
477
  }
478
+ var documentTemplates = [
479
+ { key: "notice", label: "\u901A\u77E5", direction: "\u4E0B\u884C", build: redHeadDocumentTemplate },
480
+ { key: "request", label: "\u8BF7\u793A", direction: "\u4E0A\u884C", build: requestTemplate },
481
+ { key: "report", label: "\u62A5\u544A", direction: "\u4E0A\u884C", build: reportTemplate },
482
+ { key: "reply", label: "\u6279\u590D", direction: "\u4E0B\u884C", build: replyTemplate },
483
+ { key: "letter", label: "\u51FD", direction: "\u5E73\u884C", build: letterTemplate },
484
+ { key: "circular", label: "\u901A\u62A5", direction: "\u4E0B\u884C", build: circularTemplate },
485
+ { key: "minutes", label: "\u4F1A\u8BAE\u7EAA\u8981", direction: "\u2014", build: minutesTemplate },
486
+ { key: "blank", label: "\u7A7A\u767D", direction: "\u2014", build: blankDocumentTemplate }
487
+ ];
368
488
 
369
489
  // src/editor.ts
370
490
  import { Editor } from "@tiptap/core";
@@ -468,10 +588,10 @@ var MM_TO_PX2 = 96 / 25.4;
468
588
  var mm = (v) => `${v}mm`;
469
589
  function renderBlock(node) {
470
590
  if (node.type === "horizontalRule") {
471
- const hr = document.createElement("hr");
591
+ const hr2 = document.createElement("hr");
472
592
  const variant = node.attrs?.variant || "reverse";
473
- hr.className = `odoc-separator odoc-hr--${variant}`;
474
- return hr;
593
+ hr2.className = `odoc-separator odoc-hr--${variant}`;
594
+ return hr2;
475
595
  }
476
596
  if (node.type === "image") {
477
597
  const img = document.createElement("img");
@@ -586,14 +706,19 @@ export {
586
706
  blocksFromDoc,
587
707
  buildElementStyles,
588
708
  charsPerLineFor,
709
+ circularTemplate,
589
710
  computePageBreaks,
590
711
  countPages,
591
712
  createOfficialDocumentEditor,
713
+ documentTemplates,
592
714
  estimateLines,
593
715
  formatPageNumber,
594
716
  getOfficialExtensions,
595
717
  injectOfficialStyles,
718
+ isValid,
719
+ letterTemplate,
596
720
  lineHeightPtFor,
721
+ minutesTemplate,
597
722
  pageNumberAlign,
598
723
  pageNumberStyle,
599
724
  paginate,
@@ -602,7 +727,11 @@ export {
602
727
  redHeadDocumentTemplate,
603
728
  registerFont,
604
729
  renderPaginatedPreview,
730
+ replyTemplate,
731
+ reportTemplate,
732
+ requestTemplate,
605
733
  toHalfPoint,
606
- toPt
734
+ toPt,
735
+ validateDocument
607
736
  };
608
737
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/extensions/index.ts","../src/extensions/official-role.ts","../src/extensions/official-image.ts","../src/extensions/hr-variant.ts","../src/extensions/pagination.ts","../src/templates.ts","../src/editor.ts","../src/styles/inject.ts","../src/fonts/register.ts","../src/preview/paginated.ts"],"sourcesContent":["/**\n * 公文编辑器扩展集合:StarterKit + 公文要素角色 + 文本样式/对齐/颜色。\n */\nimport StarterKit from \"@tiptap/starter-kit\";\nimport TextStyle from \"@tiptap/extension-text-style\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Color from \"@tiptap/extension-color\";\nimport Table from \"@tiptap/extension-table\";\nimport TableRow from \"@tiptap/extension-table-row\";\nimport TableCell from \"@tiptap/extension-table-cell\";\nimport TableHeader from \"@tiptap/extension-table-header\";\nimport type { Extensions } from \"@tiptap/core\";\nimport { OfficialRole } from \"./official-role\";\nimport { OfficialImage } from \"./official-image\";\nimport { HorizontalRuleVariant } from \"./hr-variant\";\nimport { Pagination } from \"./pagination\";\n\nexport interface OfficialExtensionsOptions {\n /** 占位提示文字 */\n placeholder?: string;\n /** 是否启用编辑器内联实时分页(默认关闭,需浏览器环境) */\n pagination?: boolean;\n}\n\nexport function getOfficialExtensions(options: OfficialExtensionsOptions = {}): Extensions {\n const extensions: Extensions = [\n StarterKit.configure({\n // 公文标题层级用 officialRole 表达,禁用通用 heading 以免样式冲突\n heading: false,\n }),\n TextStyle,\n Color,\n TextAlign.configure({ types: [\"paragraph\"] }),\n OfficialRole.configure({ types: [\"paragraph\"] }),\n HorizontalRuleVariant,\n Table.configure({ resizable: false }),\n TableRow,\n TableHeader,\n TableCell,\n OfficialImage.configure({ allowBase64: true, inline: false }),\n ];\n if (options.pagination) extensions.push(Pagination);\n return extensions;\n}\n\nexport { OfficialRole, Pagination, HorizontalRuleVariant, OfficialImage };\nexport type { PaginationOptions } from \"./pagination\";\nexport type { HrVariant } from \"./hr-variant\";\n","/**\n * OfficialRole 扩展:为块级节点附加“公文要素角色”属性。\n *\n * 不直接写死样式,而是输出 data-odoc-role 与 class,由公文样式表(按 ELEMENT_SPEC\n * 生成)统一渲染字体/字号/对齐/缩进,保证渲染与 docx 导出共享同一份规范。\n */\nimport { Extension } from \"@tiptap/core\";\nimport type { OfficialElement } from \"../spec/elements\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n officialRole: {\n /** 将当前段落设为指定公文要素(如 title、headingLevel1、dateline)。 */\n setOfficialRole: (role: OfficialElement) => ReturnType;\n /** 清除当前段落的公文要素角色(回退为普通正文)。 */\n unsetOfficialRole: () => ReturnType;\n };\n }\n}\n\nexport interface OfficialRoleOptions {\n /** 应用角色属性的节点类型,默认作用于 paragraph。 */\n types: string[];\n}\n\nexport const OfficialRole = Extension.create<OfficialRoleOptions>({\n name: \"officialRole\",\n\n addOptions() {\n return { types: [\"paragraph\"] };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n officialRole: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-odoc-role\"),\n renderHTML: (attributes) => {\n const role = attributes.officialRole as OfficialElement | null;\n if (!role) return {};\n return {\n \"data-odoc-role\": role,\n class: `odoc-el odoc-el--${role}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setOfficialRole:\n (role) =>\n ({ commands }) =>\n this.options.types.some((type) =>\n commands.updateAttributes(type, { officialRole: role }),\n ),\n unsetOfficialRole:\n () =>\n ({ commands }) =>\n this.options.types.some((type) =>\n commands.resetAttributes(type, \"officialRole\"),\n ),\n };\n },\n});\n","/**\n * 在 Tiptap Image 基础上扩展公文图片属性:\n * - seal:是否为印章(红色印章,排版时叠加于成文日期之上)\n *\n * 印章在编辑器内以叠加样式呈现(.odoc-seal);docx 导出为浮动图片(允许叠压),\n * 导入时若图片为浮动锚定(wp:anchor)则还原为印章。\n */\nimport Image from \"@tiptap/extension-image\";\n\nexport const OfficialImage = Image.extend({\n name: \"image\",\n addAttributes() {\n return {\n ...this.parent?.(),\n seal: {\n default: false,\n parseHTML: (element) => element.hasAttribute(\"data-odoc-seal\"),\n renderHTML: (attributes) =>\n attributes.seal ? { \"data-odoc-seal\": \"true\", class: \"odoc-seal\" } : {},\n },\n };\n },\n});\n","/**\n * 为分隔线(horizontalRule)增加公文变体属性:\n * - reverse:红头反线(发文字号下方红色分隔线,默认)\n * - record:版记分隔线(版记区上下黑色全幅线)\n *\n * 仅附加 data 属性与 class,颜色由样式表渲染;docx 导出/导入据此区分边框颜色。\n */\nimport { Extension } from \"@tiptap/core\";\n\nexport type HrVariant = \"reverse\" | \"record\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n hrVariant: {\n /** 插入指定变体的分隔线 */\n setHorizontalRuleVariant: (variant: HrVariant) => ReturnType;\n };\n }\n}\n\nexport interface HrVariantOptions {\n types: string[];\n}\n\nexport const HorizontalRuleVariant = Extension.create<HrVariantOptions>({\n name: \"hrVariant\",\n\n addOptions() {\n return { types: [\"horizontalRule\"] };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n variant: {\n default: \"reverse\",\n parseHTML: (element) => element.getAttribute(\"data-odoc-hr\") || \"reverse\",\n renderHTML: (attributes) => {\n const variant = (attributes.variant as HrVariant) || \"reverse\";\n return { \"data-odoc-hr\": variant, class: `odoc-hr odoc-hr--${variant}` };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setHorizontalRuleVariant:\n (variant) =>\n ({ chain }) =>\n chain()\n .insertContent({ type: \"horizontalRule\", attrs: { variant } })\n .run(),\n };\n },\n});\n","/**\n * 编辑器内联实时分页(Tiptap/ProseMirror 扩展)。\n *\n * 测量可编辑区内各顶层块的真实位置,借助 headless computePageBreaks 计算断点,\n * 以 widget 装饰插入“分页间隔”,把单一 contenteditable 可视化为多张 A4 页面,\n * 并在每页版心下方编排页码(单页居右、双页居左空一字)。\n *\n * 说明:本扩展依赖浏览器布局,需在真实浏览器中目视核对;为可选扩展,\n * 不影响默认编辑器。断页几何(computePageBreaks)已单测覆盖。\n * v1 以块为断页粒度,超长段落跨页断行留待后续。\n */\nimport { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { TYPE_AREA_MM, MARGIN_MM } from \"../spec/layout\";\nimport { computePageBreaks, type BlockRect } from \"../pagination/layout\";\nimport { pageNumberStyle } from \"../pagination/page-number\";\n\nconst MM_TO_PX = 96 / 25.4;\n\nexport interface PaginationOptions {\n /** 每页版心内容高度(px),默认 225mm */\n pageContentPx: number;\n /** 页间视觉间隔(px) */\n pageGapPx: number;\n /** 天头(上白边)px,用于页间留白 */\n topMarginPx: number;\n /** 地脚(下白边)px,用于页间留白 */\n bottomMarginPx: number;\n /** 是否渲染页码 */\n showPageNumbers: boolean;\n}\n\nconst pluginKey = new PluginKey<DecorationSet>(\"odocPagination\");\n\ninterface BreakMeta {\n decorations: DecorationSet;\n}\n\nfunction buildPageNumberEl(pageNo: number): HTMLElement {\n const style = pageNumberStyle(pageNo);\n const el = document.createElement(\"div\");\n el.className = \"odoc-inline-page-number\";\n el.textContent = style.text;\n el.style.position = \"absolute\";\n // spacer 为全幅(含订口/切口),故页码自纸张边缘内缩 切口/订口 + 空一字\n if (style.align === \"right\") {\n el.style.right = `${(MARGIN_MM.right + style.insetMm) * MM_TO_PX}px`;\n } else {\n el.style.left = `${(MARGIN_MM.left + style.insetMm) * MM_TO_PX}px`;\n }\n return el;\n}\n\ninterface SpacerMetrics {\n spacerPx: number;\n /** 上一页版心剩余空白(白),= spacerPx - breakExtraPx */\n remainingPx: number;\n gapPx: number;\n topMarginPx: number;\n bottomMarginPx: number;\n /** 版心下边缘距页码 7mm 的像素值 */\n pageNumberOffsetPx: number;\n endingPageNo: number;\n showPageNumbers: boolean;\n}\n\nfunction buildSpacer(m: SpacerMetrics): HTMLElement {\n const spacer = document.createElement(\"div\");\n spacer.className = \"odoc-page-break\";\n spacer.style.display = \"block\"; // 置于段落内部时强制断行,把后续行推至下一页\n spacer.style.height = `${m.spacerPx}px`;\n spacer.setAttribute(\"contenteditable\", \"false\");\n\n // 纵向构成:白(上一页剩余版心 + 地脚) → 灰(页间空隙) → 白(下一页天头)\n const whiteTop = m.remainingPx + m.bottomMarginPx;\n const grey = m.gapPx;\n spacer.style.background = `linear-gradient(to bottom, var(--odoc-page-bg) 0 ${whiteTop}px, var(--odoc-canvas-bg) ${whiteTop}px ${whiteTop + grey}px, var(--odoc-page-bg) ${whiteTop + grey}px 100%)`;\n\n if (m.showPageNumbers) {\n const num = buildPageNumberEl(m.endingPageNo);\n // 页码位于上一页版心下边缘之下 7mm\n num.style.top = `${m.remainingPx + m.pageNumberOffsetPx}px`;\n num.style.bottom = \"\";\n spacer.appendChild(num);\n }\n return spacer;\n}\n\n/**\n * 行级测量:取每个顶层块的逐行行盒(Range.getClientRects),换算为“自然位置”\n * (减去其上方所有 spacer 高度,兼容嵌在段落内部的内联 spacer),并用 posAtCoords\n * 求出每行起点的文档位置。据此即可在超长段落中间按行断页。\n *\n * 以行为单位喂给 computePageBreaks:断点落在某行起点时,若该行位于段落中部,\n * 插入的分隔 widget 即把后续行推至下一页,实现段落跨页断行。\n */\nfunction measureLines(view: EditorView): { rects: BlockRect[]; positions: number[] } {\n const rootRect = view.dom.getBoundingClientRect();\n\n // 所有已插入的 spacer(含嵌套在段落内的内联 spacer)\n const spacers = Array.from(view.dom.querySelectorAll<HTMLElement>(\".odoc-page-break\")).map(\n (s) => {\n const r = s.getBoundingClientRect();\n return { top: r.top, h: r.height };\n },\n );\n const offsetAbove = (yTop: number) =>\n spacers.reduce((acc, s) => (s.top < yTop - 0.5 ? acc + s.h : acc), 0);\n\n const rects: BlockRect[] = [];\n const positions: number[] = [];\n let lastPos = -1;\n\n const children = view.dom.children;\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as HTMLElement;\n if (el.classList.contains(\"odoc-page-break\")) continue;\n\n // 取该块的行盒;空块/原子块退化为整块一行\n let lineRects: DOMRect[] = [];\n if (el.firstChild) {\n const range = document.createRange();\n range.selectNodeContents(el);\n lineRects = Array.from(range.getClientRects());\n }\n if (lineRects.length === 0) lineRects = [el.getBoundingClientRect()];\n\n for (const lr of lineRects) {\n if (lr.height < 1) continue;\n const at = view.posAtCoords({ left: lr.left + 1, top: lr.top + lr.height / 2 });\n if (!at) continue;\n if (at.pos === lastPos) continue; // 同一行的重复行盒去重\n lastPos = at.pos;\n rects.push({ top: lr.top - rootRect.top - offsetAbove(lr.top), height: lr.height });\n positions.push(at.pos);\n }\n }\n return { rects, positions };\n}\n\nfunction signatureOf(decoset: { beforeIndex: number; spacerPx: number }[]): string {\n return decoset.map((b) => `${b.beforeIndex}:${Math.round(b.spacerPx)}`).join(\"|\");\n}\n\nexport const Pagination = Extension.create<PaginationOptions>({\n name: \"odocPagination\",\n\n addOptions() {\n return {\n pageContentPx: TYPE_AREA_MM.height * MM_TO_PX,\n pageGapPx: 24,\n topMarginPx: MARGIN_MM.top * MM_TO_PX,\n bottomMarginPx: MARGIN_MM.bottom * MM_TO_PX,\n showPageNumbers: true,\n };\n },\n\n addProseMirrorPlugins() {\n const options = this.options;\n let lastSignature = \"\";\n let raf = 0;\n\n return [\n new Plugin<DecorationSet>({\n key: pluginKey,\n state: {\n init: () => DecorationSet.empty,\n apply(tr, old) {\n const meta = tr.getMeta(pluginKey) as BreakMeta | undefined;\n if (meta) return meta.decorations;\n return old.map(tr.mapping, tr.doc);\n },\n },\n props: {\n decorations(state) {\n return pluginKey.getState(state);\n },\n },\n view(view) {\n const breakExtraPx = options.bottomMarginPx + options.pageGapPx + options.topMarginPx;\n const pageNumberOffsetPx = 7 * MM_TO_PX; // 版心下边缘距页码 7mm\n\n const recompute = () => {\n const { rects, positions } = measureLines(view);\n const { breaks, pageCount } = computePageBreaks(rects, {\n pageContentPx: options.pageContentPx,\n breakExtraPx,\n });\n\n // 末页:补足整张 A4 白纸并编排末页页码\n let tailRemaining = 0;\n if (rects.length) {\n const last = rects[rects.length - 1];\n const lastPageStart = breaks.length\n ? rects[breaks[breaks.length - 1].beforeIndex].top\n : rects[0].top;\n tailRemaining = Math.max(\n 0,\n options.pageContentPx - (last.top + last.height - lastPageStart),\n );\n }\n\n const sig = `${signatureOf(breaks)}#${pageCount}:${Math.round(tailRemaining)}`;\n if (sig === lastSignature) return;\n lastSignature = sig;\n\n const decos = breaks.map((b) =>\n Decoration.widget(\n positions[b.beforeIndex],\n () =>\n buildSpacer({\n spacerPx: b.spacerPx,\n remainingPx: Math.max(0, b.spacerPx - breakExtraPx),\n gapPx: options.pageGapPx,\n topMarginPx: options.topMarginPx,\n bottomMarginPx: options.bottomMarginPx,\n pageNumberOffsetPx,\n endingPageNo: b.pageNo - 1,\n showPageNumbers: options.showPageNumbers,\n }),\n { side: -1, key: `odoc-break-${b.beforeIndex}` },\n ),\n );\n\n if (rects.length && options.showPageNumbers) {\n // 末页补白:填满版心剩余 + 地脚(无页间空隙、无下一页天头),页码落于地脚\n decos.push(\n Decoration.widget(\n view.state.doc.content.size,\n () =>\n buildSpacer({\n spacerPx: tailRemaining + options.bottomMarginPx,\n remainingPx: tailRemaining,\n gapPx: 0,\n topMarginPx: 0,\n bottomMarginPx: options.bottomMarginPx,\n pageNumberOffsetPx,\n endingPageNo: pageCount,\n showPageNumbers: true,\n }),\n { side: 1, key: `odoc-tail-${pageCount}` },\n ),\n );\n }\n const decorations = DecorationSet.create(view.state.doc, decos);\n const tr = view.state.tr.setMeta(pluginKey, { decorations } satisfies BreakMeta);\n view.dispatch(tr);\n };\n\n const schedule = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(recompute);\n };\n\n schedule();\n return {\n update: schedule,\n destroy: () => cancelAnimationFrame(raf),\n };\n },\n }),\n ];\n },\n});\n","/**\n * 公文模板:返回 Tiptap/ProseMirror JSON 文档内容。\n * 让编辑器“开箱即默认公文版式”,使用方可直接加载或在此基础上修改。\n */\nimport type { JSONContent } from \"@tiptap/core\";\nimport type { OfficialElement } from \"./spec/elements\";\n\nfunction p(role: OfficialElement | null, text: string): JSONContent {\n const node: JSONContent = { type: \"paragraph\" };\n if (role) node.attrs = { officialRole: role };\n if (text) node.content = [{ type: \"text\", text }];\n return node;\n}\n\n/** 标准红头文件(下行文)骨架模板。 */\nexport function redHeadDocumentTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○人民政府文件\"),\n p(\"docNumber\", \"○府〔2026〕1 号\"),\n { type: \"horizontalRule\" },\n p(\"title\", \"关于×××工作的通知\"),\n p(\"mainRecipient\", \"各有关单位:\"),\n p(\"body\", \"根据有关工作部署,现就×××工作通知如下。\"),\n p(\"headingLevel1\", \"一、总体要求\"),\n p(\"body\", \"(此处填写正文内容。)\"),\n p(\"headingLevel2\", \"(一)工作目标\"),\n p(\"body\", \"(此处填写正文内容。)\"),\n p(\"signature\", \"○○○人民政府\"),\n p(\"dateline\", \"2026 年 6 月 13 日\"),\n ],\n };\n}\n\n/** 空白公文(仅一个正文段落)。 */\nexport function blankDocumentTemplate(): JSONContent {\n return { type: \"doc\", content: [p(\"body\", \"\")] };\n}\n","/**\n * createOfficialDocumentEditor —— headless 公文编辑器工厂。\n *\n * 基于 Tiptap,与具体前端框架无关;Vue/React 适配层只需在其上做薄封装。\n * 创建时自动注入公文要素样式,并默认加载公文版式模板。\n */\nimport { Editor, type EditorOptions, type JSONContent } from \"@tiptap/core\";\nimport { getOfficialExtensions } from \"./extensions\";\nimport { injectOfficialStyles } from \"./styles/inject\";\nimport { redHeadDocumentTemplate } from \"./templates\";\n\nexport interface OfficialEditorOptions\n extends Partial<Omit<EditorOptions, \"extensions\" | \"content\">> {\n /** 挂载元素(headless 使用可不传,自行渲染) */\n element?: EditorOptions[\"element\"];\n /** 初始内容;缺省加载标准红头文件模板 */\n content?: JSONContent | string;\n /** 占位提示 */\n placeholder?: string;\n /** 是否自动注入公文要素样式(默认 true) */\n injectStyles?: boolean;\n /** 是否启用编辑器内联实时分页(默认 false,需浏览器环境) */\n pagination?: boolean;\n}\n\nexport function createOfficialDocumentEditor(\n options: OfficialEditorOptions = {},\n): Editor {\n const {\n content,\n placeholder,\n pagination = false,\n injectStyles = true,\n editorProps,\n ...rest\n } = options;\n\n if (injectStyles) injectOfficialStyles();\n\n return new Editor({\n ...rest,\n editorProps: {\n ...editorProps,\n attributes: {\n class: \"odoc-typearea\",\n ...(editorProps?.attributes as Record<string, string> | undefined),\n },\n },\n extensions: getOfficialExtensions({ placeholder, pagination }),\n content: content ?? redHeadDocumentTemplate(),\n });\n}\n","/**\n * 依据 ELEMENT_SPEC 生成公文要素样式表并注入文档。\n *\n * 这样字体/字号/对齐/缩进只有一份“事实来源”(spec/elements.ts),\n * 渲染(CSS)与 docx 导出可保持一致,避免手写 CSS 与规范漂移。\n */\nimport { ELEMENT_SPEC, type ElementSpec, type OfficialElement } from \"../spec/elements\";\nimport { FONT_CSS_VAR, FONT_STACK, type FontRole } from \"../spec/fonts\";\nimport { toPt } from \"../spec/font-size\";\n\nconst STYLE_ELEMENT_ID = \"odoc-element-styles\";\n\nfunction fontVar(role: FontRole): string {\n return `var(${FONT_CSS_VAR[role]}, ${FONT_STACK[role]})`;\n}\n\nfunction ruleFor(role: OfficialElement, spec: ElementSpec): string {\n const decls: string[] = [];\n decls.push(`font-family:${fontVar(spec.font)}`);\n decls.push(`font-size:${toPt(spec.size)}pt`);\n decls.push(`font-weight:${spec.bold ? 700 : 400}`);\n if (spec.align) decls.push(`text-align:${spec.align}`);\n if (spec.color) decls.push(`color:${spec.color}`);\n // 以“字”为单位的缩进用 em(1 中文字 ≈ 1em)\n if (spec.indent) decls.push(`text-indent:${spec.indent}em`);\n if (spec.marginLeft) decls.push(`margin-left:${spec.marginLeft}em`);\n if (spec.marginRight) decls.push(`margin-right:${spec.marginRight}em`);\n return `.odoc-el--${role}{${decls.join(\";\")}}`;\n}\n\n/** 生成全部公文要素样式的 CSS 文本。 */\nexport function buildElementStyles(): string {\n return (Object.keys(ELEMENT_SPEC) as OfficialElement[])\n .map((role) => ruleFor(role, ELEMENT_SPEC[role]))\n .join(\"\\n\");\n}\n\n/** 将公文要素样式注入页面(幂等,仅注入一次)。SSR 环境下静默跳过。 */\nexport function injectOfficialStyles(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(STYLE_ELEMENT_ID)) return;\n const style = document.createElement(\"style\");\n style.id = STYLE_ELEMENT_ID;\n style.textContent = buildElementStyles();\n document.head.appendChild(style);\n}\n","/**\n * 字体插槽:允许使用方在运行时注入授权公文字体,覆盖默认开源兜底栈。\n *\n * 适用于内网 / 离线环境需要精确还原仿宋_GB2312、方正小标宋等商业字体的场景,\n * 字体文件由使用方自行提供并保证授权合规,本库不分发任何商业字体。\n */\nimport { FONT_CSS_VAR, type FontRole } from \"../spec/fonts\";\n\nexport interface RegisterFontOptions {\n /** 对应的公文字体角色 */\n role: FontRole;\n /** font-family 名称(将注入 @font-face 并设为该角色的最高优先级) */\n family: string;\n /** 字体文件来源:URL 字符串、ArrayBuffer、或 Blob */\n source?: string | ArrayBuffer | Blob;\n /** @font-face 格式提示,如 'woff2'、'truetype' */\n format?: string;\n /** 字重 */\n weight?: string | number;\n /** 作用范围根节点,默认 document.documentElement */\n target?: HTMLElement;\n}\n\nconst STYLE_ELEMENT_ID = \"odoc-registered-fonts\";\n\nfunction ensureStyleElement(): HTMLStyleElement {\n let el = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement(\"style\");\n el.id = STYLE_ELEMENT_ID;\n document.head.appendChild(el);\n }\n return el;\n}\n\nfunction toCssSource(source: string | ArrayBuffer | Blob, format?: string): string {\n if (typeof source === \"string\") {\n const fmt = format ? ` format(\"${format}\")` : \"\";\n return `url(\"${source}\")${fmt}`;\n }\n const blob = source instanceof Blob ? source : new Blob([source]);\n const url = URL.createObjectURL(blob);\n const fmt = format ? ` format(\"${format}\")` : \"\";\n return `url(\"${url}\")${fmt}`;\n}\n\n/**\n * 注册一个公文字体到指定角色。注册后该角色立即使用此字体(最高优先级)。\n *\n * @example\n * registerFont({ role: \"fangsong\", family: \"FangSong_GB2312\", source: \"/fonts/fs.woff2\", format: \"woff2\" });\n */\nexport function registerFont(options: RegisterFontOptions): void {\n if (typeof document === \"undefined\") {\n throw new Error(\"registerFont 只能在浏览器环境调用。\");\n }\n const { role, family, source, format, weight = \"normal\", target } = options;\n\n if (source) {\n const style = ensureStyleElement();\n const face = `@font-face{font-family:\"${family}\";src:${toCssSource(\n source,\n format,\n )};font-weight:${weight};font-display:swap;}`;\n style.appendChild(document.createTextNode(face));\n }\n\n // 将该角色的 CSS 变量指向新字体,并保留原兜底栈\n const root = target ?? document.documentElement;\n const prev = getComputedStyle(root).getPropertyValue(FONT_CSS_VAR[role]).trim();\n const next = prev ? `\"${family}\", ${prev}` : `\"${family}\"`;\n root.style.setProperty(FONT_CSS_VAR[role], next);\n}\n","/**\n * 分页预览渲染器(浏览器)。\n *\n * 以真实 DOM 测量为准,将公文内容按版心高度逐块流入 A4 页面,并按 GB/T 9704\n * 规则编排页码(单页居右空一字、双页居左空一字)。用于打印/导出前的所见即所得预览。\n *\n * v1 以“整块”为流动粒度(不在段落中间断行);超长段落的跨页断行将随\n * 编辑器内联分页一并在后续迭代提供。headless paginate() 已支持按行精确分页,\n * 可用于页数与导出计算。\n */\nimport type { JSONContent } from \"@tiptap/core\";\nimport { MARGIN_MM, TYPE_AREA_MM } from \"../spec/layout\";\nimport type { OfficialElement } from \"../spec/elements\";\nimport { injectOfficialStyles } from \"../styles/inject\";\nimport { pageNumberStyle, PAGE_NUMBER_OFFSET_MM } from \"../pagination/page-number\";\n\nconst MM_TO_PX = 96 / 25.4;\nconst mm = (v: number): string => `${v}mm`;\n\nexport interface PaginatedPreviewOptions {\n /** 是否渲染页码,默认 true */\n showPageNumber?: boolean;\n}\n\nfunction renderBlock(node: JSONContent): HTMLElement {\n if (node.type === \"horizontalRule\") {\n const hr = document.createElement(\"hr\");\n const variant = (node.attrs?.variant as string) || \"reverse\";\n hr.className = `odoc-separator odoc-hr--${variant}`;\n return hr;\n }\n if (node.type === \"image\") {\n const img = document.createElement(\"img\");\n if (node.attrs?.src) img.src = String(node.attrs.src);\n if (node.attrs?.alt) img.alt = String(node.attrs.alt);\n if (node.attrs?.seal) img.className = \"odoc-seal\";\n return img;\n }\n if (node.type === \"table\") {\n const table = document.createElement(\"table\");\n for (const row of node.content ?? []) {\n const tr = document.createElement(\"tr\");\n for (const cell of row.content ?? []) {\n const td = document.createElement(cell.type === \"tableHeader\" ? \"th\" : \"td\");\n const text = (cell.content ?? [])\n .map((p) => (p.content ?? []).map((t) => t.text ?? \"\").join(\"\"))\n .join(\"\\n\");\n td.textContent = text;\n tr.appendChild(td);\n }\n table.appendChild(tr);\n }\n return table;\n }\n const p = document.createElement(\"p\");\n const role = node.attrs?.officialRole as OfficialElement | undefined;\n if (role) {\n p.className = `odoc-el odoc-el--${role}`;\n p.dataset.odocRole = role;\n }\n const text = (node.content ?? [])\n .map((n) => (n.type === \"text\" ? (n.text ?? \"\") : \"\"))\n .join(\"\");\n // 空段落需占位高度\n p.textContent = text.length ? text : \" \";\n return p;\n}\n\nfunction createPageNumber(pageNo: number): HTMLElement {\n const style = pageNumberStyle(pageNo);\n const el = document.createElement(\"div\");\n el.className = \"odoc-page-number\";\n el.textContent = style.text;\n el.style.position = \"absolute\";\n // 距版心下边缘 7mm,即距页面底边 (地脚 - 7mm)\n el.style.bottom = mm(MARGIN_MM.bottom - PAGE_NUMBER_OFFSET_MM);\n if (style.align === \"right\") {\n el.style.right = mm(MARGIN_MM.right + style.insetMm);\n } else {\n el.style.left = mm(MARGIN_MM.left + style.insetMm);\n }\n return el;\n}\n\ninterface PageRefs {\n page: HTMLElement;\n area: HTMLElement;\n}\n\n/**\n * 将文档渲染为分页预览,挂载到 mount 容器。返回总页数。\n */\nexport function renderPaginatedPreview(\n doc: JSONContent,\n mount: HTMLElement,\n options: PaginatedPreviewOptions = {},\n): number {\n if (typeof document === \"undefined\") {\n throw new Error(\"renderPaginatedPreview 只能在浏览器环境调用。\");\n }\n const { showPageNumber = true } = options;\n injectOfficialStyles();\n\n mount.innerHTML = \"\";\n mount.classList.add(\"odoc-canvas\");\n\n const pageContentPx = TYPE_AREA_MM.height * MM_TO_PX;\n const blocks = (doc.type === \"doc\" ? doc.content : [doc]) ?? [];\n\n let pageNo = 0;\n let refs: PageRefs;\n\n const newPage = (): PageRefs => {\n pageNo += 1;\n const page = document.createElement(\"div\");\n page.className = \"odoc-page\";\n const area = document.createElement(\"div\");\n area.className = \"odoc-typearea\";\n page.appendChild(area);\n if (showPageNumber) page.appendChild(createPageNumber(pageNo));\n mount.appendChild(page);\n return { page, area };\n };\n\n refs = newPage();\n let used = 0;\n\n for (const node of blocks) {\n const el = renderBlock(node);\n refs.area.appendChild(el);\n const h = el.getBoundingClientRect().height;\n // 按块高累计判断是否超出版心;不依赖容器 min-height(其等于版心高会导致误判)\n if (used + h > pageContentPx && refs.area.childElementCount > 1) {\n refs.area.removeChild(el);\n refs = newPage();\n refs.area.appendChild(el);\n used = el.getBoundingClientRect().height;\n } else {\n used += h;\n }\n }\n\n return pageNo;\n}\n"],"mappings":"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","names":["Extension","Extension","Extension","STYLE_ELEMENT_ID","fmt","MM_TO_PX","text","p"]}
1
+ {"version":3,"sources":["../src/extensions/index.ts","../src/extensions/official-role.ts","../src/extensions/official-image.ts","../src/extensions/hr-variant.ts","../src/extensions/pagination.ts","../src/templates.ts","../src/editor.ts","../src/styles/inject.ts","../src/fonts/register.ts","../src/preview/paginated.ts"],"sourcesContent":["/**\n * 公文编辑器扩展集合:StarterKit + 公文要素角色 + 文本样式/对齐/颜色。\n */\nimport StarterKit from \"@tiptap/starter-kit\";\nimport TextStyle from \"@tiptap/extension-text-style\";\nimport TextAlign from \"@tiptap/extension-text-align\";\nimport Color from \"@tiptap/extension-color\";\nimport Table from \"@tiptap/extension-table\";\nimport TableRow from \"@tiptap/extension-table-row\";\nimport TableCell from \"@tiptap/extension-table-cell\";\nimport TableHeader from \"@tiptap/extension-table-header\";\nimport type { Extensions } from \"@tiptap/core\";\nimport { OfficialRole } from \"./official-role\";\nimport { OfficialImage } from \"./official-image\";\nimport { HorizontalRuleVariant } from \"./hr-variant\";\nimport { Pagination } from \"./pagination\";\n\nexport interface OfficialExtensionsOptions {\n /** 占位提示文字 */\n placeholder?: string;\n /** 是否启用编辑器内联实时分页(默认关闭,需浏览器环境) */\n pagination?: boolean;\n}\n\nexport function getOfficialExtensions(options: OfficialExtensionsOptions = {}): Extensions {\n const extensions: Extensions = [\n StarterKit.configure({\n // 公文标题层级用 officialRole 表达,禁用通用 heading 以免样式冲突\n heading: false,\n }),\n TextStyle,\n Color,\n TextAlign.configure({ types: [\"paragraph\"] }),\n OfficialRole.configure({ types: [\"paragraph\"] }),\n HorizontalRuleVariant,\n Table.configure({ resizable: false }),\n TableRow,\n TableHeader,\n TableCell,\n OfficialImage.configure({ allowBase64: true, inline: false }),\n ];\n if (options.pagination) extensions.push(Pagination);\n return extensions;\n}\n\nexport { OfficialRole, Pagination, HorizontalRuleVariant, OfficialImage };\nexport type { PaginationOptions } from \"./pagination\";\nexport type { HrVariant } from \"./hr-variant\";\n","/**\n * OfficialRole 扩展:为块级节点附加“公文要素角色”属性。\n *\n * 不直接写死样式,而是输出 data-odoc-role 与 class,由公文样式表(按 ELEMENT_SPEC\n * 生成)统一渲染字体/字号/对齐/缩进,保证渲染与 docx 导出共享同一份规范。\n */\nimport { Extension } from \"@tiptap/core\";\nimport type { OfficialElement } from \"../spec/elements\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n officialRole: {\n /** 将当前段落设为指定公文要素(如 title、headingLevel1、dateline)。 */\n setOfficialRole: (role: OfficialElement) => ReturnType;\n /** 清除当前段落的公文要素角色(回退为普通正文)。 */\n unsetOfficialRole: () => ReturnType;\n };\n }\n}\n\nexport interface OfficialRoleOptions {\n /** 应用角色属性的节点类型,默认作用于 paragraph。 */\n types: string[];\n}\n\nexport const OfficialRole = Extension.create<OfficialRoleOptions>({\n name: \"officialRole\",\n\n addOptions() {\n return { types: [\"paragraph\"] };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n officialRole: {\n default: null,\n parseHTML: (element) => element.getAttribute(\"data-odoc-role\"),\n renderHTML: (attributes) => {\n const role = attributes.officialRole as OfficialElement | null;\n if (!role) return {};\n return {\n \"data-odoc-role\": role,\n class: `odoc-el odoc-el--${role}`,\n };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setOfficialRole:\n (role) =>\n ({ commands }) =>\n this.options.types.some((type) =>\n commands.updateAttributes(type, { officialRole: role }),\n ),\n unsetOfficialRole:\n () =>\n ({ commands }) =>\n this.options.types.some((type) =>\n commands.resetAttributes(type, \"officialRole\"),\n ),\n };\n },\n});\n","/**\n * 在 Tiptap Image 基础上扩展公文图片属性:\n * - seal:是否为印章(红色印章,排版时叠加于成文日期之上)\n *\n * 印章在编辑器内以叠加样式呈现(.odoc-seal);docx 导出为浮动图片(允许叠压),\n * 导入时若图片为浮动锚定(wp:anchor)则还原为印章。\n */\nimport Image from \"@tiptap/extension-image\";\n\nexport const OfficialImage = Image.extend({\n name: \"image\",\n addAttributes() {\n return {\n ...this.parent?.(),\n seal: {\n default: false,\n parseHTML: (element) => element.hasAttribute(\"data-odoc-seal\"),\n renderHTML: (attributes) =>\n attributes.seal ? { \"data-odoc-seal\": \"true\", class: \"odoc-seal\" } : {},\n },\n };\n },\n});\n","/**\n * 为分隔线(horizontalRule)增加公文变体属性:\n * - reverse:红头反线(发文字号下方红色分隔线,默认)\n * - record:版记分隔线(版记区上下黑色全幅线)\n *\n * 仅附加 data 属性与 class,颜色由样式表渲染;docx 导出/导入据此区分边框颜色。\n */\nimport { Extension } from \"@tiptap/core\";\n\nexport type HrVariant = \"reverse\" | \"record\";\n\ndeclare module \"@tiptap/core\" {\n interface Commands<ReturnType> {\n hrVariant: {\n /** 插入指定变体的分隔线 */\n setHorizontalRuleVariant: (variant: HrVariant) => ReturnType;\n };\n }\n}\n\nexport interface HrVariantOptions {\n types: string[];\n}\n\nexport const HorizontalRuleVariant = Extension.create<HrVariantOptions>({\n name: \"hrVariant\",\n\n addOptions() {\n return { types: [\"horizontalRule\"] };\n },\n\n addGlobalAttributes() {\n return [\n {\n types: this.options.types,\n attributes: {\n variant: {\n default: \"reverse\",\n parseHTML: (element) => element.getAttribute(\"data-odoc-hr\") || \"reverse\",\n renderHTML: (attributes) => {\n const variant = (attributes.variant as HrVariant) || \"reverse\";\n return { \"data-odoc-hr\": variant, class: `odoc-hr odoc-hr--${variant}` };\n },\n },\n },\n },\n ];\n },\n\n addCommands() {\n return {\n setHorizontalRuleVariant:\n (variant) =>\n ({ chain }) =>\n chain()\n .insertContent({ type: \"horizontalRule\", attrs: { variant } })\n .run(),\n };\n },\n});\n","/**\n * 编辑器内联实时分页(Tiptap/ProseMirror 扩展)。\n *\n * 测量可编辑区内各顶层块的真实位置,借助 headless computePageBreaks 计算断点,\n * 以 widget 装饰插入“分页间隔”,把单一 contenteditable 可视化为多张 A4 页面,\n * 并在每页版心下方编排页码(单页居右、双页居左空一字)。\n *\n * 说明:本扩展依赖浏览器布局,需在真实浏览器中目视核对;为可选扩展,\n * 不影响默认编辑器。断页几何(computePageBreaks)已单测覆盖。\n * v1 以块为断页粒度,超长段落跨页断行留待后续。\n */\nimport { Extension } from \"@tiptap/core\";\nimport { Plugin, PluginKey } from \"@tiptap/pm/state\";\nimport { Decoration, DecorationSet } from \"@tiptap/pm/view\";\nimport type { EditorView } from \"@tiptap/pm/view\";\nimport { TYPE_AREA_MM, MARGIN_MM } from \"../spec/layout\";\nimport { computePageBreaks, type BlockRect } from \"../pagination/layout\";\nimport { pageNumberStyle } from \"../pagination/page-number\";\n\nconst MM_TO_PX = 96 / 25.4;\n\nexport interface PaginationOptions {\n /** 每页版心内容高度(px),默认 225mm */\n pageContentPx: number;\n /** 页间视觉间隔(px) */\n pageGapPx: number;\n /** 天头(上白边)px,用于页间留白 */\n topMarginPx: number;\n /** 地脚(下白边)px,用于页间留白 */\n bottomMarginPx: number;\n /** 是否渲染页码 */\n showPageNumbers: boolean;\n}\n\nconst pluginKey = new PluginKey<DecorationSet>(\"odocPagination\");\n\ninterface BreakMeta {\n decorations: DecorationSet;\n}\n\nfunction buildPageNumberEl(pageNo: number): HTMLElement {\n const style = pageNumberStyle(pageNo);\n const el = document.createElement(\"div\");\n el.className = \"odoc-inline-page-number\";\n el.textContent = style.text;\n el.style.position = \"absolute\";\n // spacer 为全幅(含订口/切口),故页码自纸张边缘内缩 切口/订口 + 空一字\n if (style.align === \"right\") {\n el.style.right = `${(MARGIN_MM.right + style.insetMm) * MM_TO_PX}px`;\n } else {\n el.style.left = `${(MARGIN_MM.left + style.insetMm) * MM_TO_PX}px`;\n }\n return el;\n}\n\ninterface SpacerMetrics {\n spacerPx: number;\n /** 上一页版心剩余空白(白),= spacerPx - breakExtraPx */\n remainingPx: number;\n gapPx: number;\n topMarginPx: number;\n bottomMarginPx: number;\n /** 版心下边缘距页码 7mm 的像素值 */\n pageNumberOffsetPx: number;\n endingPageNo: number;\n showPageNumbers: boolean;\n}\n\nfunction buildSpacer(m: SpacerMetrics): HTMLElement {\n const spacer = document.createElement(\"div\");\n spacer.className = \"odoc-page-break\";\n spacer.style.display = \"block\"; // 置于段落内部时强制断行,把后续行推至下一页\n spacer.style.height = `${m.spacerPx}px`;\n spacer.setAttribute(\"contenteditable\", \"false\");\n\n // 纵向构成:白(上一页剩余版心 + 地脚) → 灰(页间空隙) → 白(下一页天头)\n const whiteTop = m.remainingPx + m.bottomMarginPx;\n const grey = m.gapPx;\n spacer.style.background = `linear-gradient(to bottom, var(--odoc-page-bg) 0 ${whiteTop}px, var(--odoc-canvas-bg) ${whiteTop}px ${whiteTop + grey}px, var(--odoc-page-bg) ${whiteTop + grey}px 100%)`;\n\n if (m.showPageNumbers) {\n const num = buildPageNumberEl(m.endingPageNo);\n // 页码位于上一页版心下边缘之下 7mm\n num.style.top = `${m.remainingPx + m.pageNumberOffsetPx}px`;\n num.style.bottom = \"\";\n spacer.appendChild(num);\n }\n return spacer;\n}\n\n/**\n * 行级测量:取每个顶层块的逐行行盒(Range.getClientRects),换算为“自然位置”\n * (减去其上方所有 spacer 高度,兼容嵌在段落内部的内联 spacer),并用 posAtCoords\n * 求出每行起点的文档位置。据此即可在超长段落中间按行断页。\n *\n * 以行为单位喂给 computePageBreaks:断点落在某行起点时,若该行位于段落中部,\n * 插入的分隔 widget 即把后续行推至下一页,实现段落跨页断行。\n */\nfunction measureLines(view: EditorView): { rects: BlockRect[]; positions: number[] } {\n const rootRect = view.dom.getBoundingClientRect();\n\n // 所有已插入的 spacer(含嵌套在段落内的内联 spacer)\n const spacers = Array.from(view.dom.querySelectorAll<HTMLElement>(\".odoc-page-break\")).map(\n (s) => {\n const r = s.getBoundingClientRect();\n return { top: r.top, h: r.height };\n },\n );\n const offsetAbove = (yTop: number) =>\n spacers.reduce((acc, s) => (s.top < yTop - 0.5 ? acc + s.h : acc), 0);\n\n const rects: BlockRect[] = [];\n const positions: number[] = [];\n let lastPos = -1;\n\n const children = view.dom.children;\n for (let i = 0; i < children.length; i++) {\n const el = children[i] as HTMLElement;\n if (el.classList.contains(\"odoc-page-break\")) continue;\n\n // 取该块的行盒;空块/原子块退化为整块一行\n let lineRects: DOMRect[] = [];\n if (el.firstChild) {\n const range = document.createRange();\n range.selectNodeContents(el);\n lineRects = Array.from(range.getClientRects());\n }\n if (lineRects.length === 0) lineRects = [el.getBoundingClientRect()];\n\n for (const lr of lineRects) {\n if (lr.height < 1) continue;\n const at = view.posAtCoords({ left: lr.left + 1, top: lr.top + lr.height / 2 });\n if (!at) continue;\n if (at.pos === lastPos) continue; // 同一行的重复行盒去重\n lastPos = at.pos;\n rects.push({ top: lr.top - rootRect.top - offsetAbove(lr.top), height: lr.height });\n positions.push(at.pos);\n }\n }\n return { rects, positions };\n}\n\nfunction signatureOf(decoset: { beforeIndex: number; spacerPx: number }[]): string {\n return decoset.map((b) => `${b.beforeIndex}:${Math.round(b.spacerPx)}`).join(\"|\");\n}\n\nexport const Pagination = Extension.create<PaginationOptions>({\n name: \"odocPagination\",\n\n addOptions() {\n return {\n pageContentPx: TYPE_AREA_MM.height * MM_TO_PX,\n pageGapPx: 24,\n topMarginPx: MARGIN_MM.top * MM_TO_PX,\n bottomMarginPx: MARGIN_MM.bottom * MM_TO_PX,\n showPageNumbers: true,\n };\n },\n\n addProseMirrorPlugins() {\n const options = this.options;\n let lastSignature = \"\";\n let raf = 0;\n\n return [\n new Plugin<DecorationSet>({\n key: pluginKey,\n state: {\n init: () => DecorationSet.empty,\n apply(tr, old) {\n const meta = tr.getMeta(pluginKey) as BreakMeta | undefined;\n if (meta) return meta.decorations;\n return old.map(tr.mapping, tr.doc);\n },\n },\n props: {\n decorations(state) {\n return pluginKey.getState(state);\n },\n },\n view(view) {\n const breakExtraPx = options.bottomMarginPx + options.pageGapPx + options.topMarginPx;\n const pageNumberOffsetPx = 7 * MM_TO_PX; // 版心下边缘距页码 7mm\n\n const recompute = () => {\n const { rects, positions } = measureLines(view);\n const { breaks, pageCount } = computePageBreaks(rects, {\n pageContentPx: options.pageContentPx,\n breakExtraPx,\n });\n\n // 末页:补足整张 A4 白纸并编排末页页码\n let tailRemaining = 0;\n if (rects.length) {\n const last = rects[rects.length - 1];\n const lastPageStart = breaks.length\n ? rects[breaks[breaks.length - 1].beforeIndex].top\n : rects[0].top;\n tailRemaining = Math.max(\n 0,\n options.pageContentPx - (last.top + last.height - lastPageStart),\n );\n }\n\n const sig = `${signatureOf(breaks)}#${pageCount}:${Math.round(tailRemaining)}`;\n if (sig === lastSignature) return;\n lastSignature = sig;\n\n const decos = breaks.map((b) =>\n Decoration.widget(\n positions[b.beforeIndex],\n () =>\n buildSpacer({\n spacerPx: b.spacerPx,\n remainingPx: Math.max(0, b.spacerPx - breakExtraPx),\n gapPx: options.pageGapPx,\n topMarginPx: options.topMarginPx,\n bottomMarginPx: options.bottomMarginPx,\n pageNumberOffsetPx,\n endingPageNo: b.pageNo - 1,\n showPageNumbers: options.showPageNumbers,\n }),\n { side: -1, key: `odoc-break-${b.beforeIndex}` },\n ),\n );\n\n if (rects.length && options.showPageNumbers) {\n // 末页补白:填满版心剩余 + 地脚(无页间空隙、无下一页天头),页码落于地脚\n decos.push(\n Decoration.widget(\n view.state.doc.content.size,\n () =>\n buildSpacer({\n spacerPx: tailRemaining + options.bottomMarginPx,\n remainingPx: tailRemaining,\n gapPx: 0,\n topMarginPx: 0,\n bottomMarginPx: options.bottomMarginPx,\n pageNumberOffsetPx,\n endingPageNo: pageCount,\n showPageNumbers: true,\n }),\n { side: 1, key: `odoc-tail-${pageCount}` },\n ),\n );\n }\n const decorations = DecorationSet.create(view.state.doc, decos);\n const tr = view.state.tr.setMeta(pluginKey, { decorations } satisfies BreakMeta);\n view.dispatch(tr);\n };\n\n const schedule = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(recompute);\n };\n\n schedule();\n return {\n update: schedule,\n destroy: () => cancelAnimationFrame(raf),\n };\n },\n }),\n ];\n },\n});\n","/**\n * 公文模板:返回 Tiptap/ProseMirror JSON 文档内容。\n * 让编辑器“开箱即默认公文版式”,使用方可直接加载或在此基础上修改。\n *\n * 覆盖常见法定文种:通知、请示、报告、批复、函、通报、会议纪要。\n * 文本均为 ○○○ / ××× 占位,便于按需替换。\n */\nimport type { JSONContent } from \"@tiptap/core\";\nimport type { OfficialElement } from \"./spec/elements\";\n\nfunction p(role: OfficialElement | null, text: string): JSONContent {\n const node: JSONContent = { type: \"paragraph\" };\n if (role) node.attrs = { officialRole: role };\n if (text) node.content = [{ type: \"text\", text }];\n return node;\n}\n\n/** 红色反线(红头分隔线)。 */\nfunction hr(): JSONContent {\n return { type: \"horizontalRule\", attrs: { variant: \"reverse\" } };\n}\n\nconst DATE = \"2026 年 6 月 13 日\";\n\n/** 通知(下行文,标准红头文件)。 */\nexport function redHeadDocumentTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○人民政府文件\"),\n p(\"docNumber\", \"○府〔2026〕1 号\"),\n hr(),\n p(\"title\", \"关于×××工作的通知\"),\n p(\"mainRecipient\", \"各有关单位:\"),\n p(\"body\", \"根据有关工作部署,现就×××工作通知如下。\"),\n p(\"headingLevel1\", \"一、总体要求\"),\n p(\"body\", \"(此处填写正文内容。)\"),\n p(\"headingLevel2\", \"(一)工作目标\"),\n p(\"body\", \"(此处填写正文内容。)\"),\n p(\"signature\", \"○○○人民政府\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 请示(上行文,向上级机关请求指示/批准,含签发人)。 */\nexport function requestTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○(发文机关全称)\"),\n p(\"docNumber\", \"○○〔2026〕1 号\"),\n p(\"signer\", \"签发人:×××\"),\n hr(),\n p(\"title\", \"关于×××的请示\"),\n p(\"mainRecipient\", \"○○○(主送上级机关):\"),\n p(\"body\", \"(请示缘由:说明请示的理由、依据和背景。)\"),\n p(\"body\", \"(请示事项:提出具体、明确的请求。)\"),\n p(\"body\", \"妥否,请批示。\"),\n p(\"signature\", \"○○○(发文机关署名)\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 报告(上行文,向上级汇报工作、反映情况,不要求批复)。 */\nexport function reportTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○(发文机关全称)\"),\n p(\"docNumber\", \"○○〔2026〕1 号\"),\n p(\"signer\", \"签发人:×××\"),\n hr(),\n p(\"title\", \"关于×××工作的报告\"),\n p(\"mainRecipient\", \"○○○(主送上级机关):\"),\n p(\"body\", \"(报告事由与工作情况:说明开展情况、成效、问题与下一步打算。)\"),\n p(\"body\", \"特此报告。\"),\n p(\"signature\", \"○○○(发文机关署名)\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 批复(下行文,答复下级机关请示)。 */\nexport function replyTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○人民政府文件\"),\n p(\"docNumber\", \"○府〔2026〕1 号\"),\n hr(),\n p(\"title\", \"关于×××的批复\"),\n p(\"mainRecipient\", \"○○○(请示机关):\"),\n p(\"body\", \"你单位《关于×××的请示》(○○〔2026〕○号)收悉。经研究,现批复如下:\"),\n p(\"body\", \"一、(批复意见……)\"),\n p(\"body\", \"二、(其他要求……)\"),\n p(\"body\", \"此复。\"),\n p(\"signature\", \"○○○人民政府\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 函(平行文/不相隶属机关之间商洽、询问、答复)。 */\nexport function letterTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○(发文机关名称)函\"),\n p(\"docNumber\", \"○函〔2026〕1 号\"),\n hr(),\n p(\"title\", \"关于×××的函\"),\n p(\"mainRecipient\", \"○○○(主送机关):\"),\n p(\"body\", \"(去函事由与商洽/询问事项:说明发函的缘由与具体请求。)\"),\n p(\"body\", \"特此函达,请予支持。\"),\n p(\"signature\", \"○○○(发文机关署名)\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 通报(下行文,表彰先进、批评错误、传达情况)。 */\nexport function circularTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"issuer\", \"○○○人民政府文件\"),\n p(\"docNumber\", \"○府〔2026〕1 号\"),\n hr(),\n p(\"title\", \"关于×××的通报\"),\n p(\"mainRecipient\", \"各有关单位:\"),\n p(\"body\", \"(通报事由与情况:说明事项经过、性质与处理意见。)\"),\n p(\"body\", \"特此通报。\"),\n p(\"signature\", \"○○○人民政府\"),\n p(\"dateline\", DATE),\n ],\n };\n}\n\n/** 会议纪要(记载会议主要情况和议定事项;不加盖印章)。 */\nexport function minutesTemplate(): JSONContent {\n return {\n type: \"doc\",\n content: [\n p(\"title\", \"○○○工作会议纪要\"),\n p(\"body\", \"时间:2026 年 6 月 13 日\"),\n p(\"body\", \"地点:○○○\"),\n p(\"body\", \"主持人:×××  记录人:×××\"),\n p(\"body\", \"出席人员:……\"),\n p(\"body\", \"会议听取了×××情况汇报,经研究,议定事项如下:\"),\n p(\"headingLevel1\", \"一、(议定事项……)\"),\n p(\"body\", \"(落实要求……)\"),\n p(\"headingLevel1\", \"二、(议定事项……)\"),\n p(\"body\", \"(落实要求……)\"),\n ],\n };\n}\n\n/** 空白公文(仅一个正文段落)。 */\nexport function blankDocumentTemplate(): JSONContent {\n return { type: \"doc\", content: [p(\"body\", \"\")] };\n}\n\nexport interface DocumentTemplate {\n /** 唯一标识 */\n key: string;\n /** 中文文种名 */\n label: string;\n /** 行文方向说明 */\n direction: \"上行\" | \"下行\" | \"平行\" | \"—\";\n build: () => JSONContent;\n}\n\n/** 内置文种模板清单,便于在 UI 中列举选择。 */\nexport const documentTemplates: DocumentTemplate[] = [\n { key: \"notice\", label: \"通知\", direction: \"下行\", build: redHeadDocumentTemplate },\n { key: \"request\", label: \"请示\", direction: \"上行\", build: requestTemplate },\n { key: \"report\", label: \"报告\", direction: \"上行\", build: reportTemplate },\n { key: \"reply\", label: \"批复\", direction: \"下行\", build: replyTemplate },\n { key: \"letter\", label: \"函\", direction: \"平行\", build: letterTemplate },\n { key: \"circular\", label: \"通报\", direction: \"下行\", build: circularTemplate },\n { key: \"minutes\", label: \"会议纪要\", direction: \"—\", build: minutesTemplate },\n { key: \"blank\", label: \"空白\", direction: \"—\", build: blankDocumentTemplate },\n];\n","/**\n * createOfficialDocumentEditor —— headless 公文编辑器工厂。\n *\n * 基于 Tiptap,与具体前端框架无关;Vue/React 适配层只需在其上做薄封装。\n * 创建时自动注入公文要素样式,并默认加载公文版式模板。\n */\nimport { Editor, type EditorOptions, type JSONContent } from \"@tiptap/core\";\nimport { getOfficialExtensions } from \"./extensions\";\nimport { injectOfficialStyles } from \"./styles/inject\";\nimport { redHeadDocumentTemplate } from \"./templates\";\n\nexport interface OfficialEditorOptions\n extends Partial<Omit<EditorOptions, \"extensions\" | \"content\">> {\n /** 挂载元素(headless 使用可不传,自行渲染) */\n element?: EditorOptions[\"element\"];\n /** 初始内容;缺省加载标准红头文件模板 */\n content?: JSONContent | string;\n /** 占位提示 */\n placeholder?: string;\n /** 是否自动注入公文要素样式(默认 true) */\n injectStyles?: boolean;\n /** 是否启用编辑器内联实时分页(默认 false,需浏览器环境) */\n pagination?: boolean;\n}\n\nexport function createOfficialDocumentEditor(\n options: OfficialEditorOptions = {},\n): Editor {\n const {\n content,\n placeholder,\n pagination = false,\n injectStyles = true,\n editorProps,\n ...rest\n } = options;\n\n if (injectStyles) injectOfficialStyles();\n\n return new Editor({\n ...rest,\n editorProps: {\n ...editorProps,\n attributes: {\n class: \"odoc-typearea\",\n ...(editorProps?.attributes as Record<string, string> | undefined),\n },\n },\n extensions: getOfficialExtensions({ placeholder, pagination }),\n content: content ?? redHeadDocumentTemplate(),\n });\n}\n","/**\n * 依据 ELEMENT_SPEC 生成公文要素样式表并注入文档。\n *\n * 这样字体/字号/对齐/缩进只有一份“事实来源”(spec/elements.ts),\n * 渲染(CSS)与 docx 导出可保持一致,避免手写 CSS 与规范漂移。\n */\nimport { ELEMENT_SPEC, type ElementSpec, type OfficialElement } from \"../spec/elements\";\nimport { FONT_CSS_VAR, FONT_STACK, type FontRole } from \"../spec/fonts\";\nimport { toPt } from \"../spec/font-size\";\n\nconst STYLE_ELEMENT_ID = \"odoc-element-styles\";\n\nfunction fontVar(role: FontRole): string {\n return `var(${FONT_CSS_VAR[role]}, ${FONT_STACK[role]})`;\n}\n\nfunction ruleFor(role: OfficialElement, spec: ElementSpec): string {\n const decls: string[] = [];\n decls.push(`font-family:${fontVar(spec.font)}`);\n decls.push(`font-size:${toPt(spec.size)}pt`);\n decls.push(`font-weight:${spec.bold ? 700 : 400}`);\n if (spec.align) decls.push(`text-align:${spec.align}`);\n if (spec.color) decls.push(`color:${spec.color}`);\n // 以“字”为单位的缩进用 em(1 中文字 ≈ 1em)\n if (spec.indent) decls.push(`text-indent:${spec.indent}em`);\n if (spec.marginLeft) decls.push(`margin-left:${spec.marginLeft}em`);\n if (spec.marginRight) decls.push(`margin-right:${spec.marginRight}em`);\n return `.odoc-el--${role}{${decls.join(\";\")}}`;\n}\n\n/** 生成全部公文要素样式的 CSS 文本。 */\nexport function buildElementStyles(): string {\n return (Object.keys(ELEMENT_SPEC) as OfficialElement[])\n .map((role) => ruleFor(role, ELEMENT_SPEC[role]))\n .join(\"\\n\");\n}\n\n/** 将公文要素样式注入页面(幂等,仅注入一次)。SSR 环境下静默跳过。 */\nexport function injectOfficialStyles(): void {\n if (typeof document === \"undefined\") return;\n if (document.getElementById(STYLE_ELEMENT_ID)) return;\n const style = document.createElement(\"style\");\n style.id = STYLE_ELEMENT_ID;\n style.textContent = buildElementStyles();\n document.head.appendChild(style);\n}\n","/**\n * 字体插槽:允许使用方在运行时注入授权公文字体,覆盖默认开源兜底栈。\n *\n * 适用于内网 / 离线环境需要精确还原仿宋_GB2312、方正小标宋等商业字体的场景,\n * 字体文件由使用方自行提供并保证授权合规,本库不分发任何商业字体。\n */\nimport { FONT_CSS_VAR, type FontRole } from \"../spec/fonts\";\n\nexport interface RegisterFontOptions {\n /** 对应的公文字体角色 */\n role: FontRole;\n /** font-family 名称(将注入 @font-face 并设为该角色的最高优先级) */\n family: string;\n /** 字体文件来源:URL 字符串、ArrayBuffer、或 Blob */\n source?: string | ArrayBuffer | Blob;\n /** @font-face 格式提示,如 'woff2'、'truetype' */\n format?: string;\n /** 字重 */\n weight?: string | number;\n /** 作用范围根节点,默认 document.documentElement */\n target?: HTMLElement;\n}\n\nconst STYLE_ELEMENT_ID = \"odoc-registered-fonts\";\n\nfunction ensureStyleElement(): HTMLStyleElement {\n let el = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n if (!el) {\n el = document.createElement(\"style\");\n el.id = STYLE_ELEMENT_ID;\n document.head.appendChild(el);\n }\n return el;\n}\n\nfunction toCssSource(source: string | ArrayBuffer | Blob, format?: string): string {\n if (typeof source === \"string\") {\n const fmt = format ? ` format(\"${format}\")` : \"\";\n return `url(\"${source}\")${fmt}`;\n }\n const blob = source instanceof Blob ? source : new Blob([source]);\n const url = URL.createObjectURL(blob);\n const fmt = format ? ` format(\"${format}\")` : \"\";\n return `url(\"${url}\")${fmt}`;\n}\n\n/**\n * 注册一个公文字体到指定角色。注册后该角色立即使用此字体(最高优先级)。\n *\n * @example\n * registerFont({ role: \"fangsong\", family: \"FangSong_GB2312\", source: \"/fonts/fs.woff2\", format: \"woff2\" });\n */\nexport function registerFont(options: RegisterFontOptions): void {\n if (typeof document === \"undefined\") {\n throw new Error(\"registerFont 只能在浏览器环境调用。\");\n }\n const { role, family, source, format, weight = \"normal\", target } = options;\n\n if (source) {\n const style = ensureStyleElement();\n const face = `@font-face{font-family:\"${family}\";src:${toCssSource(\n source,\n format,\n )};font-weight:${weight};font-display:swap;}`;\n style.appendChild(document.createTextNode(face));\n }\n\n // 将该角色的 CSS 变量指向新字体,并保留原兜底栈\n const root = target ?? document.documentElement;\n const prev = getComputedStyle(root).getPropertyValue(FONT_CSS_VAR[role]).trim();\n const next = prev ? `\"${family}\", ${prev}` : `\"${family}\"`;\n root.style.setProperty(FONT_CSS_VAR[role], next);\n}\n","/**\n * 分页预览渲染器(浏览器)。\n *\n * 以真实 DOM 测量为准,将公文内容按版心高度逐块流入 A4 页面,并按 GB/T 9704\n * 规则编排页码(单页居右空一字、双页居左空一字)。用于打印/导出前的所见即所得预览。\n *\n * v1 以“整块”为流动粒度(不在段落中间断行);超长段落的跨页断行将随\n * 编辑器内联分页一并在后续迭代提供。headless paginate() 已支持按行精确分页,\n * 可用于页数与导出计算。\n */\nimport type { JSONContent } from \"@tiptap/core\";\nimport { MARGIN_MM, TYPE_AREA_MM } from \"../spec/layout\";\nimport type { OfficialElement } from \"../spec/elements\";\nimport { injectOfficialStyles } from \"../styles/inject\";\nimport { pageNumberStyle, PAGE_NUMBER_OFFSET_MM } from \"../pagination/page-number\";\n\nconst MM_TO_PX = 96 / 25.4;\nconst mm = (v: number): string => `${v}mm`;\n\nexport interface PaginatedPreviewOptions {\n /** 是否渲染页码,默认 true */\n showPageNumber?: boolean;\n}\n\nfunction renderBlock(node: JSONContent): HTMLElement {\n if (node.type === \"horizontalRule\") {\n const hr = document.createElement(\"hr\");\n const variant = (node.attrs?.variant as string) || \"reverse\";\n hr.className = `odoc-separator odoc-hr--${variant}`;\n return hr;\n }\n if (node.type === \"image\") {\n const img = document.createElement(\"img\");\n if (node.attrs?.src) img.src = String(node.attrs.src);\n if (node.attrs?.alt) img.alt = String(node.attrs.alt);\n if (node.attrs?.seal) img.className = \"odoc-seal\";\n return img;\n }\n if (node.type === \"table\") {\n const table = document.createElement(\"table\");\n for (const row of node.content ?? []) {\n const tr = document.createElement(\"tr\");\n for (const cell of row.content ?? []) {\n const td = document.createElement(cell.type === \"tableHeader\" ? \"th\" : \"td\");\n const text = (cell.content ?? [])\n .map((p) => (p.content ?? []).map((t) => t.text ?? \"\").join(\"\"))\n .join(\"\\n\");\n td.textContent = text;\n tr.appendChild(td);\n }\n table.appendChild(tr);\n }\n return table;\n }\n const p = document.createElement(\"p\");\n const role = node.attrs?.officialRole as OfficialElement | undefined;\n if (role) {\n p.className = `odoc-el odoc-el--${role}`;\n p.dataset.odocRole = role;\n }\n const text = (node.content ?? [])\n .map((n) => (n.type === \"text\" ? (n.text ?? \"\") : \"\"))\n .join(\"\");\n // 空段落需占位高度\n p.textContent = text.length ? text : \" \";\n return p;\n}\n\nfunction createPageNumber(pageNo: number): HTMLElement {\n const style = pageNumberStyle(pageNo);\n const el = document.createElement(\"div\");\n el.className = \"odoc-page-number\";\n el.textContent = style.text;\n el.style.position = \"absolute\";\n // 距版心下边缘 7mm,即距页面底边 (地脚 - 7mm)\n el.style.bottom = mm(MARGIN_MM.bottom - PAGE_NUMBER_OFFSET_MM);\n if (style.align === \"right\") {\n el.style.right = mm(MARGIN_MM.right + style.insetMm);\n } else {\n el.style.left = mm(MARGIN_MM.left + style.insetMm);\n }\n return el;\n}\n\ninterface PageRefs {\n page: HTMLElement;\n area: HTMLElement;\n}\n\n/**\n * 将文档渲染为分页预览,挂载到 mount 容器。返回总页数。\n */\nexport function renderPaginatedPreview(\n doc: JSONContent,\n mount: HTMLElement,\n options: PaginatedPreviewOptions = {},\n): number {\n if (typeof document === \"undefined\") {\n throw new Error(\"renderPaginatedPreview 只能在浏览器环境调用。\");\n }\n const { showPageNumber = true } = options;\n injectOfficialStyles();\n\n mount.innerHTML = \"\";\n mount.classList.add(\"odoc-canvas\");\n\n const pageContentPx = TYPE_AREA_MM.height * MM_TO_PX;\n const blocks = (doc.type === \"doc\" ? doc.content : [doc]) ?? [];\n\n let pageNo = 0;\n let refs: PageRefs;\n\n const newPage = (): PageRefs => {\n pageNo += 1;\n const page = document.createElement(\"div\");\n page.className = \"odoc-page\";\n const area = document.createElement(\"div\");\n area.className = \"odoc-typearea\";\n page.appendChild(area);\n if (showPageNumber) page.appendChild(createPageNumber(pageNo));\n mount.appendChild(page);\n return { page, area };\n };\n\n refs = newPage();\n let used = 0;\n\n for (const node of blocks) {\n const el = renderBlock(node);\n refs.area.appendChild(el);\n const h = el.getBoundingClientRect().height;\n // 按块高累计判断是否超出版心;不依赖容器 min-height(其等于版心高会导致误判)\n if (used + h > pageContentPx && refs.area.childElementCount > 1) {\n refs.area.removeChild(el);\n refs = newPage();\n refs.area.appendChild(el);\n used = el.getBoundingClientRect().height;\n } else {\n used += h;\n }\n }\n\n return pageNo;\n}\n"],"mappings":"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","names":["Extension","Extension","Extension","STYLE_ELEMENT_ID","fmt","MM_TO_PX","hr","text","p"]}
@@ -0,0 +1,31 @@
1
+ import { JSONContent } from '@tiptap/core';
2
+ import { O as OfficialElement } from '../elements-Bvueu_TD.js';
3
+
4
+ /**
5
+ * 公文合规校验器(headless,纯函数,零 DOM)。
6
+ *
7
+ * 依 GB/T 9704-2012 对一篇公文(Tiptap/ProseMirror JSON)做结构与格式校验,
8
+ * 返回问题列表。当前规则集面向下行文(如「通知」),可通过 options 调整必备要素。
9
+ */
10
+
11
+ type IssueLevel = "error" | "warn";
12
+ type IssueCode = "EMPTY_DOCUMENT" | "MISSING_TITLE" | "MISSING_BODY" | "MISSING_MAIN_RECIPIENT" | "MISSING_SIGNATURE" | "MISSING_DATELINE" | "TITLE_TRAILING_PUNCT" | "DOC_NUMBER_FORMAT" | "DATELINE_FORMAT" | "DATELINE_BEFORE_SIGNATURE";
13
+ interface Issue {
14
+ level: IssueLevel;
15
+ code: IssueCode;
16
+ message: string;
17
+ /** 相关块在 doc.content 中的下标(若适用) */
18
+ blockIndex?: number;
19
+ }
20
+ interface ValidateOptions {
21
+ /** 必备要素(缺失记为 error);缺省为 ["title", "body"] */
22
+ required?: OfficialElement[];
23
+ /** 建议要素(缺失记为 warn);缺省为 ["mainRecipient", "signature", "dateline"] */
24
+ recommended?: OfficialElement[];
25
+ }
26
+ /** 校验一篇公文,返回问题列表(空数组表示通过)。 */
27
+ declare function validateDocument(doc: JSONContent, options?: ValidateOptions): Issue[];
28
+ /** 便捷方法:是否通过(无 error 级问题)。 */
29
+ declare function isValid(doc: JSONContent, options?: ValidateOptions): boolean;
30
+
31
+ export { type Issue, type IssueCode, type IssueLevel, type ValidateOptions, isValid, validateDocument };
@@ -0,0 +1,9 @@
1
+ import {
2
+ isValid,
3
+ validateDocument
4
+ } from "../chunk-VDLZ23IA.js";
5
+ export {
6
+ isValid,
7
+ validateDocument
8
+ };
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maxoyed/ode-core",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "description": "Headless 公文编辑器核心:GB/T 9704-2012 版式规范、Tiptap 公文节点与字体插槽,与前端框架无关。",
5
5
  "license": "MIT",
6
6
  "author": "maxoyed <y@openingsource.org>",
@@ -47,6 +47,10 @@
47
47
  "types": "./dist/pagination/index.d.ts",
48
48
  "import": "./dist/pagination/index.js"
49
49
  },
50
+ "./validate": {
51
+ "types": "./dist/validate/index.d.ts",
52
+ "import": "./dist/validate/index.js"
53
+ },
50
54
  "./docx": {
51
55
  "types": "./dist/docx/index.d.ts",
52
56
  "import": "./dist/docx/index.js"