@maxoyed/ode-core 0.0.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/LICENSE +21 -0
- package/README.md +51 -0
- package/dist/chunk-OUPZEHJO.js +162 -0
- package/dist/chunk-OUPZEHJO.js.map +1 -0
- package/dist/chunk-SYMAPCOS.js +104 -0
- package/dist/chunk-SYMAPCOS.js.map +1 -0
- package/dist/chunk-TRNXHJAU.js +21 -0
- package/dist/chunk-TRNXHJAU.js.map +1 -0
- package/dist/docx/index.d.ts +44 -0
- package/dist/docx/index.js +540 -0
- package/dist/docx/index.js.map +1 -0
- package/dist/elements-Bvueu_TD.d.ts +69 -0
- package/dist/index.d.ts +176 -0
- package/dist/index.js +608 -0
- package/dist/index.js.map +1 -0
- package/dist/pagination/index.d.ts +131 -0
- package/dist/pagination/index.js +34 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/spec/index.d.ts +69 -0
- package/dist/spec/index.js +45 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/styles.css +189 -0
- package/package.json +89 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FONT_CSS_VAR,
|
|
3
|
+
FONT_STACK
|
|
4
|
+
} from "./chunk-TRNXHJAU.js";
|
|
5
|
+
import {
|
|
6
|
+
BODY_LINE_HEIGHT_PT,
|
|
7
|
+
DASH,
|
|
8
|
+
PAGE_NUMBER_OFFSET_MM,
|
|
9
|
+
TYPE_AREA_HEIGHT_PT,
|
|
10
|
+
blocksFromDoc,
|
|
11
|
+
charsPerLineFor,
|
|
12
|
+
computePageBreaks,
|
|
13
|
+
countPages,
|
|
14
|
+
estimateLines,
|
|
15
|
+
formatPageNumber,
|
|
16
|
+
lineHeightPtFor,
|
|
17
|
+
pageNumberAlign,
|
|
18
|
+
pageNumberStyle,
|
|
19
|
+
paginate
|
|
20
|
+
} from "./chunk-OUPZEHJO.js";
|
|
21
|
+
import {
|
|
22
|
+
CHARS_PER_LINE,
|
|
23
|
+
CHAR_BOX_MM,
|
|
24
|
+
ELEMENT_SPEC,
|
|
25
|
+
FONT_SIZE_PT,
|
|
26
|
+
LINES_PER_PAGE,
|
|
27
|
+
LINE_HEIGHT_MM,
|
|
28
|
+
Layout,
|
|
29
|
+
MARGIN_MM,
|
|
30
|
+
OFFICIAL_RED,
|
|
31
|
+
PAGE_A4_MM,
|
|
32
|
+
PT_TO_MM,
|
|
33
|
+
PT_TO_PX,
|
|
34
|
+
TYPE_AREA_MM,
|
|
35
|
+
ptToMm,
|
|
36
|
+
ptToPx,
|
|
37
|
+
toHalfPoint,
|
|
38
|
+
toPt
|
|
39
|
+
} from "./chunk-SYMAPCOS.js";
|
|
40
|
+
|
|
41
|
+
// src/extensions/index.ts
|
|
42
|
+
import StarterKit from "@tiptap/starter-kit";
|
|
43
|
+
import TextStyle from "@tiptap/extension-text-style";
|
|
44
|
+
import TextAlign from "@tiptap/extension-text-align";
|
|
45
|
+
import Color from "@tiptap/extension-color";
|
|
46
|
+
import Table from "@tiptap/extension-table";
|
|
47
|
+
import TableRow from "@tiptap/extension-table-row";
|
|
48
|
+
import TableCell from "@tiptap/extension-table-cell";
|
|
49
|
+
import TableHeader from "@tiptap/extension-table-header";
|
|
50
|
+
|
|
51
|
+
// src/extensions/official-role.ts
|
|
52
|
+
import { Extension } from "@tiptap/core";
|
|
53
|
+
var OfficialRole = Extension.create({
|
|
54
|
+
name: "officialRole",
|
|
55
|
+
addOptions() {
|
|
56
|
+
return { types: ["paragraph"] };
|
|
57
|
+
},
|
|
58
|
+
addGlobalAttributes() {
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
types: this.options.types,
|
|
62
|
+
attributes: {
|
|
63
|
+
officialRole: {
|
|
64
|
+
default: null,
|
|
65
|
+
parseHTML: (element) => element.getAttribute("data-odoc-role"),
|
|
66
|
+
renderHTML: (attributes) => {
|
|
67
|
+
const role = attributes.officialRole;
|
|
68
|
+
if (!role) return {};
|
|
69
|
+
return {
|
|
70
|
+
"data-odoc-role": role,
|
|
71
|
+
class: `odoc-el odoc-el--${role}`
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
},
|
|
79
|
+
addCommands() {
|
|
80
|
+
return {
|
|
81
|
+
setOfficialRole: (role) => ({ commands }) => this.options.types.some(
|
|
82
|
+
(type) => commands.updateAttributes(type, { officialRole: role })
|
|
83
|
+
),
|
|
84
|
+
unsetOfficialRole: () => ({ commands }) => this.options.types.some(
|
|
85
|
+
(type) => commands.resetAttributes(type, "officialRole")
|
|
86
|
+
)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// src/extensions/official-image.ts
|
|
92
|
+
import Image from "@tiptap/extension-image";
|
|
93
|
+
var OfficialImage = Image.extend({
|
|
94
|
+
name: "image",
|
|
95
|
+
addAttributes() {
|
|
96
|
+
return {
|
|
97
|
+
...this.parent?.(),
|
|
98
|
+
seal: {
|
|
99
|
+
default: false,
|
|
100
|
+
parseHTML: (element) => element.hasAttribute("data-odoc-seal"),
|
|
101
|
+
renderHTML: (attributes) => attributes.seal ? { "data-odoc-seal": "true", class: "odoc-seal" } : {}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// src/extensions/hr-variant.ts
|
|
108
|
+
import { Extension as Extension2 } from "@tiptap/core";
|
|
109
|
+
var HorizontalRuleVariant = Extension2.create({
|
|
110
|
+
name: "hrVariant",
|
|
111
|
+
addOptions() {
|
|
112
|
+
return { types: ["horizontalRule"] };
|
|
113
|
+
},
|
|
114
|
+
addGlobalAttributes() {
|
|
115
|
+
return [
|
|
116
|
+
{
|
|
117
|
+
types: this.options.types,
|
|
118
|
+
attributes: {
|
|
119
|
+
variant: {
|
|
120
|
+
default: "reverse",
|
|
121
|
+
parseHTML: (element) => element.getAttribute("data-odoc-hr") || "reverse",
|
|
122
|
+
renderHTML: (attributes) => {
|
|
123
|
+
const variant = attributes.variant || "reverse";
|
|
124
|
+
return { "data-odoc-hr": variant, class: `odoc-hr odoc-hr--${variant}` };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
},
|
|
131
|
+
addCommands() {
|
|
132
|
+
return {
|
|
133
|
+
setHorizontalRuleVariant: (variant) => ({ chain }) => chain().insertContent({ type: "horizontalRule", attrs: { variant } }).run()
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// src/extensions/pagination.ts
|
|
139
|
+
import { Extension as Extension3 } from "@tiptap/core";
|
|
140
|
+
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
141
|
+
import { Decoration, DecorationSet } from "@tiptap/pm/view";
|
|
142
|
+
var MM_TO_PX = 96 / 25.4;
|
|
143
|
+
var pluginKey = new PluginKey("odocPagination");
|
|
144
|
+
function buildPageNumberEl(pageNo) {
|
|
145
|
+
const style = pageNumberStyle(pageNo);
|
|
146
|
+
const el = document.createElement("div");
|
|
147
|
+
el.className = "odoc-inline-page-number";
|
|
148
|
+
el.textContent = style.text;
|
|
149
|
+
el.style.position = "absolute";
|
|
150
|
+
if (style.align === "right") {
|
|
151
|
+
el.style.right = `${(MARGIN_MM.right + style.insetMm) * MM_TO_PX}px`;
|
|
152
|
+
} else {
|
|
153
|
+
el.style.left = `${(MARGIN_MM.left + style.insetMm) * MM_TO_PX}px`;
|
|
154
|
+
}
|
|
155
|
+
return el;
|
|
156
|
+
}
|
|
157
|
+
function buildSpacer(m) {
|
|
158
|
+
const spacer = document.createElement("div");
|
|
159
|
+
spacer.className = "odoc-page-break";
|
|
160
|
+
spacer.style.display = "block";
|
|
161
|
+
spacer.style.height = `${m.spacerPx}px`;
|
|
162
|
+
spacer.setAttribute("contenteditable", "false");
|
|
163
|
+
const whiteTop = m.remainingPx + m.bottomMarginPx;
|
|
164
|
+
const grey = m.gapPx;
|
|
165
|
+
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%)`;
|
|
166
|
+
if (m.showPageNumbers) {
|
|
167
|
+
const num = buildPageNumberEl(m.endingPageNo);
|
|
168
|
+
num.style.top = `${m.remainingPx + m.pageNumberOffsetPx}px`;
|
|
169
|
+
num.style.bottom = "";
|
|
170
|
+
spacer.appendChild(num);
|
|
171
|
+
}
|
|
172
|
+
return spacer;
|
|
173
|
+
}
|
|
174
|
+
function measureLines(view) {
|
|
175
|
+
const rootRect = view.dom.getBoundingClientRect();
|
|
176
|
+
const spacers = Array.from(view.dom.querySelectorAll(".odoc-page-break")).map(
|
|
177
|
+
(s) => {
|
|
178
|
+
const r = s.getBoundingClientRect();
|
|
179
|
+
return { top: r.top, h: r.height };
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
const offsetAbove = (yTop) => spacers.reduce((acc, s) => s.top < yTop - 0.5 ? acc + s.h : acc, 0);
|
|
183
|
+
const rects = [];
|
|
184
|
+
const positions = [];
|
|
185
|
+
let lastPos = -1;
|
|
186
|
+
const children = view.dom.children;
|
|
187
|
+
for (let i = 0; i < children.length; i++) {
|
|
188
|
+
const el = children[i];
|
|
189
|
+
if (el.classList.contains("odoc-page-break")) continue;
|
|
190
|
+
let lineRects = [];
|
|
191
|
+
if (el.firstChild) {
|
|
192
|
+
const range = document.createRange();
|
|
193
|
+
range.selectNodeContents(el);
|
|
194
|
+
lineRects = Array.from(range.getClientRects());
|
|
195
|
+
}
|
|
196
|
+
if (lineRects.length === 0) lineRects = [el.getBoundingClientRect()];
|
|
197
|
+
for (const lr of lineRects) {
|
|
198
|
+
if (lr.height < 1) continue;
|
|
199
|
+
const at = view.posAtCoords({ left: lr.left + 1, top: lr.top + lr.height / 2 });
|
|
200
|
+
if (!at) continue;
|
|
201
|
+
if (at.pos === lastPos) continue;
|
|
202
|
+
lastPos = at.pos;
|
|
203
|
+
rects.push({ top: lr.top - rootRect.top - offsetAbove(lr.top), height: lr.height });
|
|
204
|
+
positions.push(at.pos);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return { rects, positions };
|
|
208
|
+
}
|
|
209
|
+
function signatureOf(decoset) {
|
|
210
|
+
return decoset.map((b) => `${b.beforeIndex}:${Math.round(b.spacerPx)}`).join("|");
|
|
211
|
+
}
|
|
212
|
+
var Pagination = Extension3.create({
|
|
213
|
+
name: "odocPagination",
|
|
214
|
+
addOptions() {
|
|
215
|
+
return {
|
|
216
|
+
pageContentPx: TYPE_AREA_MM.height * MM_TO_PX,
|
|
217
|
+
pageGapPx: 24,
|
|
218
|
+
topMarginPx: MARGIN_MM.top * MM_TO_PX,
|
|
219
|
+
bottomMarginPx: MARGIN_MM.bottom * MM_TO_PX,
|
|
220
|
+
showPageNumbers: true
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
addProseMirrorPlugins() {
|
|
224
|
+
const options = this.options;
|
|
225
|
+
let lastSignature = "";
|
|
226
|
+
let raf = 0;
|
|
227
|
+
return [
|
|
228
|
+
new Plugin({
|
|
229
|
+
key: pluginKey,
|
|
230
|
+
state: {
|
|
231
|
+
init: () => DecorationSet.empty,
|
|
232
|
+
apply(tr, old) {
|
|
233
|
+
const meta = tr.getMeta(pluginKey);
|
|
234
|
+
if (meta) return meta.decorations;
|
|
235
|
+
return old.map(tr.mapping, tr.doc);
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
props: {
|
|
239
|
+
decorations(state) {
|
|
240
|
+
return pluginKey.getState(state);
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
view(view) {
|
|
244
|
+
const breakExtraPx = options.bottomMarginPx + options.pageGapPx + options.topMarginPx;
|
|
245
|
+
const pageNumberOffsetPx = 7 * MM_TO_PX;
|
|
246
|
+
const recompute = () => {
|
|
247
|
+
const { rects, positions } = measureLines(view);
|
|
248
|
+
const { breaks, pageCount } = computePageBreaks(rects, {
|
|
249
|
+
pageContentPx: options.pageContentPx,
|
|
250
|
+
breakExtraPx
|
|
251
|
+
});
|
|
252
|
+
let tailRemaining = 0;
|
|
253
|
+
if (rects.length) {
|
|
254
|
+
const last = rects[rects.length - 1];
|
|
255
|
+
const lastPageStart = breaks.length ? rects[breaks[breaks.length - 1].beforeIndex].top : rects[0].top;
|
|
256
|
+
tailRemaining = Math.max(
|
|
257
|
+
0,
|
|
258
|
+
options.pageContentPx - (last.top + last.height - lastPageStart)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const sig = `${signatureOf(breaks)}#${pageCount}:${Math.round(tailRemaining)}`;
|
|
262
|
+
if (sig === lastSignature) return;
|
|
263
|
+
lastSignature = sig;
|
|
264
|
+
const decos = breaks.map(
|
|
265
|
+
(b) => Decoration.widget(
|
|
266
|
+
positions[b.beforeIndex],
|
|
267
|
+
() => buildSpacer({
|
|
268
|
+
spacerPx: b.spacerPx,
|
|
269
|
+
remainingPx: Math.max(0, b.spacerPx - breakExtraPx),
|
|
270
|
+
gapPx: options.pageGapPx,
|
|
271
|
+
topMarginPx: options.topMarginPx,
|
|
272
|
+
bottomMarginPx: options.bottomMarginPx,
|
|
273
|
+
pageNumberOffsetPx,
|
|
274
|
+
endingPageNo: b.pageNo - 1,
|
|
275
|
+
showPageNumbers: options.showPageNumbers
|
|
276
|
+
}),
|
|
277
|
+
{ side: -1, key: `odoc-break-${b.beforeIndex}` }
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
if (rects.length && options.showPageNumbers) {
|
|
281
|
+
decos.push(
|
|
282
|
+
Decoration.widget(
|
|
283
|
+
view.state.doc.content.size,
|
|
284
|
+
() => buildSpacer({
|
|
285
|
+
spacerPx: tailRemaining + options.bottomMarginPx,
|
|
286
|
+
remainingPx: tailRemaining,
|
|
287
|
+
gapPx: 0,
|
|
288
|
+
topMarginPx: 0,
|
|
289
|
+
bottomMarginPx: options.bottomMarginPx,
|
|
290
|
+
pageNumberOffsetPx,
|
|
291
|
+
endingPageNo: pageCount,
|
|
292
|
+
showPageNumbers: true
|
|
293
|
+
}),
|
|
294
|
+
{ side: 1, key: `odoc-tail-${pageCount}` }
|
|
295
|
+
)
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const decorations = DecorationSet.create(view.state.doc, decos);
|
|
299
|
+
const tr = view.state.tr.setMeta(pluginKey, { decorations });
|
|
300
|
+
view.dispatch(tr);
|
|
301
|
+
};
|
|
302
|
+
const schedule = () => {
|
|
303
|
+
cancelAnimationFrame(raf);
|
|
304
|
+
raf = requestAnimationFrame(recompute);
|
|
305
|
+
};
|
|
306
|
+
schedule();
|
|
307
|
+
return {
|
|
308
|
+
update: schedule,
|
|
309
|
+
destroy: () => cancelAnimationFrame(raf)
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
];
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// src/extensions/index.ts
|
|
318
|
+
function getOfficialExtensions(options = {}) {
|
|
319
|
+
const extensions = [
|
|
320
|
+
StarterKit.configure({
|
|
321
|
+
// 公文标题层级用 officialRole 表达,禁用通用 heading 以免样式冲突
|
|
322
|
+
heading: false
|
|
323
|
+
}),
|
|
324
|
+
TextStyle,
|
|
325
|
+
Color,
|
|
326
|
+
TextAlign.configure({ types: ["paragraph"] }),
|
|
327
|
+
OfficialRole.configure({ types: ["paragraph"] }),
|
|
328
|
+
HorizontalRuleVariant,
|
|
329
|
+
Table.configure({ resizable: false }),
|
|
330
|
+
TableRow,
|
|
331
|
+
TableHeader,
|
|
332
|
+
TableCell,
|
|
333
|
+
OfficialImage.configure({ allowBase64: true, inline: false })
|
|
334
|
+
];
|
|
335
|
+
if (options.pagination) extensions.push(Pagination);
|
|
336
|
+
return extensions;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// src/templates.ts
|
|
340
|
+
function p(role, text) {
|
|
341
|
+
const node = { type: "paragraph" };
|
|
342
|
+
if (role) node.attrs = { officialRole: role };
|
|
343
|
+
if (text) node.content = [{ type: "text", text }];
|
|
344
|
+
return node;
|
|
345
|
+
}
|
|
346
|
+
function redHeadDocumentTemplate() {
|
|
347
|
+
return {
|
|
348
|
+
type: "doc",
|
|
349
|
+
content: [
|
|
350
|
+
p("issuer", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C\u6587\u4EF6"),
|
|
351
|
+
p("docNumber", "\u25CB\u5E9C\u30142026\u30151 \u53F7"),
|
|
352
|
+
{ type: "horizontalRule" },
|
|
353
|
+
p("title", "\u5173\u4E8E\xD7\xD7\xD7\u5DE5\u4F5C\u7684\u901A\u77E5"),
|
|
354
|
+
p("mainRecipient", "\u5404\u6709\u5173\u5355\u4F4D\uFF1A"),
|
|
355
|
+
p("body", "\u6839\u636E\u6709\u5173\u5DE5\u4F5C\u90E8\u7F72\uFF0C\u73B0\u5C31\xD7\xD7\xD7\u5DE5\u4F5C\u901A\u77E5\u5982\u4E0B\u3002"),
|
|
356
|
+
p("headingLevel1", "\u4E00\u3001\u603B\u4F53\u8981\u6C42"),
|
|
357
|
+
p("body", "\uFF08\u6B64\u5904\u586B\u5199\u6B63\u6587\u5185\u5BB9\u3002\uFF09"),
|
|
358
|
+
p("headingLevel2", "\uFF08\u4E00\uFF09\u5DE5\u4F5C\u76EE\u6807"),
|
|
359
|
+
p("body", "\uFF08\u6B64\u5904\u586B\u5199\u6B63\u6587\u5185\u5BB9\u3002\uFF09"),
|
|
360
|
+
p("signature", "\u25CB\u25CB\u25CB\u4EBA\u6C11\u653F\u5E9C"),
|
|
361
|
+
p("dateline", "2026 \u5E74 6 \u6708 13 \u65E5")
|
|
362
|
+
]
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function blankDocumentTemplate() {
|
|
366
|
+
return { type: "doc", content: [p("body", "")] };
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/editor.ts
|
|
370
|
+
import { Editor } from "@tiptap/core";
|
|
371
|
+
|
|
372
|
+
// src/styles/inject.ts
|
|
373
|
+
var STYLE_ELEMENT_ID = "odoc-element-styles";
|
|
374
|
+
function fontVar(role) {
|
|
375
|
+
return `var(${FONT_CSS_VAR[role]}, ${FONT_STACK[role]})`;
|
|
376
|
+
}
|
|
377
|
+
function ruleFor(role, spec) {
|
|
378
|
+
const decls = [];
|
|
379
|
+
decls.push(`font-family:${fontVar(spec.font)}`);
|
|
380
|
+
decls.push(`font-size:${toPt(spec.size)}pt`);
|
|
381
|
+
decls.push(`font-weight:${spec.bold ? 700 : 400}`);
|
|
382
|
+
if (spec.align) decls.push(`text-align:${spec.align}`);
|
|
383
|
+
if (spec.color) decls.push(`color:${spec.color}`);
|
|
384
|
+
if (spec.indent) decls.push(`text-indent:${spec.indent}em`);
|
|
385
|
+
if (spec.marginLeft) decls.push(`margin-left:${spec.marginLeft}em`);
|
|
386
|
+
if (spec.marginRight) decls.push(`margin-right:${spec.marginRight}em`);
|
|
387
|
+
return `.odoc-el--${role}{${decls.join(";")}}`;
|
|
388
|
+
}
|
|
389
|
+
function buildElementStyles() {
|
|
390
|
+
return Object.keys(ELEMENT_SPEC).map((role) => ruleFor(role, ELEMENT_SPEC[role])).join("\n");
|
|
391
|
+
}
|
|
392
|
+
function injectOfficialStyles() {
|
|
393
|
+
if (typeof document === "undefined") return;
|
|
394
|
+
if (document.getElementById(STYLE_ELEMENT_ID)) return;
|
|
395
|
+
const style = document.createElement("style");
|
|
396
|
+
style.id = STYLE_ELEMENT_ID;
|
|
397
|
+
style.textContent = buildElementStyles();
|
|
398
|
+
document.head.appendChild(style);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/editor.ts
|
|
402
|
+
function createOfficialDocumentEditor(options = {}) {
|
|
403
|
+
const {
|
|
404
|
+
content,
|
|
405
|
+
placeholder,
|
|
406
|
+
pagination = false,
|
|
407
|
+
injectStyles = true,
|
|
408
|
+
editorProps,
|
|
409
|
+
...rest
|
|
410
|
+
} = options;
|
|
411
|
+
if (injectStyles) injectOfficialStyles();
|
|
412
|
+
return new Editor({
|
|
413
|
+
...rest,
|
|
414
|
+
editorProps: {
|
|
415
|
+
...editorProps,
|
|
416
|
+
attributes: {
|
|
417
|
+
class: "odoc-typearea",
|
|
418
|
+
...editorProps?.attributes
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
extensions: getOfficialExtensions({ placeholder, pagination }),
|
|
422
|
+
content: content ?? redHeadDocumentTemplate()
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/fonts/register.ts
|
|
427
|
+
var STYLE_ELEMENT_ID2 = "odoc-registered-fonts";
|
|
428
|
+
function ensureStyleElement() {
|
|
429
|
+
let el = document.getElementById(STYLE_ELEMENT_ID2);
|
|
430
|
+
if (!el) {
|
|
431
|
+
el = document.createElement("style");
|
|
432
|
+
el.id = STYLE_ELEMENT_ID2;
|
|
433
|
+
document.head.appendChild(el);
|
|
434
|
+
}
|
|
435
|
+
return el;
|
|
436
|
+
}
|
|
437
|
+
function toCssSource(source, format) {
|
|
438
|
+
if (typeof source === "string") {
|
|
439
|
+
const fmt2 = format ? ` format("${format}")` : "";
|
|
440
|
+
return `url("${source}")${fmt2}`;
|
|
441
|
+
}
|
|
442
|
+
const blob = source instanceof Blob ? source : new Blob([source]);
|
|
443
|
+
const url = URL.createObjectURL(blob);
|
|
444
|
+
const fmt = format ? ` format("${format}")` : "";
|
|
445
|
+
return `url("${url}")${fmt}`;
|
|
446
|
+
}
|
|
447
|
+
function registerFont(options) {
|
|
448
|
+
if (typeof document === "undefined") {
|
|
449
|
+
throw new Error("registerFont \u53EA\u80FD\u5728\u6D4F\u89C8\u5668\u73AF\u5883\u8C03\u7528\u3002");
|
|
450
|
+
}
|
|
451
|
+
const { role, family, source, format, weight = "normal", target } = options;
|
|
452
|
+
if (source) {
|
|
453
|
+
const style = ensureStyleElement();
|
|
454
|
+
const face = `@font-face{font-family:"${family}";src:${toCssSource(
|
|
455
|
+
source,
|
|
456
|
+
format
|
|
457
|
+
)};font-weight:${weight};font-display:swap;}`;
|
|
458
|
+
style.appendChild(document.createTextNode(face));
|
|
459
|
+
}
|
|
460
|
+
const root = target ?? document.documentElement;
|
|
461
|
+
const prev = getComputedStyle(root).getPropertyValue(FONT_CSS_VAR[role]).trim();
|
|
462
|
+
const next = prev ? `"${family}", ${prev}` : `"${family}"`;
|
|
463
|
+
root.style.setProperty(FONT_CSS_VAR[role], next);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// src/preview/paginated.ts
|
|
467
|
+
var MM_TO_PX2 = 96 / 25.4;
|
|
468
|
+
var mm = (v) => `${v}mm`;
|
|
469
|
+
function renderBlock(node) {
|
|
470
|
+
if (node.type === "horizontalRule") {
|
|
471
|
+
const hr = document.createElement("hr");
|
|
472
|
+
const variant = node.attrs?.variant || "reverse";
|
|
473
|
+
hr.className = `odoc-separator odoc-hr--${variant}`;
|
|
474
|
+
return hr;
|
|
475
|
+
}
|
|
476
|
+
if (node.type === "image") {
|
|
477
|
+
const img = document.createElement("img");
|
|
478
|
+
if (node.attrs?.src) img.src = String(node.attrs.src);
|
|
479
|
+
if (node.attrs?.alt) img.alt = String(node.attrs.alt);
|
|
480
|
+
if (node.attrs?.seal) img.className = "odoc-seal";
|
|
481
|
+
return img;
|
|
482
|
+
}
|
|
483
|
+
if (node.type === "table") {
|
|
484
|
+
const table = document.createElement("table");
|
|
485
|
+
for (const row of node.content ?? []) {
|
|
486
|
+
const tr = document.createElement("tr");
|
|
487
|
+
for (const cell of row.content ?? []) {
|
|
488
|
+
const td = document.createElement(cell.type === "tableHeader" ? "th" : "td");
|
|
489
|
+
const text2 = (cell.content ?? []).map((p3) => (p3.content ?? []).map((t) => t.text ?? "").join("")).join("\n");
|
|
490
|
+
td.textContent = text2;
|
|
491
|
+
tr.appendChild(td);
|
|
492
|
+
}
|
|
493
|
+
table.appendChild(tr);
|
|
494
|
+
}
|
|
495
|
+
return table;
|
|
496
|
+
}
|
|
497
|
+
const p2 = document.createElement("p");
|
|
498
|
+
const role = node.attrs?.officialRole;
|
|
499
|
+
if (role) {
|
|
500
|
+
p2.className = `odoc-el odoc-el--${role}`;
|
|
501
|
+
p2.dataset.odocRole = role;
|
|
502
|
+
}
|
|
503
|
+
const text = (node.content ?? []).map((n) => n.type === "text" ? n.text ?? "" : "").join("");
|
|
504
|
+
p2.textContent = text.length ? text : "\xA0";
|
|
505
|
+
return p2;
|
|
506
|
+
}
|
|
507
|
+
function createPageNumber(pageNo) {
|
|
508
|
+
const style = pageNumberStyle(pageNo);
|
|
509
|
+
const el = document.createElement("div");
|
|
510
|
+
el.className = "odoc-page-number";
|
|
511
|
+
el.textContent = style.text;
|
|
512
|
+
el.style.position = "absolute";
|
|
513
|
+
el.style.bottom = mm(MARGIN_MM.bottom - PAGE_NUMBER_OFFSET_MM);
|
|
514
|
+
if (style.align === "right") {
|
|
515
|
+
el.style.right = mm(MARGIN_MM.right + style.insetMm);
|
|
516
|
+
} else {
|
|
517
|
+
el.style.left = mm(MARGIN_MM.left + style.insetMm);
|
|
518
|
+
}
|
|
519
|
+
return el;
|
|
520
|
+
}
|
|
521
|
+
function renderPaginatedPreview(doc, mount, options = {}) {
|
|
522
|
+
if (typeof document === "undefined") {
|
|
523
|
+
throw new Error("renderPaginatedPreview \u53EA\u80FD\u5728\u6D4F\u89C8\u5668\u73AF\u5883\u8C03\u7528\u3002");
|
|
524
|
+
}
|
|
525
|
+
const { showPageNumber = true } = options;
|
|
526
|
+
injectOfficialStyles();
|
|
527
|
+
mount.innerHTML = "";
|
|
528
|
+
mount.classList.add("odoc-canvas");
|
|
529
|
+
const pageContentPx = TYPE_AREA_MM.height * MM_TO_PX2;
|
|
530
|
+
const blocks = (doc.type === "doc" ? doc.content : [doc]) ?? [];
|
|
531
|
+
let pageNo = 0;
|
|
532
|
+
let refs;
|
|
533
|
+
const newPage = () => {
|
|
534
|
+
pageNo += 1;
|
|
535
|
+
const page = document.createElement("div");
|
|
536
|
+
page.className = "odoc-page";
|
|
537
|
+
const area = document.createElement("div");
|
|
538
|
+
area.className = "odoc-typearea";
|
|
539
|
+
page.appendChild(area);
|
|
540
|
+
if (showPageNumber) page.appendChild(createPageNumber(pageNo));
|
|
541
|
+
mount.appendChild(page);
|
|
542
|
+
return { page, area };
|
|
543
|
+
};
|
|
544
|
+
refs = newPage();
|
|
545
|
+
let used = 0;
|
|
546
|
+
for (const node of blocks) {
|
|
547
|
+
const el = renderBlock(node);
|
|
548
|
+
refs.area.appendChild(el);
|
|
549
|
+
const h = el.getBoundingClientRect().height;
|
|
550
|
+
if (used + h > pageContentPx && refs.area.childElementCount > 1) {
|
|
551
|
+
refs.area.removeChild(el);
|
|
552
|
+
refs = newPage();
|
|
553
|
+
refs.area.appendChild(el);
|
|
554
|
+
used = el.getBoundingClientRect().height;
|
|
555
|
+
} else {
|
|
556
|
+
used += h;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return pageNo;
|
|
560
|
+
}
|
|
561
|
+
export {
|
|
562
|
+
BODY_LINE_HEIGHT_PT,
|
|
563
|
+
CHARS_PER_LINE,
|
|
564
|
+
CHAR_BOX_MM,
|
|
565
|
+
DASH,
|
|
566
|
+
ELEMENT_SPEC,
|
|
567
|
+
FONT_CSS_VAR,
|
|
568
|
+
FONT_SIZE_PT,
|
|
569
|
+
FONT_STACK,
|
|
570
|
+
HorizontalRuleVariant,
|
|
571
|
+
LINES_PER_PAGE,
|
|
572
|
+
LINE_HEIGHT_MM,
|
|
573
|
+
Layout,
|
|
574
|
+
MARGIN_MM,
|
|
575
|
+
OFFICIAL_RED,
|
|
576
|
+
OfficialImage,
|
|
577
|
+
OfficialRole,
|
|
578
|
+
PAGE_A4_MM,
|
|
579
|
+
PAGE_NUMBER_OFFSET_MM,
|
|
580
|
+
PT_TO_MM,
|
|
581
|
+
PT_TO_PX,
|
|
582
|
+
Pagination,
|
|
583
|
+
TYPE_AREA_HEIGHT_PT,
|
|
584
|
+
TYPE_AREA_MM,
|
|
585
|
+
blankDocumentTemplate,
|
|
586
|
+
blocksFromDoc,
|
|
587
|
+
buildElementStyles,
|
|
588
|
+
charsPerLineFor,
|
|
589
|
+
computePageBreaks,
|
|
590
|
+
countPages,
|
|
591
|
+
createOfficialDocumentEditor,
|
|
592
|
+
estimateLines,
|
|
593
|
+
formatPageNumber,
|
|
594
|
+
getOfficialExtensions,
|
|
595
|
+
injectOfficialStyles,
|
|
596
|
+
lineHeightPtFor,
|
|
597
|
+
pageNumberAlign,
|
|
598
|
+
pageNumberStyle,
|
|
599
|
+
paginate,
|
|
600
|
+
ptToMm,
|
|
601
|
+
ptToPx,
|
|
602
|
+
redHeadDocumentTemplate,
|
|
603
|
+
registerFont,
|
|
604
|
+
renderPaginatedPreview,
|
|
605
|
+
toHalfPoint,
|
|
606
|
+
toPt
|
|
607
|
+
};
|
|
608
|
+
//# sourceMappingURL=index.js.map
|