@file-viewer/core 2.0.11 → 2.1.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.
Files changed (116) 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 +76 -1
  6. package/dist/headless.d.ts +3 -3
  7. package/dist/headless.js +2 -2
  8. package/dist/index.d.ts +10 -7
  9. package/dist/index.js +106 -49
  10. package/dist/lifecycle/operations.d.ts +1 -0
  11. package/dist/lifecycle/operations.js +65 -6
  12. package/dist/platform/assets.d.ts +3 -1
  13. package/dist/platform/assets.js +43 -6
  14. package/dist/registry/capabilities.d.ts +2 -2
  15. package/dist/registry/capabilities.js +2 -1
  16. package/dist/registry/formats.d.ts +20 -7
  17. package/dist/registry/formats.js +14 -5
  18. package/dist/registry/registry.d.ts +8 -1
  19. package/dist/registry/registry.js +29 -0
  20. package/dist/renderers/image.js +1 -10
  21. package/dist/renderers/index.d.ts +320 -2
  22. package/dist/renderers/index.js +27 -157
  23. package/dist/viewer/createViewer.js +86 -3
  24. package/package.json +17 -44
  25. package/dist/renderers/archive.d.ts +0 -2
  26. package/dist/renderers/archive.js +0 -547
  27. package/dist/renderers/archiveCache.d.ts +0 -10
  28. package/dist/renderers/archiveCache.js +0 -96
  29. package/dist/renderers/archiveFallback.d.ts +0 -7
  30. package/dist/renderers/archiveFallback.js +0 -166
  31. package/dist/renderers/archiveShared.d.ts +0 -23
  32. package/dist/renderers/archiveShared.js +0 -71
  33. package/dist/renderers/audio.d.ts +0 -8
  34. package/dist/renderers/audio.js +0 -219
  35. package/dist/renderers/cad.d.ts +0 -2
  36. package/dist/renderers/cad.js +0 -446
  37. package/dist/renderers/code.d.ts +0 -11
  38. package/dist/renderers/code.js +0 -233
  39. package/dist/renderers/data.d.ts +0 -7
  40. package/dist/renderers/data.js +0 -370
  41. package/dist/renderers/drawing.d.ts +0 -10
  42. package/dist/renderers/drawing.js +0 -882
  43. package/dist/renderers/eda.d.ts +0 -2
  44. package/dist/renderers/eda.js +0 -434
  45. package/dist/renderers/edaParser.d.ts +0 -77
  46. package/dist/renderers/edaParser.js +0 -569
  47. package/dist/renderers/email.d.ts +0 -2
  48. package/dist/renderers/email.js +0 -463
  49. package/dist/renderers/epub.d.ts +0 -2
  50. package/dist/renderers/epub.js +0 -331
  51. package/dist/renderers/geo.d.ts +0 -2
  52. package/dist/renderers/geo.js +0 -284
  53. package/dist/renderers/markdown.d.ts +0 -2
  54. package/dist/renderers/markdown.js +0 -83
  55. package/dist/renderers/model.d.ts +0 -2
  56. package/dist/renderers/model.js +0 -567
  57. package/dist/renderers/ofd.d.ts +0 -2
  58. package/dist/renderers/ofd.js +0 -256
  59. package/dist/renderers/openDocument.d.ts +0 -2
  60. package/dist/renderers/openDocument.js +0 -122
  61. package/dist/renderers/pdf.d.ts +0 -3
  62. package/dist/renderers/pdf.js +0 -1001
  63. package/dist/renderers/pdfStyles.d.ts +0 -1
  64. package/dist/renderers/pdfStyles.js +0 -1
  65. package/dist/renderers/pptx.d.ts +0 -2
  66. package/dist/renderers/pptx.js +0 -217
  67. package/dist/renderers/spreadsheet/state.d.ts +0 -80
  68. package/dist/renderers/spreadsheet/state.js +0 -96
  69. package/dist/renderers/spreadsheet/view.d.ts +0 -25
  70. package/dist/renderers/spreadsheet/view.js +0 -833
  71. package/dist/renderers/spreadsheet/worker/index.d.ts +0 -2
  72. package/dist/renderers/spreadsheet/worker/index.js +0 -1
  73. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.d.ts +0 -73
  74. package/dist/renderers/spreadsheet/worker/sheetjs/SheetJsModel.js +0 -623
  75. package/dist/renderers/spreadsheet/worker/sheetjs/color.d.ts +0 -2
  76. package/dist/renderers/spreadsheet/worker/sheetjs/color.js +0 -73
  77. package/dist/renderers/spreadsheet/worker/sheetjs/index.d.ts +0 -1
  78. package/dist/renderers/spreadsheet/worker/sheetjs/index.js +0 -1
  79. package/dist/renderers/spreadsheet/worker/sheetjs/parser.d.ts +0 -18
  80. package/dist/renderers/spreadsheet/worker/sheetjs/parser.js +0 -106
  81. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.d.ts +0 -1
  82. package/dist/renderers/spreadsheet/worker/sheetjs/sheet.worker.js +0 -11
  83. package/dist/renderers/spreadsheet/worker/type.d.ts +0 -57
  84. package/dist/renderers/spreadsheet/worker/type.js +0 -1
  85. package/dist/renderers/spreadsheet.d.ts +0 -3
  86. package/dist/renderers/spreadsheet.js +0 -929
  87. package/dist/renderers/typst.d.ts +0 -8
  88. package/dist/renderers/typst.js +0 -547
  89. package/dist/renderers/umd/parser.d.ts +0 -30
  90. package/dist/renderers/umd/parser.js +0 -408
  91. package/dist/renderers/umd.d.ts +0 -2
  92. package/dist/renderers/umd.js +0 -297
  93. package/dist/renderers/video.d.ts +0 -8
  94. package/dist/renderers/video.js +0 -108
  95. package/dist/renderers/wordDoc.d.ts +0 -5
  96. package/dist/renderers/wordDoc.js +0 -284
  97. package/dist/renderers/wordDocx.d.ts +0 -5
  98. package/dist/renderers/wordDocx.js +0 -985
  99. package/dist/renderers/wordDocx.worker.d.ts +0 -1
  100. package/dist/renderers/wordDocx.worker.js +0 -96
  101. package/vendor/ofd/dltech/jbig2/arithmetic_decoder.js +0 -183
  102. package/vendor/ofd/dltech/jbig2/ccitt.js +0 -1070
  103. package/vendor/ofd/dltech/jbig2/compatibility.js +0 -12
  104. package/vendor/ofd/dltech/jbig2/core_utils.js +0 -180
  105. package/vendor/ofd/dltech/jbig2/is_node.js +0 -27
  106. package/vendor/ofd/dltech/jbig2/jbig2.js +0 -2589
  107. package/vendor/ofd/dltech/jbig2/jbig2_stream.js +0 -81
  108. package/vendor/ofd/dltech/jbig2/primitives.js +0 -387
  109. package/vendor/ofd/dltech/jbig2/stream.js +0 -1348
  110. package/vendor/ofd/dltech/jbig2/util.js +0 -972
  111. package/vendor/ofd/dltech/ofd/ofd.d.ts +0 -11
  112. package/vendor/ofd/dltech/ofd/ofd.js +0 -100
  113. package/vendor/ofd/dltech/ofd/ofd_parser.js +0 -395
  114. package/vendor/ofd/dltech/ofd/ofd_render.js +0 -473
  115. package/vendor/ofd/dltech/ofd/ofd_util.js +0 -350
  116. 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;