@file-viewer/core 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.en.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/config/options.d.ts +1 -1
  4. package/dist/config/options.js +1 -1
  5. package/dist/contracts/types.d.ts +71 -1
  6. package/dist/headless.d.ts +2 -2
  7. package/dist/headless.js +1 -1
  8. package/dist/index.d.ts +9 -6
  9. package/dist/index.js +105 -48
  10. package/dist/platform/assets.d.ts +3 -1
  11. package/dist/platform/assets.js +18 -2
  12. package/dist/registry/capabilities.d.ts +2 -2
  13. package/dist/registry/capabilities.js +2 -1
  14. package/dist/registry/formats.d.ts +20 -7
  15. package/dist/registry/formats.js +14 -5
  16. package/dist/registry/registry.d.ts +8 -1
  17. package/dist/registry/registry.js +29 -0
  18. package/dist/renderers/image.js +1 -10
  19. package/dist/renderers/index.d.ts +320 -2
  20. package/dist/renderers/index.js +27 -157
  21. package/dist/viewer/createViewer.js +86 -3
  22. package/package.json +17 -44
  23. package/dist/renderers/archive.d.ts +0 -2
  24. package/dist/renderers/archive.js +0 -547
  25. package/dist/renderers/archiveCache.d.ts +0 -10
  26. package/dist/renderers/archiveCache.js +0 -96
  27. package/dist/renderers/archiveFallback.d.ts +0 -7
  28. package/dist/renderers/archiveFallback.js +0 -166
  29. package/dist/renderers/archiveShared.d.ts +0 -23
  30. package/dist/renderers/archiveShared.js +0 -71
  31. package/dist/renderers/audio.d.ts +0 -8
  32. package/dist/renderers/audio.js +0 -219
  33. package/dist/renderers/cad.d.ts +0 -2
  34. package/dist/renderers/cad.js +0 -446
  35. package/dist/renderers/code.d.ts +0 -11
  36. package/dist/renderers/code.js +0 -233
  37. package/dist/renderers/data.d.ts +0 -7
  38. package/dist/renderers/data.js +0 -370
  39. package/dist/renderers/drawing.d.ts +0 -10
  40. package/dist/renderers/drawing.js +0 -882
  41. package/dist/renderers/eda.d.ts +0 -2
  42. package/dist/renderers/eda.js +0 -434
  43. package/dist/renderers/edaParser.d.ts +0 -77
  44. package/dist/renderers/edaParser.js +0 -569
  45. package/dist/renderers/email.d.ts +0 -2
  46. package/dist/renderers/email.js +0 -463
  47. package/dist/renderers/epub.d.ts +0 -2
  48. package/dist/renderers/epub.js +0 -331
  49. package/dist/renderers/geo.d.ts +0 -2
  50. package/dist/renderers/geo.js +0 -284
  51. package/dist/renderers/markdown.d.ts +0 -2
  52. package/dist/renderers/markdown.js +0 -83
  53. package/dist/renderers/model.d.ts +0 -2
  54. package/dist/renderers/model.js +0 -567
  55. package/dist/renderers/ofd.d.ts +0 -2
  56. package/dist/renderers/ofd.js +0 -256
  57. package/dist/renderers/openDocument.d.ts +0 -2
  58. package/dist/renderers/openDocument.js +0 -122
  59. package/dist/renderers/pdf.d.ts +0 -3
  60. package/dist/renderers/pdf.js +0 -1001
  61. package/dist/renderers/pdfStyles.d.ts +0 -1
  62. package/dist/renderers/pdfStyles.js +0 -1
  63. package/dist/renderers/pptx.d.ts +0 -2
  64. package/dist/renderers/pptx.js +0 -217
  65. package/dist/renderers/spreadsheet/state.d.ts +0 -80
  66. package/dist/renderers/spreadsheet/state.js +0 -96
  67. package/dist/renderers/spreadsheet/view.d.ts +0 -25
  68. package/dist/renderers/spreadsheet/view.js +0 -833
  69. package/dist/renderers/spreadsheet/worker/index.d.ts +0 -2
  70. package/dist/renderers/spreadsheet/worker/index.js +0 -1
  71. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.d.ts +0 -73
  72. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.js +0 -623
  73. package/dist/renderers/spreadsheet/worker/sheetjs/color.d.ts +0 -2
  74. package/dist/renderers/spreadsheet/worker/sheetjs/color.js +0 -73
  75. package/dist/renderers/spreadsheet/worker/sheetjs/index.d.ts +0 -1
  76. package/dist/renderers/spreadsheet/worker/sheetjs/index.js +0 -1
  77. package/dist/renderers/spreadsheet/worker/sheetjs/parser.d.ts +0 -18
  78. package/dist/renderers/spreadsheet/worker/sheetjs/parser.js +0 -106
  79. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.d.ts +0 -1
  80. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.js +0 -11
  81. package/dist/renderers/spreadsheet/worker/type.d.ts +0 -57
  82. package/dist/renderers/spreadsheet/worker/type.js +0 -1
  83. package/dist/renderers/spreadsheet.d.ts +0 -3
  84. package/dist/renderers/spreadsheet.js +0 -929
  85. package/dist/renderers/typst.d.ts +0 -8
  86. package/dist/renderers/typst.js +0 -547
  87. package/dist/renderers/umd/parser.d.ts +0 -30
  88. package/dist/renderers/umd/parser.js +0 -408
  89. package/dist/renderers/umd.d.ts +0 -2
  90. package/dist/renderers/umd.js +0 -297
  91. package/dist/renderers/video.d.ts +0 -8
  92. package/dist/renderers/video.js +0 -108
  93. package/dist/renderers/wordDoc.d.ts +0 -5
  94. package/dist/renderers/wordDoc.js +0 -284
  95. package/dist/renderers/wordDocx.d.ts +0 -5
  96. package/dist/renderers/wordDocx.js +0 -985
  97. package/dist/renderers/wordDocx.worker.d.ts +0 -1
  98. package/dist/renderers/wordDocx.worker.js +0 -96
  99. package/vendor/ofd/dltech/jbig2/arithmetic_decoder.js +0 -183
  100. package/vendor/ofd/dltech/jbig2/ccitt.js +0 -1070
  101. package/vendor/ofd/dltech/jbig2/compatibility.js +0 -12
  102. package/vendor/ofd/dltech/jbig2/core_utils.js +0 -180
  103. package/vendor/ofd/dltech/jbig2/is_node.js +0 -27
  104. package/vendor/ofd/dltech/jbig2/jbig2.js +0 -2589
  105. package/vendor/ofd/dltech/jbig2/jbig2_stream.js +0 -81
  106. package/vendor/ofd/dltech/jbig2/primitives.js +0 -387
  107. package/vendor/ofd/dltech/jbig2/stream.js +0 -1348
  108. package/vendor/ofd/dltech/jbig2/util.js +0 -972
  109. package/vendor/ofd/dltech/ofd/ofd.d.ts +0 -11
  110. package/vendor/ofd/dltech/ofd/ofd.js +0 -100
  111. package/vendor/ofd/dltech/ofd/ofd_parser.js +0 -395
  112. package/vendor/ofd/dltech/ofd/ofd_render.js +0 -473
  113. package/vendor/ofd/dltech/ofd/ofd_util.js +0 -350
  114. package/vendor/ofd/dltech/ofd/pipeline.js +0 -26
