@file-viewer/core 2.0.6 → 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.
@@ -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 = "https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@0.7.0/pkg/typst_ts_web_compiler_bg.wasm";
10
- export declare const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = "https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@0.7.0/pkg/typst_ts_renderer_bg.wasm";
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 = "https://cdn.jsdelivr.net/npm/sql.js@1.14.1/dist/sql-wasm.wasm";
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>) => string;
58
- export declare const resolveFileViewerTypstRendererWasmUrl: (options?: Pick<FileViewerTypstOptions, "rendererWasmUrl"> | null, overrides?: Array<string | undefined>) => string;
59
- export declare const resolveFileViewerDataSqlWasmUrl: (options?: Pick<FileViewerDataOptions, "sqlWasmUrl"> | null, overrides?: Array<string | undefined>) => string;
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[];
@@ -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 = 'https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@0.7.0/pkg/typst_ts_web_compiler_bg.wasm';
9
- export const DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL = 'https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@0.7.0/pkg/typst_ts_renderer_bg.wasm';
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 = 'https://cdn.jsdelivr.net/npm/sql.js@1.14.1/dist/sql-wasm.wasm';
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: 'external',
112
+ target: 'public',
111
113
  required: true,
112
- defaultUrl: DEFAULT_FILE_VIEWER_TYPST_COMPILER_WASM_URL,
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; configurable for private CDN deployment.',
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: 'bundled-wasm',
120
- target: 'bundled',
122
+ kind: 'wasm',
123
+ target: 'public',
121
124
  required: true,
122
- defaultUrl: DEFAULT_FILE_VIEWER_TYPST_RENDERER_WASM_URL,
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 bundled by the active frontend build tool.',
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: 'external',
139
+ target: 'public',
137
140
  required: false,
138
- defaultUrl: DEFAULT_FILE_VIEWER_DATA_SQL_WASM_URL,
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 used when previewing SQLite files.',
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];
@@ -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}
@@ -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 renderDrawio = async (documentRef, text, target) => {
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;
@@ -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}
@@ -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}}
@@ -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}
@@ -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 = `${pdfViewerStyle}
22
+ style.textContent = `${normalizedPdfViewerStyle}
18
23
  .pdf-state[hidden],.pdf-nav-pane[hidden]{display:none!important}
19
24
  `;
20
25
  return style;
@@ -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' ? getPageSummary(pages) : 'Typst WASM renderer';
355
- status.textContent = state === 'loading' ? '正在编译' : state === 'error' ? '编译失败' : '已渲染';
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
- (_b = context === null || context === void 0 ? void 0 : context.onProgressiveRender) === null || _b === void 0 ? void 0 : _b.call(context);
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();
@@ -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.6",
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.6",
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",