@file-viewer/core 2.0.5 → 2.0.7
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/dist/contracts/types.d.ts +1 -0
- package/dist/platform/assets.d.ts +8 -6
- package/dist/platform/assets.js +23 -25
- package/dist/renderers/cad.js +1 -0
- package/dist/renderers/data.js +1 -1
- package/dist/renderers/drawing.js +274 -3
- package/dist/renderers/epub.js +1 -0
- package/dist/renderers/model.js +1 -0
- package/dist/renderers/ofd.js +1 -0
- package/dist/renderers/pdf.js +6 -1
- package/dist/renderers/typst.js +82 -11
- package/dist/renderers/umd.js +1 -1
- package/package.json +2 -2
|
@@ -107,6 +107,7 @@ export type FileViewerRenderedInstance = {
|
|
|
107
107
|
export interface FileViewerTypstOptions {
|
|
108
108
|
compilerWasmUrl?: string;
|
|
109
109
|
rendererWasmUrl?: string;
|
|
110
|
+
renderTimeoutMs?: number;
|
|
110
111
|
}
|
|
111
112
|
export interface FileViewerDataOptions {
|
|
112
113
|
sqlWasmUrl?: string;
|
|
@@ -6,10 +6,12 @@ export declare const DEFAULT_FILE_VIEWER_SPREADSHEET_WORKER_PATH = "vendor/xlsx/
|
|
|
6
6
|
export declare const DEFAULT_FILE_VIEWER_CAD_WASM_PATH = "wasm/cad/";
|
|
7
7
|
export declare const DEFAULT_FILE_VIEWER_CAD_WORKER_PATH = "wasm/cad/dwg-worker.js";
|
|
8
8
|
export declare const DEFAULT_FILE_VIEWER_CAD_DWF_WASM_PATH = "wasm/cad/dwfv-render.wasm";
|
|
9
|
-
export declare const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL = "
|
|
10
|
-
export declare const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = "
|
|
9
|
+
export declare const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL = "wasm/typst/typst_ts_web_compiler_bg.wasm";
|
|
10
|
+
export declare const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = "wasm/typst/typst_ts_renderer_bg.wasm";
|
|
11
|
+
export declare const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_PACKAGE_PATH = "@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm";
|
|
11
12
|
export declare const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_PACKAGE_PATH = "@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm";
|
|
12
|
-
export declare const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL = "
|
|
13
|
+
export declare const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL = "wasm/data/sql-wasm.wasm";
|
|
14
|
+
export declare const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_PACKAGE_PATH = "sql.js/dist/sql-wasm.wasm";
|
|
13
15
|
export interface ResolveFileViewerAssetUrlOptions {
|
|
14
16
|
baseUrl?: string;
|
|
15
17
|
documentBaseUrl?: string;
|
|
@@ -54,9 +56,9 @@ export declare const resolveFileViewerArchiveWasmUrl: (options?: Pick<FileViewer
|
|
|
54
56
|
export declare const resolveFileViewerCadAssetUrls: (options?: Pick<FileViewerCadOptions, "wasmPath" | "workerUrl" | "dwfWasmUrl"> | null, documentBaseUrl?: string) => ResolvedFileViewerCadAssetUrls;
|
|
55
57
|
export declare const resolveFileViewerDocxWorkerUrl: (options?: Pick<FileViewerDocxOptions, "workerUrl"> | null, documentBaseUrl?: string) => string;
|
|
56
58
|
export declare const resolveFileViewerSpreadsheetWorkerUrl: (options?: Pick<FileViewerSpreadsheetOptions, "workerUrl"> | null, documentBaseUrl?: string) => string;
|
|
57
|
-
export declare const resolveFileViewerTypstCompilerWasmUrl: (options?: Pick<FileViewerTypstOptions, "compilerWasmUrl"> | null, overrides?: Array<string | undefined
|
|
58
|
-
export declare const resolveFileViewerTypstRendererWasmUrl: (options?: Pick<FileViewerTypstOptions, "rendererWasmUrl"> | null, overrides?: Array<string | undefined
|
|
59
|
-
export declare const resolveFileViewerDataSqlWasmUrl: (options?: Pick<FileViewerDataOptions, "sqlWasmUrl"> | null, overrides?: Array<string | undefined
|
|
59
|
+
export declare const resolveFileViewerTypstCompilerWasmUrl: (options?: Pick<FileViewerTypstOptions, "compilerWasmUrl"> | null, overrides?: Array<string | undefined>, documentBaseUrl?: string) => string;
|
|
60
|
+
export declare const resolveFileViewerTypstRendererWasmUrl: (options?: Pick<FileViewerTypstOptions, "rendererWasmUrl"> | null, overrides?: Array<string | undefined>, documentBaseUrl?: string) => string;
|
|
61
|
+
export declare const resolveFileViewerDataSqlWasmUrl: (options?: Pick<FileViewerDataOptions, "sqlWasmUrl"> | null, overrides?: Array<string | undefined>, documentBaseUrl?: string) => string;
|
|
60
62
|
export declare const listFileViewerRendererAssetManifests: () => FileViewerRendererAssetManifest[];
|
|
61
63
|
export declare const getFileViewerRendererAssetManifest: (rendererId: string) => FileViewerRendererAssetManifest | null;
|
|
62
64
|
export declare const resolveFileViewerRendererAssets: (rendererId: string, resolveOptions?: ResolveFileViewerRendererAssetsOptions) => ResolvedFileViewerRendererAsset[];
|
package/dist/platform/assets.js
CHANGED
|
@@ -5,10 +5,12 @@ export const DEFAULT_FILE_VIEWER_SPREADSHEET_WORKER_PATH = 'vendor/xlsx/sheet.wo
|
|
|
5
5
|
export const DEFAULT_FILE_VIEWER_CAD_WASM_PATH = 'wasm/cad/';
|
|
6
6
|
export const DEFAULT_FILE_VIEWER_CAD_WORKER_PATH = 'wasm/cad/dwg-worker.js';
|
|
7
7
|
export const DEFAULT_FILE_VIEWER_CAD_DWF_WASM_PATH = 'wasm/cad/dwfv-render.wasm';
|
|
8
|
-
export const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL = '
|
|
9
|
-
export const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = '
|
|
8
|
+
export const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL = 'wasm/typst/typst_ts_web_compiler_bg.wasm';
|
|
9
|
+
export const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = 'wasm/typst/typst_ts_renderer_bg.wasm';
|
|
10
|
+
export const DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_PACKAGE_PATH = '@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm';
|
|
10
11
|
export const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_PACKAGE_PATH = '@myriaddreamin/typst-ts-renderer/pkg/typst_ts_renderer_bg.wasm';
|
|
11
|
-
export const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL = '
|
|
12
|
+
export const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL = 'wasm/data/sql-wasm.wasm';
|
|
13
|
+
export const DEFAULT_FILE_VIEWER_DATA_SQL_WASM_PACKAGE_PATH = 'sql.js/dist/sql-wasm.wasm';
|
|
12
14
|
export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
|
|
13
15
|
{
|
|
14
16
|
rendererId: 'archive',
|
|
@@ -107,22 +109,23 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
|
|
|
107
109
|
id: 'typst-compiler-wasm',
|
|
108
110
|
rendererId: 'typst',
|
|
109
111
|
kind: 'wasm',
|
|
110
|
-
target: '
|
|
112
|
+
target: 'public',
|
|
111
113
|
required: true,
|
|
112
|
-
|
|
114
|
+
defaultPath: DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL,
|
|
115
|
+
packagePath: DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_PACKAGE_PATH,
|
|
113
116
|
optionPath: 'typst.compilerWasmUrl',
|
|
114
|
-
description: 'Typst compiler WebAssembly module
|
|
117
|
+
description: 'Typst compiler WebAssembly module copied to the public assets directory.',
|
|
115
118
|
},
|
|
116
119
|
{
|
|
117
120
|
id: 'typst-renderer-wasm',
|
|
118
121
|
rendererId: 'typst',
|
|
119
|
-
kind: '
|
|
120
|
-
target: '
|
|
122
|
+
kind: 'wasm',
|
|
123
|
+
target: 'public',
|
|
121
124
|
required: true,
|
|
122
|
-
|
|
125
|
+
defaultPath: DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL,
|
|
123
126
|
packagePath: DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_PACKAGE_PATH,
|
|
124
127
|
optionPath: 'typst.rendererWasmUrl',
|
|
125
|
-
description: 'Typst SVG renderer WebAssembly module
|
|
128
|
+
description: 'Typst SVG renderer WebAssembly module copied to the public assets directory.',
|
|
126
129
|
},
|
|
127
130
|
],
|
|
128
131
|
},
|
|
@@ -133,11 +136,12 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
|
|
|
133
136
|
id: 'data-sql-wasm',
|
|
134
137
|
rendererId: 'data-asset',
|
|
135
138
|
kind: 'wasm',
|
|
136
|
-
target: '
|
|
139
|
+
target: 'public',
|
|
137
140
|
required: false,
|
|
138
|
-
|
|
141
|
+
defaultPath: DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL,
|
|
142
|
+
packagePath: DEFAULT_FILE_VIEWER_DATA_SQL_WASM_PACKAGE_PATH,
|
|
139
143
|
optionPath: 'data.sqlWasmUrl',
|
|
140
|
-
description: 'sql.js WebAssembly module
|
|
144
|
+
description: 'sql.js WebAssembly module copied to the public assets directory for SQLite previews.',
|
|
141
145
|
},
|
|
142
146
|
],
|
|
143
147
|
},
|
|
@@ -188,20 +192,14 @@ export const resolveFileViewerSpreadsheetWorkerUrl = (options, documentBaseUrl)
|
|
|
188
192
|
documentBaseUrl,
|
|
189
193
|
});
|
|
190
194
|
};
|
|
191
|
-
export const resolveFileViewerTypstCompilerWasmUrl = (options, overrides = []) => {
|
|
192
|
-
return (options === null || options === void 0 ? void 0 : options.compilerWasmUrl) ||
|
|
193
|
-
overrides.find(Boolean) ||
|
|
194
|
-
DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL;
|
|
195
|
+
export const resolveFileViewerTypstCompilerWasmUrl = (options, overrides = [], documentBaseUrl) => {
|
|
196
|
+
return resolveFileViewerAssetUrl((options === null || options === void 0 ? void 0 : options.compilerWasmUrl) || overrides.find(Boolean), DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL, { documentBaseUrl });
|
|
195
197
|
};
|
|
196
|
-
export const resolveFileViewerTypstRendererWasmUrl = (options, overrides = []) => {
|
|
197
|
-
return (options === null || options === void 0 ? void 0 : options.rendererWasmUrl) ||
|
|
198
|
-
overrides.find(Boolean) ||
|
|
199
|
-
DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL;
|
|
198
|
+
export const resolveFileViewerTypstRendererWasmUrl = (options, overrides = [], documentBaseUrl) => {
|
|
199
|
+
return resolveFileViewerAssetUrl((options === null || options === void 0 ? void 0 : options.rendererWasmUrl) || overrides.find(Boolean), DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL, { documentBaseUrl });
|
|
200
200
|
};
|
|
201
|
-
export const resolveFileViewerDataSqlWasmUrl = (options, overrides = []) => {
|
|
202
|
-
return (options === null || options === void 0 ? void 0 : options.sqlWasmUrl) ||
|
|
203
|
-
overrides.find(Boolean) ||
|
|
204
|
-
DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL;
|
|
201
|
+
export const resolveFileViewerDataSqlWasmUrl = (options, overrides = [], documentBaseUrl) => {
|
|
202
|
+
return resolveFileViewerAssetUrl((options === null || options === void 0 ? void 0 : options.sqlWasmUrl) || overrides.find(Boolean), DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL, { documentBaseUrl });
|
|
205
203
|
};
|
|
206
204
|
export const listFileViewerRendererAssetManifests = () => {
|
|
207
205
|
return [...DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS];
|
package/dist/renderers/cad.js
CHANGED
|
@@ -68,6 +68,7 @@ const cadStyle = `
|
|
|
68
68
|
.cad-native-stage .dwfv-root,.cad-native-stage .dwfv-workspace,.cad-native-stage .dwfv-stage{width:100%;min-width:0;min-height:0}
|
|
69
69
|
.cad-native-stage .dwfv-root{height:100%}
|
|
70
70
|
.cad-state{position:absolute;inset:50% auto auto 50%;max-width:min(520px,calc(100% - 48px));transform:translate(-50%,-50%);border-radius:12px;padding:14px 18px;background:rgba(255,255,255,.92);box-shadow:0 14px 38px rgba(15,23,42,.12);color:#53637a;font-size:13px;font-weight:800;text-align:center}
|
|
71
|
+
.cad-state[hidden]{display:none!important}
|
|
71
72
|
.cad-state.error{color:#b42318}
|
|
72
73
|
.cad-inspector strong{display:block;margin-bottom:12px;color:#1f2a3d;font-size:13px}
|
|
73
74
|
.cad-inspector dl{display:grid;gap:8px;margin:0}
|
package/dist/renderers/data.js
CHANGED
|
@@ -144,7 +144,7 @@ const renderSqlite = async (documentRef, buffer, context) => {
|
|
|
144
144
|
const { default: initSqlJs } = await import('sql.js');
|
|
145
145
|
const sqlWasmUrl = resolveFileViewerDataSqlWasmUrl((_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.data, [
|
|
146
146
|
getWindowSqlWasmOverride(documentRef),
|
|
147
|
-
]);
|
|
147
|
+
], documentRef.baseURI);
|
|
148
148
|
const SQL = await initSqlJs({ locateFile: () => sqlWasmUrl });
|
|
149
149
|
const db = new SQL.Database(new Uint8Array(buffer));
|
|
150
150
|
try {
|
|
@@ -5,6 +5,7 @@ import { readFileViewerText } from '../source/index.js';
|
|
|
5
5
|
const DIAGRAMS_VIEWER_URL = 'https://viewer.diagrams.net/js/viewer-static.min.js';
|
|
6
6
|
const SVG_NS = 'http://www.w3.org/2000/svg';
|
|
7
7
|
const EXCALIDRAW_OFFICIAL_TIMEOUT = 6000;
|
|
8
|
+
const DRAWIO_OFFICIAL_TIMEOUT = 6000;
|
|
8
9
|
const diagramsViewerPromises = new WeakMap();
|
|
9
10
|
const drawingStyle = `
|
|
10
11
|
.drawing-viewer{display:flex;height:100%;min-height:360px;flex-direction:column;background:#edf2f7;color:#172033}
|
|
@@ -22,6 +23,7 @@ const drawingStyle = `
|
|
|
22
23
|
.drawing-canvas .drawing-svg,.drawing-canvas svg{display:block;max-width:100%;height:auto;margin:0 auto;border-radius:10px;background:#fff;box-shadow:0 18px 42px rgba(15,23,42,.12)}
|
|
23
24
|
.drawing-canvas .drawing-mxgraph{min-height:420px;overflow:hidden;border-radius:10px;background:#fff;box-shadow:0 18px 42px rgba(15,23,42,.12)}
|
|
24
25
|
.drawing-state{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;padding:24px;color:#64748b;font-size:14px;font-weight:700;text-align:center}
|
|
26
|
+
.drawing-state[hidden]{display:none!important}
|
|
25
27
|
.drawing-state.error{color:#b42318}
|
|
26
28
|
@media (max-width:720px){.drawing-toolbar{align-items:flex-start;flex-direction:column}.drawing-actions{width:100%;justify-content:space-between}.drawing-scroll{padding:12px}}
|
|
27
29
|
`;
|
|
@@ -120,7 +122,8 @@ const suppressExcalidrawWorkerWarning = () => {
|
|
|
120
122
|
const originalError = console.error;
|
|
121
123
|
const patchedError = (...args) => {
|
|
122
124
|
const message = args.map(arg => String(arg)).join(' ');
|
|
123
|
-
if (message.includes('Failed to use workers for subsetting')
|
|
125
|
+
if (message.includes('Failed to use workers for subsetting') ||
|
|
126
|
+
message.includes('Failed to fetch font family')) {
|
|
124
127
|
return;
|
|
125
128
|
}
|
|
126
129
|
originalError(...args);
|
|
@@ -361,7 +364,7 @@ const renderOfficialExcalidraw = async (payload, elements, target) => {
|
|
|
361
364
|
}
|
|
362
365
|
finally {
|
|
363
366
|
clearTimeout(restoreTimer);
|
|
364
|
-
restoreConsole
|
|
367
|
+
setTimeout(restoreConsole, 3000);
|
|
365
368
|
}
|
|
366
369
|
};
|
|
367
370
|
const renderExcalidraw = async (documentRef, text, target) => {
|
|
@@ -380,7 +383,262 @@ const renderExcalidraw = async (documentRef, text, target) => {
|
|
|
380
383
|
await renderRoughFallback(documentRef, payload, elements, target);
|
|
381
384
|
}
|
|
382
385
|
};
|
|
383
|
-
const
|
|
386
|
+
const getDirectChild = (parent, tagName) => {
|
|
387
|
+
return Array.from(parent.children).find(child => child.localName === tagName) || null;
|
|
388
|
+
};
|
|
389
|
+
const parseDrawioStyle = (style) => {
|
|
390
|
+
const entries = new Map();
|
|
391
|
+
for (const item of (style || '').split(';')) {
|
|
392
|
+
if (!item) {
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
const [key, ...rest] = item.split('=');
|
|
396
|
+
entries.set(key, rest.join('=') || '1');
|
|
397
|
+
}
|
|
398
|
+
return entries;
|
|
399
|
+
};
|
|
400
|
+
const getDrawioStyleValue = (style, key, fallback) => {
|
|
401
|
+
const value = style.get(key);
|
|
402
|
+
return value && value !== 'none' ? value : fallback;
|
|
403
|
+
};
|
|
404
|
+
const parseDrawioGeometry = (cell) => {
|
|
405
|
+
const geometry = getDirectChild(cell, 'mxGeometry');
|
|
406
|
+
if (!geometry) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
return {
|
|
410
|
+
x: toNumber(geometry.getAttribute('x')),
|
|
411
|
+
y: toNumber(geometry.getAttribute('y')),
|
|
412
|
+
width: Math.max(1, toNumber(geometry.getAttribute('width'), 80)),
|
|
413
|
+
height: Math.max(1, toNumber(geometry.getAttribute('height'), 40)),
|
|
414
|
+
points: Array.from(geometry.querySelectorAll('mxPoint')).map(point => ({
|
|
415
|
+
x: toNumber(point.getAttribute('x')),
|
|
416
|
+
y: toNumber(point.getAttribute('y')),
|
|
417
|
+
})),
|
|
418
|
+
};
|
|
419
|
+
};
|
|
420
|
+
const normalizeDrawioText = (documentRef, value) => {
|
|
421
|
+
if (!value) {
|
|
422
|
+
return '';
|
|
423
|
+
}
|
|
424
|
+
const helper = documentRef.createElement('textarea');
|
|
425
|
+
helper.innerHTML = value;
|
|
426
|
+
return helper.value
|
|
427
|
+
.replace(/<br\s*\/?>/gi, '\n')
|
|
428
|
+
.replace(/<[^>]+>/g, '')
|
|
429
|
+
.replace(/\u00a0/g, ' ')
|
|
430
|
+
.replace(/[ \t]+/g, ' ')
|
|
431
|
+
.trim();
|
|
432
|
+
};
|
|
433
|
+
const appendDrawioWrappedText = (documentRef, svg, text, x, y, width, height, fontSize, fill) => {
|
|
434
|
+
if (!text) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
const textNode = createSvgElement(documentRef, 'text');
|
|
438
|
+
const maxChars = Math.max(4, Math.floor(width / Math.max(7, fontSize * 0.55)));
|
|
439
|
+
const words = text.includes(' ') ? text.split(/\s+/) : text.match(new RegExp(`.{1,${maxChars}}`, 'g')) || [text];
|
|
440
|
+
const lines = [];
|
|
441
|
+
let current = '';
|
|
442
|
+
for (const word of words) {
|
|
443
|
+
const next = current ? `${current} ${word}` : word;
|
|
444
|
+
if (next.length > maxChars && current) {
|
|
445
|
+
lines.push(current);
|
|
446
|
+
current = word;
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
current = next;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (current) {
|
|
453
|
+
lines.push(current);
|
|
454
|
+
}
|
|
455
|
+
const lineHeight = fontSize * 1.24;
|
|
456
|
+
const totalHeight = lineHeight * lines.length;
|
|
457
|
+
textNode.setAttribute('x', String(x + width / 2));
|
|
458
|
+
textNode.setAttribute('y', String(y + height / 2 - totalHeight / 2 + fontSize));
|
|
459
|
+
textNode.setAttribute('fill', fill);
|
|
460
|
+
textNode.setAttribute('font-size', String(fontSize));
|
|
461
|
+
textNode.setAttribute('font-family', 'Inter, Segoe UI, Arial, sans-serif');
|
|
462
|
+
textNode.setAttribute('font-weight', '600');
|
|
463
|
+
textNode.setAttribute('text-anchor', 'middle');
|
|
464
|
+
textNode.setAttribute('pointer-events', 'none');
|
|
465
|
+
lines.slice(0, 5).forEach((line, index) => {
|
|
466
|
+
const lineNode = createSvgElement(documentRef, 'tspan');
|
|
467
|
+
lineNode.setAttribute('x', String(x + width / 2));
|
|
468
|
+
lineNode.setAttribute('dy', index === 0 ? '0' : String(lineHeight));
|
|
469
|
+
lineNode.textContent = line;
|
|
470
|
+
textNode.appendChild(lineNode);
|
|
471
|
+
});
|
|
472
|
+
svg.appendChild(textNode);
|
|
473
|
+
};
|
|
474
|
+
const renderDrawioFallback = (documentRef, text, target) => {
|
|
475
|
+
var _a;
|
|
476
|
+
const parser = new DOMParser();
|
|
477
|
+
const parsed = parser.parseFromString(text, 'text/xml');
|
|
478
|
+
const parseError = parsed.querySelector('parsererror');
|
|
479
|
+
if (parseError) {
|
|
480
|
+
throw new Error(`Draw.io XML 解析失败:${parseError.textContent || 'invalid xml'}`);
|
|
481
|
+
}
|
|
482
|
+
const firstDiagram = parsed.querySelector('diagram');
|
|
483
|
+
const graphModel = (firstDiagram === null || firstDiagram === void 0 ? void 0 : firstDiagram.querySelector('mxGraphModel')) || parsed.querySelector('mxGraphModel');
|
|
484
|
+
if (!graphModel) {
|
|
485
|
+
throw new Error('当前 Draw.io 文件没有可直接渲染的 mxGraphModel。');
|
|
486
|
+
}
|
|
487
|
+
const cells = Array.from(graphModel.querySelectorAll('mxCell'));
|
|
488
|
+
const vertices = cells
|
|
489
|
+
.filter(cell => cell.getAttribute('vertex') === '1' && cell.getAttribute('connectable') !== '0')
|
|
490
|
+
.map(cell => ({
|
|
491
|
+
cell,
|
|
492
|
+
id: cell.getAttribute('id') || '',
|
|
493
|
+
geometry: parseDrawioGeometry(cell),
|
|
494
|
+
style: parseDrawioStyle(cell.getAttribute('style')),
|
|
495
|
+
text: normalizeDrawioText(documentRef, cell.getAttribute('value')),
|
|
496
|
+
}))
|
|
497
|
+
.filter(item => item.id && item.geometry);
|
|
498
|
+
if (!vertices.length) {
|
|
499
|
+
throw new Error('当前 Draw.io 文件没有可预览图元。');
|
|
500
|
+
}
|
|
501
|
+
const vertexById = new Map(vertices.map(vertex => [vertex.id, vertex]));
|
|
502
|
+
const allX = vertices.flatMap(vertex => [vertex.geometry.x, vertex.geometry.x + vertex.geometry.width]);
|
|
503
|
+
const allY = vertices.flatMap(vertex => [vertex.geometry.y, vertex.geometry.y + vertex.geometry.height]);
|
|
504
|
+
const edgePoints = [];
|
|
505
|
+
const edges = cells.filter(cell => cell.getAttribute('edge') === '1');
|
|
506
|
+
for (const edge of edges) {
|
|
507
|
+
const source = vertexById.get(edge.getAttribute('source') || '');
|
|
508
|
+
const targetVertex = vertexById.get(edge.getAttribute('target') || '');
|
|
509
|
+
const geometry = parseDrawioGeometry(edge);
|
|
510
|
+
if (source === null || source === void 0 ? void 0 : source.geometry) {
|
|
511
|
+
edgePoints.push({
|
|
512
|
+
x: source.geometry.x + source.geometry.width / 2,
|
|
513
|
+
y: source.geometry.y + source.geometry.height / 2,
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
geometry === null || geometry === void 0 ? void 0 : geometry.points.forEach(point => edgePoints.push(point));
|
|
517
|
+
if (targetVertex === null || targetVertex === void 0 ? void 0 : targetVertex.geometry) {
|
|
518
|
+
edgePoints.push({
|
|
519
|
+
x: targetVertex.geometry.x + targetVertex.geometry.width / 2,
|
|
520
|
+
y: targetVertex.geometry.y + targetVertex.geometry.height / 2,
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
allX.push(...edgePoints.map(point => point.x));
|
|
525
|
+
allY.push(...edgePoints.map(point => point.y));
|
|
526
|
+
const padding = 96;
|
|
527
|
+
const minX = Math.min(...allX) - padding;
|
|
528
|
+
const minY = Math.min(...allY) - padding;
|
|
529
|
+
const width = Math.max(480, Math.max(...allX) - Math.min(...allX) + padding * 2);
|
|
530
|
+
const height = Math.max(320, Math.max(...allY) - Math.min(...allY) + padding * 2);
|
|
531
|
+
const svg = createSvgElement(documentRef, 'svg');
|
|
532
|
+
svg.setAttribute('viewBox', `${minX} ${minY} ${width} ${height}`);
|
|
533
|
+
svg.setAttribute('width', String(Math.ceil(width)));
|
|
534
|
+
svg.setAttribute('height', String(Math.ceil(height)));
|
|
535
|
+
svg.setAttribute('role', 'img');
|
|
536
|
+
svg.setAttribute('aria-label', (firstDiagram === null || firstDiagram === void 0 ? void 0 : firstDiagram.getAttribute('name')) || 'Draw.io local SVG preview');
|
|
537
|
+
const defs = createSvgElement(documentRef, 'defs');
|
|
538
|
+
const marker = createSvgElement(documentRef, 'marker');
|
|
539
|
+
marker.setAttribute('id', 'drawio-arrow');
|
|
540
|
+
marker.setAttribute('viewBox', '0 0 10 10');
|
|
541
|
+
marker.setAttribute('refX', '9');
|
|
542
|
+
marker.setAttribute('refY', '5');
|
|
543
|
+
marker.setAttribute('markerWidth', '7');
|
|
544
|
+
marker.setAttribute('markerHeight', '7');
|
|
545
|
+
marker.setAttribute('orient', 'auto-start-reverse');
|
|
546
|
+
const arrow = createSvgElement(documentRef, 'path');
|
|
547
|
+
arrow.setAttribute('d', 'M 0 0 L 10 5 L 0 10 z');
|
|
548
|
+
arrow.setAttribute('fill', '#64748b');
|
|
549
|
+
marker.appendChild(arrow);
|
|
550
|
+
defs.appendChild(marker);
|
|
551
|
+
svg.appendChild(defs);
|
|
552
|
+
const background = createSvgElement(documentRef, 'rect');
|
|
553
|
+
background.setAttribute('x', String(minX));
|
|
554
|
+
background.setAttribute('y', String(minY));
|
|
555
|
+
background.setAttribute('width', String(width));
|
|
556
|
+
background.setAttribute('height', String(height));
|
|
557
|
+
background.setAttribute('fill', '#ffffff');
|
|
558
|
+
svg.appendChild(background);
|
|
559
|
+
for (const edge of edges) {
|
|
560
|
+
const source = vertexById.get(edge.getAttribute('source') || '');
|
|
561
|
+
const targetVertex = vertexById.get(edge.getAttribute('target') || '');
|
|
562
|
+
if (!(source === null || source === void 0 ? void 0 : source.geometry) || !(targetVertex === null || targetVertex === void 0 ? void 0 : targetVertex.geometry)) {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
const style = parseDrawioStyle(edge.getAttribute('style'));
|
|
566
|
+
const stroke = getDrawioStyleValue(style, 'strokeColor', '#64748b');
|
|
567
|
+
const points = [
|
|
568
|
+
{
|
|
569
|
+
x: source.geometry.x + source.geometry.width / 2,
|
|
570
|
+
y: source.geometry.y + source.geometry.height / 2,
|
|
571
|
+
},
|
|
572
|
+
...(((_a = parseDrawioGeometry(edge)) === null || _a === void 0 ? void 0 : _a.points) || []),
|
|
573
|
+
{
|
|
574
|
+
x: targetVertex.geometry.x + targetVertex.geometry.width / 2,
|
|
575
|
+
y: targetVertex.geometry.y + targetVertex.geometry.height / 2,
|
|
576
|
+
},
|
|
577
|
+
];
|
|
578
|
+
const polyline = createSvgElement(documentRef, 'polyline');
|
|
579
|
+
polyline.setAttribute('points', points.map(point => `${point.x},${point.y}`).join(' '));
|
|
580
|
+
polyline.setAttribute('fill', 'none');
|
|
581
|
+
polyline.setAttribute('stroke', stroke);
|
|
582
|
+
polyline.setAttribute('stroke-width', '2');
|
|
583
|
+
if (style.get('dashed') === '1') {
|
|
584
|
+
polyline.setAttribute('stroke-dasharray', '8 7');
|
|
585
|
+
}
|
|
586
|
+
if (style.get('endArrow') !== 'none') {
|
|
587
|
+
polyline.setAttribute('marker-end', 'url(#drawio-arrow)');
|
|
588
|
+
}
|
|
589
|
+
svg.appendChild(polyline);
|
|
590
|
+
}
|
|
591
|
+
for (const vertex of vertices) {
|
|
592
|
+
const geometry = vertex.geometry;
|
|
593
|
+
const fill = getDrawioStyleValue(vertex.style, 'fillColor', '#f8fafc');
|
|
594
|
+
const stroke = getDrawioStyleValue(vertex.style, 'strokeColor', '#64748b');
|
|
595
|
+
const fontSize = Math.max(10, toNumber(vertex.style.get('fontSize'), 14));
|
|
596
|
+
const shape = vertex.style.has('ellipse')
|
|
597
|
+
? 'ellipse'
|
|
598
|
+
: vertex.style.get('shape') === 'rhombus'
|
|
599
|
+
? 'diamond'
|
|
600
|
+
: 'rect';
|
|
601
|
+
if (shape === 'ellipse') {
|
|
602
|
+
const ellipse = createSvgElement(documentRef, 'ellipse');
|
|
603
|
+
ellipse.setAttribute('cx', String(geometry.x + geometry.width / 2));
|
|
604
|
+
ellipse.setAttribute('cy', String(geometry.y + geometry.height / 2));
|
|
605
|
+
ellipse.setAttribute('rx', String(geometry.width / 2));
|
|
606
|
+
ellipse.setAttribute('ry', String(geometry.height / 2));
|
|
607
|
+
ellipse.setAttribute('fill', fill);
|
|
608
|
+
ellipse.setAttribute('stroke', stroke);
|
|
609
|
+
ellipse.setAttribute('stroke-width', '2');
|
|
610
|
+
svg.appendChild(ellipse);
|
|
611
|
+
}
|
|
612
|
+
else if (shape === 'diamond') {
|
|
613
|
+
const diamond = createSvgElement(documentRef, 'polygon');
|
|
614
|
+
diamond.setAttribute('points', [
|
|
615
|
+
`${geometry.x + geometry.width / 2},${geometry.y}`,
|
|
616
|
+
`${geometry.x + geometry.width},${geometry.y + geometry.height / 2}`,
|
|
617
|
+
`${geometry.x + geometry.width / 2},${geometry.y + geometry.height}`,
|
|
618
|
+
`${geometry.x},${geometry.y + geometry.height / 2}`,
|
|
619
|
+
].join(' '));
|
|
620
|
+
diamond.setAttribute('fill', fill);
|
|
621
|
+
diamond.setAttribute('stroke', stroke);
|
|
622
|
+
diamond.setAttribute('stroke-width', '2');
|
|
623
|
+
svg.appendChild(diamond);
|
|
624
|
+
}
|
|
625
|
+
else {
|
|
626
|
+
const rect = createSvgElement(documentRef, 'rect');
|
|
627
|
+
rect.setAttribute('x', String(geometry.x));
|
|
628
|
+
rect.setAttribute('y', String(geometry.y));
|
|
629
|
+
rect.setAttribute('width', String(geometry.width));
|
|
630
|
+
rect.setAttribute('height', String(geometry.height));
|
|
631
|
+
rect.setAttribute('rx', vertex.style.get('rounded') === '1' ? '10' : '2');
|
|
632
|
+
rect.setAttribute('fill', fill);
|
|
633
|
+
rect.setAttribute('stroke', stroke);
|
|
634
|
+
rect.setAttribute('stroke-width', '2');
|
|
635
|
+
svg.appendChild(rect);
|
|
636
|
+
}
|
|
637
|
+
appendDrawioWrappedText(documentRef, svg, vertex.text, geometry.x, geometry.y, geometry.width, geometry.height, fontSize, getDrawioStyleValue(vertex.style, 'fontColor', '#172033'));
|
|
638
|
+
}
|
|
639
|
+
appendRenderedSvg(target, svg, 'rough');
|
|
640
|
+
};
|
|
641
|
+
const renderOfficialDrawio = async (documentRef, text, target) => {
|
|
384
642
|
const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
|
|
385
643
|
await loadDiagramsViewer(documentRef);
|
|
386
644
|
await waitForFileViewerNextPaint(ownerWindow);
|
|
@@ -403,6 +661,19 @@ const renderDrawio = async (documentRef, text, target) => {
|
|
|
403
661
|
throw new Error('diagrams.net viewer 未正确初始化');
|
|
404
662
|
}
|
|
405
663
|
ownerWindow.GraphViewer.createViewerForElement(host);
|
|
664
|
+
markRendered(target, 'official');
|
|
665
|
+
};
|
|
666
|
+
const renderDrawio = async (documentRef, text, target) => {
|
|
667
|
+
try {
|
|
668
|
+
await runWithTimeout(renderOfficialDrawio(documentRef, text, target), DRAWIO_OFFICIAL_TIMEOUT, 'diagrams.net 官方 Viewer 加载超时,自动切换本地 SVG 预览');
|
|
669
|
+
}
|
|
670
|
+
catch (error) {
|
|
671
|
+
console.warn(error);
|
|
672
|
+
diagramsViewerPromises.delete(documentRef);
|
|
673
|
+
delete target.dataset.drawingRendered;
|
|
674
|
+
target.replaceChildren();
|
|
675
|
+
renderDrawioFallback(documentRef, text, target);
|
|
676
|
+
}
|
|
406
677
|
};
|
|
407
678
|
export default async function renderDrawing(buffer, target, type = 'drawio', _context) {
|
|
408
679
|
const documentRef = target.ownerDocument || document;
|
package/dist/renderers/epub.js
CHANGED
|
@@ -32,6 +32,7 @@ const epubStyle = `
|
|
|
32
32
|
.epub-stage .epub-container{width:100%!important;max-width:100%;overflow-x:hidden!important;overflow-y:auto!important}
|
|
33
33
|
.epub-stage iframe{max-width:100%}
|
|
34
34
|
.epub-state{position:absolute;inset:18px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:rgba(255,255,255,.92);color:#64748b;font-size:14px}
|
|
35
|
+
.epub-state[hidden]{display:none!important}
|
|
35
36
|
.epub-state.error{color:#b42318}
|
|
36
37
|
.file-viewer[data-viewer-theme='dark'] .epub-viewer{background:#172033;color:#e5eef8}
|
|
37
38
|
.file-viewer[data-viewer-theme='dark'] .epub-toolbar,.file-viewer[data-viewer-theme='dark'] .epub-toc,.file-viewer[data-viewer-theme='dark'] .epub-stage{background:#fff;color:#172033}
|
package/dist/renderers/model.js
CHANGED
|
@@ -13,6 +13,7 @@ const modelStyle = `
|
|
|
13
13
|
.model-stage{position:relative;flex:1;min-height:0;overflow:hidden}
|
|
14
14
|
.model-stage canvas{display:block;width:100%;height:100%;outline:none}
|
|
15
15
|
.model-state{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;padding:24px;background:rgba(248,250,252,.88);color:#64748b;text-align:center;line-height:1.7}
|
|
16
|
+
.model-state[hidden]{display:none!important}
|
|
16
17
|
.model-state.error{color:#b42318}
|
|
17
18
|
.model-state strong{color:#b42318;font-size:18px}
|
|
18
19
|
@media (max-width:720px){.model-toolbar{min-height:64px;align-items:flex-start;flex-direction:column;gap:8px;padding:8px 10px}.model-meta{width:100%;justify-content:flex-start}}
|
package/dist/renderers/ofd.js
CHANGED
|
@@ -8,6 +8,7 @@ const ofdStyle = `
|
|
|
8
8
|
.ofd-viewer *{box-sizing:border-box}
|
|
9
9
|
.ofd-stage{min-height:100%;padding:18px 0 28px;overflow:auto;scrollbar-gutter:stable}
|
|
10
10
|
.ofd-state{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;background:rgba(246,248,250,.92);color:#64748b;font-size:14px}
|
|
11
|
+
.ofd-state[hidden]{display:none!important}
|
|
11
12
|
.ofd-state.error{color:#b42318}
|
|
12
13
|
.ofd-page-frame{position:relative;display:block;margin:0 auto 20px;overflow:visible}
|
|
13
14
|
.ofd-page{display:block;margin-left:auto!important;margin-right:auto!important;box-shadow:0 10px 26px rgba(15,23,42,.12);transition:transform .16s ease}
|
package/dist/renderers/pdf.js
CHANGED
|
@@ -12,9 +12,14 @@ const SCALE_STEP = 0.1;
|
|
|
12
12
|
const FIT_HORIZONTAL_PADDING = 28;
|
|
13
13
|
const PAGE_BORDER_WIDTH = 18;
|
|
14
14
|
const PDF_EXPORT_MAX_PAGE_PIXELS = 8000000;
|
|
15
|
+
// PDF.js viewer CSS references image assets that are not shipped with the
|
|
16
|
+
// on-demand renderer chunk, so keep the preview self-contained and 404-free.
|
|
17
|
+
const normalizedPdfViewerStyle = pdfViewerStyle
|
|
18
|
+
.replace(/--page-border-image:\s*url\(images\/shadow\.png\)\s*9 9 repeat;/g, '--page-border-image:none;')
|
|
19
|
+
.replace(/background:\s*url\("\.\/images\/loading-icon\.gif"\)\s*center no-repeat;/g, 'background:none;');
|
|
15
20
|
const createStyle = (documentRef) => {
|
|
16
21
|
const style = documentRef.createElement('style');
|
|
17
|
-
style.textContent = `${
|
|
22
|
+
style.textContent = `${normalizedPdfViewerStyle}
|
|
18
23
|
.pdf-state[hidden],.pdf-nav-pane[hidden]{display:none!important}
|
|
19
24
|
`;
|
|
20
25
|
return style;
|
package/dist/renderers/typst.js
CHANGED
|
@@ -21,6 +21,11 @@ const typstStyle = `
|
|
|
21
21
|
.typst-loading p{margin:0;color:#6a778b;font-size:13px}
|
|
22
22
|
.typst-error{color:#9f1d1d}
|
|
23
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
|
+
.typst-source-fallback{box-sizing:border-box;width:min(1040px,calc(100% - 32px));margin:28px auto 44px;border:1px solid rgba(20,35,53,.1);border-radius:16px;background:#fff;box-shadow:0 18px 44px rgba(15,23,42,.14);overflow:hidden}
|
|
25
|
+
.typst-source-fallback header{padding:18px 20px;border-bottom:1px solid rgba(120,134,155,.18);background:linear-gradient(135deg,#f0fdf4,#eff6ff)}
|
|
26
|
+
.typst-source-fallback strong{display:block;color:#172033;font-size:15px;font-weight:850}
|
|
27
|
+
.typst-source-fallback p{margin:6px 0 0;color:#5f6e84;font-size:13px;line-height:1.7}
|
|
28
|
+
.typst-source-fallback pre{box-sizing:border-box;max-height:none;margin:0;overflow:auto;background:#0f172a;color:#e2e8f0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:13px;line-height:1.75;padding:20px;tab-size:2;white-space:pre}
|
|
24
29
|
.file-viewer[data-viewer-theme='dark'] .typst-viewer{background:#101820;color:#e6edf3}
|
|
25
30
|
.file-viewer[data-viewer-theme='dark'] .typst-toolbar{border-bottom-color:rgba(139,148,158,.22);background:rgba(15,23,42,.9)}
|
|
26
31
|
.file-viewer[data-viewer-theme='dark'] .typst-toolbar strong{color:#f8fafc}
|
|
@@ -28,11 +33,22 @@ const typstStyle = `
|
|
|
28
33
|
.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
34
|
.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
35
|
.file-viewer[data-viewer-theme='dark'] .typst-loading strong,.file-viewer[data-viewer-theme='dark'] .typst-error strong{color:#f8fafc}
|
|
36
|
+
.file-viewer[data-viewer-theme='dark'] .typst-source-fallback{border-color:rgba(139,148,158,.26);background:#151b23;box-shadow:0 24px 56px rgba(0,0,0,.32)}
|
|
37
|
+
.file-viewer[data-viewer-theme='dark'] .typst-source-fallback header{border-bottom-color:rgba(139,148,158,.22);background:linear-gradient(135deg,rgba(16,185,129,.18),rgba(59,130,246,.16))}
|
|
38
|
+
.file-viewer[data-viewer-theme='dark'] .typst-source-fallback strong{color:#f8fafc}
|
|
39
|
+
.file-viewer[data-viewer-theme='dark'] .typst-source-fallback p{color:#9aa7b8}
|
|
31
40
|
@keyframes typst-spin{to{transform:rotate(360deg)}}
|
|
32
41
|
@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}}
|
|
42
|
+
@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}.file-viewer[data-viewer-theme='system'] .typst-source-fallback{border-color:rgba(139,148,158,.26);background:#151b23;box-shadow:0 24px 56px rgba(0,0,0,.32)}.file-viewer[data-viewer-theme='system'] .typst-source-fallback header{border-bottom-color:rgba(139,148,158,.22);background:linear-gradient(135deg,rgba(16,185,129,.18),rgba(59,130,246,.16))}.file-viewer[data-viewer-theme='system'] .typst-source-fallback strong{color:#f8fafc}.file-viewer[data-viewer-theme='system'] .typst-source-fallback p{color:#9aa7b8}}
|
|
34
43
|
`;
|
|
35
44
|
let typstEngineConfigKey = '';
|
|
45
|
+
const DEFAULT_TYPST_RENDER_TIMEOUT_MS = 20000;
|
|
46
|
+
class TypstRenderTimeoutError extends Error {
|
|
47
|
+
constructor(timeoutMs) {
|
|
48
|
+
super(`Typst 编译超过 ${Math.round(timeoutMs / 1000)} 秒,已切换为源码预览`);
|
|
49
|
+
this.name = 'TypstRenderTimeoutError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
36
52
|
const createStyle = (documentRef) => {
|
|
37
53
|
const style = documentRef.createElement('style');
|
|
38
54
|
style.textContent = typstStyle;
|
|
@@ -54,15 +70,15 @@ const getWindowOverride = (key) => {
|
|
|
54
70
|
}
|
|
55
71
|
return window[key];
|
|
56
72
|
};
|
|
57
|
-
const configureTypstEngine = (context) => {
|
|
73
|
+
const configureTypstEngine = (context, documentBaseUrl) => {
|
|
58
74
|
var _a;
|
|
59
75
|
const typstOptions = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.typst;
|
|
60
76
|
const compilerWasmUrl = resolveFileViewerTypstCompilerWasmUrl(typstOptions, [
|
|
61
77
|
getWindowOverride('__FLYFISH_TYPST_COMPILER_WASM_URL__'),
|
|
62
|
-
]);
|
|
78
|
+
], documentBaseUrl);
|
|
63
79
|
const rendererWasmUrl = resolveFileViewerTypstRendererWasmUrl(typstOptions, [
|
|
64
80
|
getWindowOverride('__FLYFISH_TYPST_RENDERER_WASM_URL__'),
|
|
65
|
-
]);
|
|
81
|
+
], documentBaseUrl);
|
|
66
82
|
const configKey = `${compilerWasmUrl}\n${rendererWasmUrl}`;
|
|
67
83
|
if (typstEngineConfigKey === configKey) {
|
|
68
84
|
return;
|
|
@@ -171,6 +187,29 @@ const formatTypstError = (error) => {
|
|
|
171
187
|
const clampZoom = (value) => {
|
|
172
188
|
return Math.min(3, Math.max(0.3, Number(value.toFixed(2))));
|
|
173
189
|
};
|
|
190
|
+
const normalizeRenderTimeoutMs = (timeoutMs) => {
|
|
191
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs === undefined) {
|
|
192
|
+
return DEFAULT_TYPST_RENDER_TIMEOUT_MS;
|
|
193
|
+
}
|
|
194
|
+
return Math.max(0, timeoutMs);
|
|
195
|
+
};
|
|
196
|
+
const withRenderTimeout = async (promise, timeoutMs) => {
|
|
197
|
+
if (timeoutMs <= 0) {
|
|
198
|
+
return promise;
|
|
199
|
+
}
|
|
200
|
+
let timeoutId;
|
|
201
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
202
|
+
timeoutId = setTimeout(() => reject(new TypstRenderTimeoutError(timeoutMs)), timeoutMs);
|
|
203
|
+
});
|
|
204
|
+
try {
|
|
205
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
if (timeoutId) {
|
|
209
|
+
clearTimeout(timeoutId);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
174
213
|
const buildExportStyles = () => `
|
|
175
214
|
<style>
|
|
176
215
|
.typst-export-document {
|
|
@@ -269,6 +308,7 @@ export default async function renderTypst(buffer, target, _type, context) {
|
|
|
269
308
|
let state = 'loading';
|
|
270
309
|
let pages = [];
|
|
271
310
|
let errorMessage = '';
|
|
311
|
+
let sourceFallbackMessage = '';
|
|
272
312
|
let zoom = 1;
|
|
273
313
|
let renderToken = 0;
|
|
274
314
|
let disposed = false;
|
|
@@ -334,6 +374,16 @@ export default async function renderTypst(buffer, target, _type, context) {
|
|
|
334
374
|
error.append(createElement(documentRef, 'strong', undefined, 'Typst 渲染失败'), createElement(documentRef, 'pre', undefined, errorMessage));
|
|
335
375
|
body.replaceChildren(error);
|
|
336
376
|
};
|
|
377
|
+
const renderSourceFallback = () => {
|
|
378
|
+
const fallback = createElement(documentRef, 'main', 'typst-source-fallback');
|
|
379
|
+
fallback.setAttribute('aria-label', 'Typst source preview');
|
|
380
|
+
const header = createElement(documentRef, 'header');
|
|
381
|
+
header.append(createElement(documentRef, 'strong', undefined, '已切换为 Typst 源码预览'), createElement(documentRef, 'p', undefined, sourceFallbackMessage || '当前浏览器没有在预期时间内完成 Typst 编译,源码仍可完整查看。'));
|
|
382
|
+
const pre = createElement(documentRef, 'pre');
|
|
383
|
+
pre.textContent = source;
|
|
384
|
+
fallback.append(header, pre);
|
|
385
|
+
body.replaceChildren(fallback);
|
|
386
|
+
};
|
|
337
387
|
const renderPages = () => {
|
|
338
388
|
pageShells.clear();
|
|
339
389
|
const pagesRoot = createElement(documentRef, 'main', 'typst-pages');
|
|
@@ -351,29 +401,43 @@ export default async function renderTypst(buffer, target, _type, context) {
|
|
|
351
401
|
applyPageZoom();
|
|
352
402
|
};
|
|
353
403
|
const syncUi = () => {
|
|
354
|
-
summary.textContent = state === 'ready'
|
|
355
|
-
|
|
404
|
+
summary.textContent = state === 'ready'
|
|
405
|
+
? getPageSummary(pages)
|
|
406
|
+
: state === 'source'
|
|
407
|
+
? 'Typst source preview'
|
|
408
|
+
: 'Typst WASM renderer';
|
|
409
|
+
status.textContent = state === 'loading'
|
|
410
|
+
? '正在编译'
|
|
411
|
+
: state === 'error'
|
|
412
|
+
? '编译失败'
|
|
413
|
+
: state === 'source'
|
|
414
|
+
? '源码预览'
|
|
415
|
+
: '已渲染';
|
|
356
416
|
if (state === 'loading') {
|
|
357
417
|
renderLoading();
|
|
358
418
|
}
|
|
359
419
|
else if (state === 'error') {
|
|
360
420
|
renderError();
|
|
361
421
|
}
|
|
422
|
+
else if (state === 'source') {
|
|
423
|
+
renderSourceFallback();
|
|
424
|
+
}
|
|
362
425
|
else {
|
|
363
426
|
renderPages();
|
|
364
427
|
}
|
|
365
428
|
};
|
|
366
429
|
const render = async () => {
|
|
367
|
-
var _a, _b;
|
|
430
|
+
var _a, _b, _c, _d, _e;
|
|
368
431
|
const token = ++renderToken;
|
|
369
432
|
state = 'loading';
|
|
370
433
|
errorMessage = '';
|
|
434
|
+
sourceFallbackMessage = '';
|
|
371
435
|
pages = [];
|
|
372
436
|
(_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, null);
|
|
373
437
|
syncUi();
|
|
374
438
|
try {
|
|
375
|
-
configureTypstEngine(context);
|
|
376
|
-
const svg = await $typst.svg({
|
|
439
|
+
configureTypstEngine(context, documentRef.baseURI);
|
|
440
|
+
const svg = await withRenderTimeout($typst.svg({
|
|
377
441
|
mainContent: source,
|
|
378
442
|
data_selection: {
|
|
379
443
|
body: true,
|
|
@@ -381,7 +445,7 @@ export default async function renderTypst(buffer, target, _type, context) {
|
|
|
381
445
|
css: true,
|
|
382
446
|
js: false,
|
|
383
447
|
},
|
|
384
|
-
});
|
|
448
|
+
}), normalizeRenderTimeoutMs((_c = (_b = context === null || context === void 0 ? void 0 : context.options) === null || _b === void 0 ? void 0 : _b.typst) === null || _c === void 0 ? void 0 : _c.renderTimeoutMs));
|
|
385
449
|
if (disposed || token !== renderToken) {
|
|
386
450
|
return;
|
|
387
451
|
}
|
|
@@ -389,12 +453,19 @@ export default async function renderTypst(buffer, target, _type, context) {
|
|
|
389
453
|
state = 'ready';
|
|
390
454
|
syncUi();
|
|
391
455
|
registerExportAdapter();
|
|
392
|
-
(
|
|
456
|
+
(_d = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _d === void 0 ? void 0 : _d.call(context);
|
|
393
457
|
}
|
|
394
458
|
catch (error) {
|
|
395
459
|
if (disposed || token !== renderToken) {
|
|
396
460
|
return;
|
|
397
461
|
}
|
|
462
|
+
if (error instanceof TypstRenderTimeoutError) {
|
|
463
|
+
sourceFallbackMessage = error.message;
|
|
464
|
+
state = 'source';
|
|
465
|
+
syncUi();
|
|
466
|
+
(_e = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _e === void 0 ? void 0 : _e.call(context);
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
398
469
|
errorMessage = formatTypstError(error);
|
|
399
470
|
state = 'error';
|
|
400
471
|
syncUi();
|
package/dist/renderers/umd.js
CHANGED
|
@@ -28,7 +28,7 @@ const umdStyle = `
|
|
|
28
28
|
.umd-text{color:#1f2937;font-family:Georgia,'Times New Roman','Songti SC',SimSun,serif;font-size:17px;line-height:1.86;white-space:pre-wrap;word-break:break-word}
|
|
29
29
|
.umd-image-list{display:grid;gap:18px}.umd-image-list figure{margin:0;text-align:center}.umd-image-list img{max-width:100%;height:auto;border-radius:6px;box-shadow:0 10px 24px rgba(15,23,42,.12)}
|
|
30
30
|
.umd-empty,.umd-warning{color:#64748b;font-size:14px;line-height:1.7}.umd-warning{max-width:820px;margin:-28px auto 36px;padding:0 34px;color:#b45309;box-sizing:border-box}
|
|
31
|
-
.umd-state{position:absolute;inset:18px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:rgba(255,255,255,.92);color:#64748b;font-size:14px}.umd-state.error{color:#b42318}
|
|
31
|
+
.umd-state{position:absolute;inset:18px;display:flex;align-items:center;justify-content:center;border-radius:8px;background:rgba(255,255,255,.92);color:#64748b;font-size:14px}.umd-state[hidden]{display:none!important}.umd-state.error{color:#b42318}
|
|
32
32
|
.file-viewer[data-viewer-theme='dark'] .umd-viewer{background:#101820;color:#e5edf6}.file-viewer[data-viewer-theme='dark'] .umd-toolbar,.file-viewer[data-viewer-theme='dark'] .umd-toc{background:rgba(15,23,42,.92);border-color:rgba(148,163,184,.18)}
|
|
33
33
|
.file-viewer[data-viewer-theme='dark'] .umd-stage{background:#111827;box-shadow:0 18px 45px rgba(0,0,0,.35),inset 0 0 0 1px rgba(148,163,184,.16)}
|
|
34
34
|
.file-viewer[data-viewer-theme='dark'] .umd-book-head h1,.file-viewer[data-viewer-theme='dark'] .umd-chapter h2,.file-viewer[data-viewer-theme='dark'] .umd-text,.file-viewer[data-viewer-theme='dark'] .umd-toc-head{color:#e5edf6}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Framework-neutral TypeScript core for Flyfish File Viewer",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
"LICENSE"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@file-viewer/pptx": "^2.0.
|
|
61
|
+
"@file-viewer/pptx": "^2.0.7",
|
|
62
62
|
"@flyfish-dev/cad-viewer": "^0.6.4",
|
|
63
63
|
"@excalidraw/excalidraw": "^0.18.1",
|
|
64
64
|
"@kenjiuno/msgreader": "^1.28.0",
|