@@ -1,8 +0,0 @@
1
- import type { FileRenderContext, FileViewerRenderedInstance } from '../contracts/types';
2
- declare global {
3
- interface Window {
4
- __FLYFISH_TYPST_COMPILER_WASM_URL__?: string;
5
- __FLYFISH_TYPST_RENDERER_WASM_URL__?: string;
6
- }
7
- }
8
- export default function renderTypst(buffer: ArrayBuffer, target: HTMLDivElement, _type?: string, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;
@@ -1,547 +0,0 @@
1
- import { $typst } from '@myriaddreamin/typst.ts';
2
- import { resolveFileViewerTypstCompilerWasmUrl, resolveFileViewerTypstRendererWasmUrl, } from '../platform/assets.js';
3
- import { registerFileViewerZoomProvider, unregisterFileViewerZoomProvider, } from '../features/document/dom/index.js';
4
- import { createFileViewerZoomChangeEmitter } from '../features/document/zoom.js';
5
- import { formatCssPixels } from '../output/printLayout.js';
6
- import { readFileViewerText } from '../source/index.js';
7
- const typstStyle = `
8
- .typst-viewer{min-height:100%;overflow:auto;background:#eef1f4;color:#172033}
9
- .typst-toolbar{position:sticky;top:0;z-index:2;display:flex;min-height:52px;align-items:center;justify-content:space-between;gap:16px;padding:10px 18px;border-bottom:1px solid rgba(120,134,155,.18);background:rgba(248,250,252,.92);backdrop-filter:blur(16px)}
10
- .typst-toolbar div{min-width:0}
11
- .typst-toolbar strong,.typst-toolbar span{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
12
- .typst-toolbar strong{color:#172033;font-size:14px;font-weight:800}
13
- .typst-toolbar span,.typst-toolbar em{color:#6a778b;font-size:12px;font-style:normal;font-weight:700}
14
- .typst-pages{display:flex;min-height:calc(100% - 52px);flex-direction:column;align-items:center;gap:22px;box-sizing:border-box;padding:28px 16px 44px}
15
- .typst-page-shell{max-width:100%;overflow:hidden;border:1px solid rgba(20,35,53,.1);background:#fff;box-shadow:0 18px 44px rgba(15,23,42,.14)}
16
- .typst-page-content svg{display:block;width:100%;height:auto}
17
- .typst-loading,.typst-error{width:min(520px,calc(100% - 32px));box-sizing:border-box;margin:80px auto;padding:26px;border:1px solid rgba(120,134,155,.18);border-radius:14px;background:#fff;box-shadow:0 18px 44px rgba(15,23,42,.12)}
18
- .typst-loading{display:grid;justify-items:center;gap:10px;text-align:center}
19
- .typst-loading span{width:34px;height:34px;border:3px solid rgba(46,130,94,.18);border-top-color:#239661;border-radius:999px;animation:typst-spin .8s linear infinite}
20
- .typst-loading strong,.typst-error strong{color:#172033;font-size:16px}
21
- .typst-loading p{margin:0;color:#6a778b;font-size:13px}
22
- .typst-error{color:#9f1d1d}
23
- .typst-error pre{max-height:360px;margin:14px 0 0;overflow:auto;border-radius:10px;background:#fff1f2;color:#9f1d1d;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:12px;line-height:1.7;padding:14px;white-space:pre-wrap}
24
- .file-viewer[data-viewer-theme='dark'] .typst-viewer{background:#101820;color:#e6edf3}
25
- .file-viewer[data-viewer-theme='dark'] .typst-toolbar{border-bottom-color:rgba(139,148,158,.22);background:rgba(15,23,42,.9)}
26
- .file-viewer[data-viewer-theme='dark'] .typst-toolbar strong{color:#f8fafc}
27
- .file-viewer[data-viewer-theme='dark'] .typst-toolbar span,.file-viewer[data-viewer-theme='dark'] .typst-toolbar em{color:#9aa7b8}
28
- .file-viewer[data-viewer-theme='dark'] .typst-page-shell{border-color:rgba(139,148,158,.26);box-shadow:0 24px 56px rgba(0,0,0,.38)}
29
- .file-viewer[data-viewer-theme='dark'] .typst-loading,.file-viewer[data-viewer-theme='dark'] .typst-error{border-color:rgba(139,148,158,.22);background:#151b23;box-shadow:0 24px 56px rgba(0,0,0,.32)}
30
- .file-viewer[data-viewer-theme='dark'] .typst-loading strong,.file-viewer[data-viewer-theme='dark'] .typst-error strong{color:#f8fafc}
31
- @keyframes typst-spin{to{transform:rotate(360deg)}}
32
- @media (max-width:767px){.typst-toolbar{align-items:flex-start;flex-direction:column;gap:4px}.typst-pages{gap:16px;padding:16px 10px 28px}}
33
- @media (prefers-color-scheme:dark){.file-viewer[data-viewer-theme='system'] .typst-viewer{background:#101820;color:#e6edf3}.file-viewer[data-viewer-theme='system'] .typst-toolbar{border-bottom-color:rgba(139,148,158,.22);background:rgba(15,23,42,.9)}.file-viewer[data-viewer-theme='system'] .typst-toolbar strong{color:#f8fafc}.file-viewer[data-viewer-theme='system'] .typst-toolbar span,.file-viewer[data-viewer-theme='system'] .typst-toolbar em{color:#9aa7b8}.file-viewer[data-viewer-theme='system'] .typst-page-shell{border-color:rgba(139,148,158,.26);box-shadow:0 24px 56px rgba(0,0,0,.38)}.file-viewer[data-viewer-theme='system'] .typst-loading,.file-viewer[data-viewer-theme='system'] .typst-error{border-color:rgba(139,148,158,.22);background:#151b23;box-shadow:0 24px 56px rgba(0,0,0,.32)}.file-viewer[data-viewer-theme='system'] .typst-loading strong,.file-viewer[data-viewer-theme='system'] .typst-error strong{color:#f8fafc}}
34
- `;
35
- let typstEngineConfigKey = '';
36
- const DEFAULT_TYPST_RENDER_TIMEOUT_MS = 60000;
37
- class TypstRenderTimeoutError extends Error {
38
- constructor(timeoutMs) {
39
- super(`Typst 编译超过 ${Math.round(timeoutMs / 1000)} 秒`);
40
- this.name = 'TypstRenderTimeoutError';
41
- }
42
- }
43
- const createStyle = (documentRef) => {
44
- const style = documentRef.createElement('style');
45
- style.textContent = typstStyle;
46
- return style;
47
- };
48
- const createElement = (documentRef, tagName, className, text) => {
49
- const element = documentRef.createElement(tagName);
50
- if (className) {
51
- element.className = className;
52
- }
53
- if (text !== undefined) {
54
- element.textContent = text;
55
- }
56
- return element;
57
- };
58
- const getWindowOverride = (key) => {
59
- if (typeof window === 'undefined') {
60
- return undefined;
61
- }
62
- return window[key];
63
- };
64
- const configureTypstEngine = (compilerWasmUrl, rendererWasmUrl) => {
65
- const configKey = `${compilerWasmUrl}\n${rendererWasmUrl}`;
66
- if (typstEngineConfigKey === configKey) {
67
- return;
68
- }
69
- $typst.setCompilerInitOptions({
70
- getModule: () => compilerWasmUrl,
71
- });
72
- $typst.setRendererInitOptions({
73
- getModule: () => rendererWasmUrl,
74
- });
75
- typstEngineConfigKey = configKey;
76
- };
77
- const pushUniqueTypstCandidate = (candidates, candidate) => {
78
- if (candidates.some(item => item.compilerWasmUrl === candidate.compilerWasmUrl &&
79
- item.rendererWasmUrl === candidate.rendererWasmUrl)) {
80
- return;
81
- }
82
- candidates.push(candidate);
83
- };
84
- const resolveTypstEngineCandidates = (context, documentBaseUrl) => {
85
- var _a;
86
- const typstOptions = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.typst;
87
- const compilerOverride = getWindowOverride('__FLYFISH_TYPST_COMPILER_WASM_URL__');
88
- const rendererOverride = getWindowOverride('__FLYFISH_TYPST_RENDERER_WASM_URL__');
89
- const compilerWasmUrl = resolveFileViewerTypstCompilerWasmUrl(typstOptions, [
90
- compilerOverride,
91
- ], documentBaseUrl);
92
- const rendererWasmUrl = resolveFileViewerTypstRendererWasmUrl(typstOptions, [
93
- rendererOverride,
94
- ], documentBaseUrl);
95
- const hasConfiguredAsset = Boolean((typstOptions === null || typstOptions === void 0 ? void 0 : typstOptions.compilerWasmUrl) ||
96
- (typstOptions === null || typstOptions === void 0 ? void 0 : typstOptions.rendererWasmUrl) ||
97
- compilerOverride ||
98
- rendererOverride);
99
- const candidates = [];
100
- pushUniqueTypstCandidate(candidates, {
101
- compilerWasmUrl,
102
- rendererWasmUrl,
103
- source: hasConfiguredAsset ? 'configured' : 'local',
104
- preflight: !hasConfiguredAsset,
105
- });
106
- return candidates;
107
- };
108
- const isHttpUrl = (url) => /^https?:\/\//i.test(url);
109
- const isKnownMissingWasmUrl = async (url) => {
110
- if (typeof fetch !== 'function' || !isHttpUrl(url)) {
111
- return false;
112
- }
113
- try {
114
- const response = await fetch(url, {
115
- cache: 'force-cache',
116
- method: 'HEAD',
117
- });
118
- return response.status === 404 || response.status === 410;
119
- }
120
- catch {
121
- return false;
122
- }
123
- };
124
- const resolveKnownMissingTypstAsset = async (candidate) => {
125
- if (await isKnownMissingWasmUrl(candidate.compilerWasmUrl)) {
126
- return `Typst compiler WASM missing: ${candidate.compilerWasmUrl}`;
127
- }
128
- if (await isKnownMissingWasmUrl(candidate.rendererWasmUrl)) {
129
- return `Typst renderer WASM missing: ${candidate.rendererWasmUrl}`;
130
- }
131
- return '';
132
- };
133
- const isTypstAssetLoadError = (error) => {
134
- if (Array.isArray(error)) {
135
- return false;
136
- }
137
- const message = error instanceof Error ? error.message : String(error);
138
- return /wasm|webassembly|fetch|module|instantiate|compile|network|404|410/i.test(message);
139
- };
140
- const escapeAttribute = (value) => {
141
- return value.replace(/[&<>"']/g, char => {
142
- const entities = {
143
- '&': '&amp;',
144
- '<': '&lt;',
145
- '>': '&gt;',
146
- '"': '&quot;',
147
- "'": '&#39;',
148
- };
149
- return entities[char] || char;
150
- });
151
- };
152
- const readNumberAttribute = (element, name) => {
153
- const value = Number.parseFloat(element.getAttribute(name) || '');
154
- return Number.isFinite(value) && value > 0 ? value : 0;
155
- };
156
- const removeUnsafeSvgContent = (root) => {
157
- root.querySelectorAll('script').forEach(script => script.remove());
158
- root.querySelectorAll('*').forEach(element => {
159
- Array.from(element.attributes).forEach(attribute => {
160
- const name = attribute.name.toLowerCase();
161
- const value = attribute.value.trim().toLowerCase();
162
- if (name.startsWith('on') || value.startsWith('javascript:')) {
163
- element.removeAttribute(attribute.name);
164
- }
165
- });
166
- });
167
- };
168
- const serializeNode = (node) => {
169
- return new XMLSerializer().serializeToString(node);
170
- };
171
- const parseTypstSvgPages = (svgText) => {
172
- const parser = new DOMParser();
173
- const documentSvg = parser.parseFromString(svgText, 'image/svg+xml');
174
- const parseError = documentSvg.querySelector('parsererror');
175
- if (parseError) {
176
- throw new Error(parseError.textContent || 'Typst SVG 解析失败');
177
- }
178
- removeUnsafeSvgContent(documentSvg);
179
- const root = documentSvg.documentElement;
180
- const sharedNodes = Array.from(root.children)
181
- .filter(child => ['style', 'defs'].includes(child.tagName.toLowerCase()))
182
- .map(serializeNode)
183
- .join('');
184
- const pageGroups = Array.from(root.querySelectorAll('g.typst-page'));
185
- const fallbackWidth = readNumberAttribute(root, 'data-width') ||
186
- readNumberAttribute(root, 'width') ||
187
- 596;
188
- const fallbackHeight = readNumberAttribute(root, 'data-height') ||
189
- readNumberAttribute(root, 'height') ||
190
- 842;
191
- if (!pageGroups.length) {
192
- return [{
193
- index: 1,
194
- width: fallbackWidth,
195
- height: fallbackHeight,
196
- svg: svgText,
197
- }];
198
- }
199
- return pageGroups.map((group, index) => {
200
- const pageWidth = readNumberAttribute(group, 'data-page-width') || fallbackWidth;
201
- const pageHeight = readNumberAttribute(group, 'data-page-height') || fallbackHeight;
202
- const pageClone = group.cloneNode(true);
203
- pageClone.setAttribute('transform', 'translate(0, 0)');
204
- const pageSvg = [
205
- `<svg style="overflow:visible;" class="typst-doc" viewBox="0 0 ${pageWidth} ${pageHeight}" width="${pageWidth}" height="${pageHeight}" data-width="${pageWidth}" data-height="${pageHeight}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml">`,
206
- sharedNodes,
207
- serializeNode(pageClone),
208
- '</svg>',
209
- ].join('');
210
- return {
211
- index: index + 1,
212
- width: pageWidth,
213
- height: pageHeight,
214
- svg: pageSvg,
215
- };
216
- });
217
- };
218
- const formatTypstError = (error) => {
219
- if (Array.isArray(error)) {
220
- return error.map(item => {
221
- if (item && typeof item === 'object' && 'message' in item) {
222
- const severity = 'severity' in item ? String(item.severity) : 'Error';
223
- return `${severity}: ${String(item.message)}`;
224
- }
225
- return String(item);
226
- }).join('\n');
227
- }
228
- if (error instanceof Error) {
229
- return error.message;
230
- }
231
- return String(error);
232
- };
233
- const formatTypstRuntimeError = (error) => {
234
- const message = formatTypstError(error);
235
- if (error instanceof TypstRenderTimeoutError) {
236
- return [
237
- message,
238
- '请检查 Typst 源文件复杂度,或通过 options.typst.renderTimeoutMs 调大浏览器端编译超时。'
239
- ].join('\n\n');
240
- }
241
- if (isTypstAssetLoadError(error)) {
242
- return [
243
- message,
244
- 'Typst 需要本地 compiler / renderer WASM。请运行 file-viewer-copy-assets,或配置 options.typst.compilerWasmUrl / options.typst.rendererWasmUrl,并确认服务器以 application/wasm 返回资源。'
245
- ].join('\n\n');
246
- }
247
- return message;
248
- };
249
- const clampZoom = (value) => {
250
- return Math.min(3, Math.max(0.3, Number(value.toFixed(2))));
251
- };
252
- const normalizeRenderTimeoutMs = (timeoutMs) => {
253
- if (!Number.isFinite(timeoutMs) || timeoutMs === undefined) {
254
- return DEFAULT_TYPST_RENDER_TIMEOUT_MS;
255
- }
256
- return Math.max(0, timeoutMs);
257
- };
258
- const withRenderTimeout = async (promise, timeoutMs) => {
259
- if (timeoutMs <= 0) {
260
- return promise;
261
- }
262
- let timeoutId;
263
- const timeoutPromise = new Promise((_, reject) => {
264
- timeoutId = setTimeout(() => reject(new TypstRenderTimeoutError(timeoutMs)), timeoutMs);
265
- });
266
- try {
267
- return await Promise.race([promise, timeoutPromise]);
268
- }
269
- finally {
270
- if (timeoutId) {
271
- clearTimeout(timeoutId);
272
- }
273
- }
274
- };
275
- const buildExportStyles = () => `
276
- <style>
277
- .typst-export-document {
278
- box-sizing: border-box;
279
- display: flex;
280
- flex-direction: column;
281
- align-items: center;
282
- gap: 18px;
283
- margin: 0;
284
- padding: 24px;
285
- background: #eef1f4;
286
- }
287
- .typst-export-page {
288
- box-sizing: border-box;
289
- flex: 0 0 auto;
290
- overflow: hidden;
291
- background: #ffffff;
292
- box-shadow: 0 18px 42px rgba(15, 23, 42, 0.14);
293
- }
294
- .typst-export-page svg {
295
- display: block;
296
- width: 100%;
297
- height: auto;
298
- }
299
- </style>
300
- `;
301
- const buildExportHtml = (pages, filename) => {
302
- return `${buildExportStyles()}<main class="typst-export-document" aria-label="${escapeAttribute(filename || 'Typst document')}">${pages.map(page => {
303
- const width = formatCssPixels(page.width);
304
- const height = formatCssPixels(page.height);
305
- return `<section class="typst-export-page viewer-print-page" style="--viewer-print-page-width:${width};--viewer-print-page-height:${height};width:${width};height:${height};" aria-label="Page ${page.index}">${page.svg}</section>`;
306
- }).join('')}</main>`;
307
- };
308
- const buildPrintStyle = (pages) => {
309
- const firstPage = pages[0];
310
- const width = firstPage ? formatCssPixels(firstPage.width) : '596px';
311
- const height = firstPage ? formatCssPixels(firstPage.height) : '842px';
312
- return `
313
- @page { size: ${width} ${height}; margin: 0; }
314
- @media print {
315
- html,
316
- body {
317
- width: ${width};
318
- min-width: ${width};
319
- margin: 0 !important;
320
- background: #ffffff !important;
321
- }
322
- .typst-export-document {
323
- display: block !important;
324
- margin: 0 !important;
325
- padding: 0 !important;
326
- background: #ffffff !important;
327
- }
328
- .typst-export-page {
329
- display: block !important;
330
- margin: 0 !important;
331
- border: 0 !important;
332
- box-shadow: none !important;
333
- break-after: page;
334
- page-break-after: always;
335
- }
336
- .typst-export-page:last-child {
337
- break-after: auto;
338
- page-break-after: auto;
339
- }
340
- .typst-export-page svg {
341
- width: 100% !important;
342
- height: auto !important;
343
- }
344
- }
345
- `;
346
- };
347
- const buildExportAdapter = (pages, filename) => {
348
- if (!pages.length) {
349
- return null;
350
- }
351
- return {
352
- includeDocumentStyles: false,
353
- print: true,
354
- exportHtml: true,
355
- printStyle: () => buildPrintStyle(pages),
356
- toHtml: () => buildExportHtml(pages, filename),
357
- };
358
- };
359
- const getPageSummary = (pages) => {
360
- if (!pages.length) {
361
- return '0 pages';
362
- }
363
- const firstPage = pages[0];
364
- return `${pages.length} pages / ${Math.round(firstPage.width)} x ${Math.round(firstPage.height)} pt`;
365
- };
366
- export default async function renderTypst(buffer, target, _type, context) {
367
- const source = await readFileViewerText(buffer);
368
- const documentRef = target.ownerDocument || document;
369
- const zoomEmitter = createFileViewerZoomChangeEmitter();
370
- let state = 'loading';
371
- let pages = [];
372
- let errorMessage = '';
373
- let zoom = 1;
374
- let renderToken = 0;
375
- let disposed = false;
376
- const pageShells = new Map();
377
- const root = createElement(documentRef, 'div', 'typst-viewer');
378
- root.dataset.viewerZoomProvider = 'typst';
379
- const toolbar = createElement(documentRef, 'header', 'typst-toolbar');
380
- const titleGroup = createElement(documentRef, 'div');
381
- const title = createElement(documentRef, 'strong', undefined, (context === null || context === void 0 ? void 0 : context.filename) || 'Typst document');
382
- const summary = createElement(documentRef, 'span', undefined, 'Typst WASM renderer');
383
- const status = createElement(documentRef, 'em', undefined, '正在编译');
384
- const body = createElement(documentRef, 'div');
385
- titleGroup.append(title, summary);
386
- toolbar.append(titleGroup, status);
387
- root.append(toolbar, body);
388
- target.replaceChildren(createStyle(documentRef), root);
389
- const getZoomState = () => ({
390
- scale: zoom,
391
- label: `${Math.round(zoom * 100)}%`,
392
- canZoomIn: zoom < 3,
393
- canZoomOut: zoom > 0.3,
394
- canReset: zoom !== 1,
395
- minScale: 0.3,
396
- maxScale: 3,
397
- });
398
- const applyPageZoom = () => {
399
- pages.forEach(page => {
400
- const shell = pageShells.get(page.index);
401
- if (!shell) {
402
- return;
403
- }
404
- shell.style.width = `${page.width * zoom}px`;
405
- shell.style.maxWidth = '100%';
406
- shell.style.height = 'auto';
407
- });
408
- };
409
- const setZoom = (scale) => {
410
- zoom = clampZoom(scale);
411
- applyPageZoom();
412
- zoomEmitter.emit();
413
- return getZoomState();
414
- };
415
- registerFileViewerZoomProvider(root, {
416
- zoomIn: () => setZoom(zoom + 0.1),
417
- zoomOut: () => setZoom(zoom - 0.1),
418
- resetZoom: () => setZoom(1),
419
- setZoom,
420
- getState: getZoomState,
421
- subscribe: zoomEmitter.subscribe,
422
- });
423
- const registerExportAdapter = () => {
424
- var _a;
425
- (_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, buildExportAdapter(pages, context.filename));
426
- };
427
- const renderLoading = () => {
428
- const loading = createElement(documentRef, 'div', 'typst-loading');
429
- loading.setAttribute('role', 'status');
430
- loading.append(createElement(documentRef, 'span'), createElement(documentRef, 'strong', undefined, '正在解析 Typst'), createElement(documentRef, 'p', undefined, '加载编译器并生成页面预览...'));
431
- body.replaceChildren(loading);
432
- };
433
- const renderError = () => {
434
- const error = createElement(documentRef, 'div', 'typst-error');
435
- error.append(createElement(documentRef, 'strong', undefined, 'Typst 渲染失败'), createElement(documentRef, 'pre', undefined, errorMessage));
436
- body.replaceChildren(error);
437
- };
438
- const renderPages = () => {
439
- pageShells.clear();
440
- const pagesRoot = createElement(documentRef, 'main', 'typst-pages');
441
- pagesRoot.setAttribute('aria-label', 'Typst preview pages');
442
- pages.forEach(page => {
443
- const shell = createElement(documentRef, 'section', 'typst-page-shell');
444
- shell.setAttribute('aria-label', `Page ${page.index}`);
445
- const content = createElement(documentRef, 'div', 'typst-page-content');
446
- content.innerHTML = page.svg;
447
- shell.append(content);
448
- pageShells.set(page.index, shell);
449
- pagesRoot.append(shell);
450
- });
451
- body.replaceChildren(pagesRoot);
452
- applyPageZoom();
453
- };
454
- const syncUi = () => {
455
- summary.textContent = state === 'ready'
456
- ? getPageSummary(pages)
457
- : 'Typst WASM renderer';
458
- status.textContent = state === 'loading'
459
- ? '正在编译'
460
- : state === 'error'
461
- ? '编译失败'
462
- : '已渲染';
463
- if (state === 'loading') {
464
- renderLoading();
465
- }
466
- else if (state === 'error') {
467
- renderError();
468
- }
469
- else {
470
- renderPages();
471
- }
472
- };
473
- const renderTypstSvg = async () => {
474
- var _a, _b;
475
- const candidates = resolveTypstEngineCandidates(context, documentRef.baseURI);
476
- const timeoutMs = normalizeRenderTimeoutMs((_b = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.typst) === null || _b === void 0 ? void 0 : _b.renderTimeoutMs);
477
- let lastError;
478
- for (const candidate of candidates) {
479
- const missingAsset = candidate.preflight
480
- ? await resolveKnownMissingTypstAsset(candidate)
481
- : '';
482
- if (missingAsset) {
483
- lastError = new Error(missingAsset);
484
- continue;
485
- }
486
- try {
487
- configureTypstEngine(candidate.compilerWasmUrl, candidate.rendererWasmUrl);
488
- return await withRenderTimeout($typst.svg({
489
- mainContent: source,
490
- data_selection: {
491
- body: true,
492
- defs: true,
493
- css: true,
494
- js: false,
495
- },
496
- }), timeoutMs);
497
- }
498
- catch (error) {
499
- lastError = error;
500
- if (error instanceof TypstRenderTimeoutError || !isTypstAssetLoadError(error)) {
501
- throw error;
502
- }
503
- }
504
- }
505
- throw lastError instanceof Error ? lastError : new Error('Typst WASM 加载失败');
506
- };
507
- const render = async () => {
508
- var _a, _b;
509
- const token = ++renderToken;
510
- state = 'loading';
511
- errorMessage = '';
512
- pages = [];
513
- (_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, null);
514
- syncUi();
515
- try {
516
- const svg = await renderTypstSvg();
517
- if (disposed || token !== renderToken) {
518
- return;
519
- }
520
- pages = parseTypstSvgPages(svg);
521
- state = 'ready';
522
- syncUi();
523
- registerExportAdapter();
524
- (_b = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _b === void 0 ? void 0 : _b.call(context);
525
- }
526
- catch (error) {
527
- if (disposed || token !== renderToken) {
528
- return;
529
- }
530
- errorMessage = formatTypstRuntimeError(error);
531
- state = 'error';
532
- syncUi();
533
- }
534
- };
535
- void render();
536
- return {
537
- $el: target,
538
- unmount() {
539
- var _a;
540
- disposed = true;
541
- renderToken += 1;
542
- unregisterFileViewerZoomProvider(root);
543
- (_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, null);
544
- target.replaceChildren();
545
- },
546
- };
547
- }
@@ -1,30 +0,0 @@
1
- export type UmdBookKind = 'text' | 'comic' | 'mixed' | 'unknown';
2
- export interface UmdImage {
3
- bytes: Uint8Array;
4
- extension: string;
5
- id: string;
6
- mimeType: string;
7
- }
8
- export interface UmdChapter {
9
- content: string;
10
- end: number;
11
- id: string;
12
- images: UmdImage[];
13
- start: number;
14
- title: string;
15
- }
16
- export interface UmdBook {
17
- author: string;
18
- category: string;
19
- chapters: UmdChapter[];
20
- contentLength: number;
21
- cover?: UmdImage;
22
- kind: UmdBookKind;
23
- publishedAt: string;
24
- publisher: string;
25
- rawType: number;
26
- title: string;
27
- vendor: string;
28
- warnings: string[];
29
- }
30
- export declare const parseUmdBook: (buffer: ArrayBuffer) => UmdBook;