@file-viewer/renderer-drawing 2.1.2 → 2.1.3

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/diagram.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { FileViewerDrawingOptions, FileViewerThemeMode } from '@file-viewer/core';
1
+ import { type FileViewerDrawingOptions, type FileViewerOptions, type FileViewerThemeMode } from '@file-viewer/core';
2
2
  export type DiagramKind = 'mermaid' | 'plantuml';
3
3
  export interface DiagramController {
4
4
  setZoom: (scale: number) => void;
@@ -13,6 +13,7 @@ interface RenderDiagramParams {
13
13
  kind: DiagramKind;
14
14
  options?: FileViewerDrawingOptions;
15
15
  theme?: FileViewerThemeMode;
16
+ viewerOptions?: FileViewerOptions;
16
17
  }
17
- export declare const renderDiagram: ({ documentRef, text, target, kind, options, theme }: RenderDiagramParams) => Promise<DiagramController>;
18
+ export declare const renderDiagram: ({ documentRef, text, target, kind, options, theme, viewerOptions }: RenderDiagramParams) => Promise<DiagramController>;
18
19
  export {};
package/dist/diagram.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createFileViewerTranslator } from '@file-viewer/core';
1
2
  import Panzoom, {} from '@panzoom/panzoom';
2
3
  const getOwnerWindow = (documentRef) => {
3
4
  return documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
@@ -28,11 +29,11 @@ const normalizePlantumlServer = (documentRef, value) => {
28
29
  return normalized;
29
30
  }
30
31
  };
31
- const sanitizeSvg = (documentRef, svg) => {
32
+ const sanitizeSvg = (documentRef, svg, t) => {
32
33
  const parsed = new DOMParser().parseFromString(svg, 'image/svg+xml');
33
34
  const parseError = parsed.querySelector('parsererror');
34
35
  if (parseError) {
35
- throw new Error(parseError.textContent || 'SVG 解析失败');
36
+ throw new Error(parseError.textContent || t('drawing.error.svgParseFailed'));
36
37
  }
37
38
  parsed.querySelectorAll('script,iframe,object,embed').forEach(node => node.remove());
38
39
  parsed.querySelectorAll('*').forEach(node => {
@@ -45,7 +46,7 @@ const sanitizeSvg = (documentRef, svg) => {
45
46
  const svgNode = parsed.documentElement;
46
47
  return documentRef.importNode(svgNode, true);
47
48
  };
48
- const renderMermaidSvg = async (documentRef, text, theme) => {
49
+ const renderMermaidSvg = async (documentRef, text, theme, t) => {
49
50
  const mermaidModule = await import('mermaid');
50
51
  const mermaid = mermaidModule.default;
51
52
  const id = `file-viewer-mermaid-${Date.now()}-${Math.random().toString(36).slice(2)}`;
@@ -55,7 +56,7 @@ const renderMermaidSvg = async (documentRef, text, theme) => {
55
56
  theme: isDarkTheme(documentRef, theme) ? 'dark' : 'default'
56
57
  });
57
58
  const rendered = await mermaid.render(id, text);
58
- return sanitizeSvg(documentRef, rendered.svg);
59
+ return sanitizeSvg(documentRef, rendered.svg, t);
59
60
  };
60
61
  const appendSvgText = (documentRef, parent, text, x, dy, weight = '500') => {
61
62
  const line = documentRef.createElementNS('http://www.w3.org/2000/svg', 'tspan');
@@ -121,7 +122,7 @@ const renderPlantumlFallbackSvg = (documentRef, text, message) => {
121
122
  svg.appendChild(source);
122
123
  return svg;
123
124
  };
124
- const renderPlantumlSvg = async (documentRef, text, options) => {
125
+ const renderPlantumlSvg = async (documentRef, text, options, t) => {
125
126
  if (!options?.plantumlServerUrl) {
126
127
  return renderPlantumlFallbackSvg(documentRef, text, 'Offline mode is active. Configure options.drawing.plantumlServerUrl for server-rendered PlantUML SVG.');
127
128
  }
@@ -135,9 +136,9 @@ const renderPlantumlSvg = async (documentRef, text, options) => {
135
136
  signal: controller.signal
136
137
  });
137
138
  if (!response.ok) {
138
- throw new Error(`PlantUML SVG 渲染失败:${response.status}`);
139
+ throw new Error(t('drawing.error.plantumlRenderFailed', { status: response.status }));
139
140
  }
140
- return sanitizeSvg(documentRef, await response.text());
141
+ return sanitizeSvg(documentRef, await response.text(), t);
141
142
  }
142
143
  catch (error) {
143
144
  if (error instanceof DOMException && error.name === 'AbortError') {
@@ -162,14 +163,15 @@ const applySvgDefaults = (svg, kind) => {
162
163
  svg.setAttribute('height', String(Math.ceil(svg.viewBox.baseVal.height)));
163
164
  }
164
165
  };
165
- export const renderDiagram = async ({ documentRef, text, target, kind, options, theme }) => {
166
+ export const renderDiagram = async ({ documentRef, text, target, kind, options, theme, viewerOptions }) => {
167
+ const t = createFileViewerTranslator(viewerOptions);
166
168
  const shell = createElement(documentRef, 'div', 'drawing-diagram-shell');
167
169
  const panTarget = createElement(documentRef, 'div', 'drawing-diagram-pan');
168
170
  shell.appendChild(panTarget);
169
171
  target.replaceChildren(shell);
170
172
  const svg = kind === 'mermaid'
171
- ? await renderMermaidSvg(documentRef, text, theme)
172
- : await renderPlantumlSvg(documentRef, text, options);
173
+ ? await renderMermaidSvg(documentRef, text, theme, t)
174
+ : await renderPlantumlSvg(documentRef, text, options, t);
173
175
  applySvgDefaults(svg, kind);
174
176
  panTarget.replaceChildren(svg);
175
177
  const panzoom = Panzoom(panTarget, {
package/dist/drawing.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, readFileViewerText, resolveFileViewerDrawioViewerScriptUrl, waitForFileViewerNextPaint, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
1
+ import { createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerZoomProvider, readFileViewerText, resolveFileViewerDrawioViewerScriptUrl, waitForFileViewerNextPaint, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
2
2
  const SVG_NS = 'http://www.w3.org/2000/svg';
3
3
  const EXCALIDRAW_OFFICIAL_TIMEOUT = 6000;
4
4
  const DRAWIO_OFFICIAL_TIMEOUT = 6000;
@@ -139,7 +139,7 @@ const deleteDiagramsViewerPromise = (documentRef, scriptUrl) => {
139
139
  diagramsViewerPromises.delete(documentRef);
140
140
  }
141
141
  };
142
- const loadDiagramsViewer = (documentRef, scriptUrl) => {
142
+ const loadDiagramsViewer = (documentRef, scriptUrl, t) => {
143
143
  const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
144
144
  if (ownerWindow?.GraphViewer) {
145
145
  return Promise.resolve();
@@ -155,14 +155,14 @@ const loadDiagramsViewer = (documentRef, scriptUrl) => {
155
155
  .find(script => script.src === scriptUrl);
156
156
  if (existed) {
157
157
  existed.addEventListener('load', () => resolve(), { once: true });
158
- existed.addEventListener('error', () => reject(new Error('diagrams.net viewer 加载失败')), { once: true });
158
+ existed.addEventListener('error', () => reject(new Error(t('drawing.error.viewerLoadFailed'))), { once: true });
159
159
  return;
160
160
  }
161
161
  const script = documentRef.createElement('script');
162
162
  script.src = scriptUrl;
163
163
  script.async = true;
164
164
  script.onload = () => resolve();
165
- script.onerror = () => reject(new Error('diagrams.net viewer 加载失败'));
165
+ script.onerror = () => reject(new Error(t('drawing.error.viewerLoadFailed')));
166
166
  documentRef.head.appendChild(script);
167
167
  });
168
168
  promiseMap.set(scriptUrl, nextPromise);
@@ -446,16 +446,16 @@ const renderOfficialExcalidraw = async (payload, elements, target) => {
446
446
  setTimeout(restoreConsole, 3000);
447
447
  }
448
448
  };
449
- const renderExcalidraw = async (documentRef, text, target) => {
449
+ const renderExcalidraw = async (documentRef, text, target, t) => {
450
450
  const payload = JSON.parse(text);
451
451
  const elements = Array.isArray(payload.elements)
452
452
  ? payload.elements.filter((element) => !element.isDeleted)
453
453
  : [];
454
454
  if (!elements.length) {
455
- throw new Error('Excalidraw 文件中没有可预览图元');
455
+ throw new Error(t('drawing.error.excalidrawEmpty'));
456
456
  }
457
457
  try {
458
- await runWithTimeout(renderOfficialExcalidraw(payload, elements, target), EXCALIDRAW_OFFICIAL_TIMEOUT, 'Excalidraw 官方导出超时,自动切换 rough.js 兼容渲染');
458
+ await runWithTimeout(renderOfficialExcalidraw(payload, elements, target), EXCALIDRAW_OFFICIAL_TIMEOUT, t('drawing.error.excalidrawTimeout'));
459
459
  }
460
460
  catch (error) {
461
461
  console.warn(error);
@@ -550,17 +550,17 @@ const appendDrawioWrappedText = (documentRef, svg, text, x, y, width, height, fo
550
550
  });
551
551
  svg.appendChild(textNode);
552
552
  };
553
- const renderDrawioFallback = (documentRef, text, target) => {
553
+ const renderDrawioFallback = (documentRef, text, target, t) => {
554
554
  const parser = new DOMParser();
555
555
  const parsed = parser.parseFromString(text, 'text/xml');
556
556
  const parseError = parsed.querySelector('parsererror');
557
557
  if (parseError) {
558
- throw new Error(`Draw.io XML 解析失败:${parseError.textContent || 'invalid xml'}`);
558
+ throw new Error(t('drawing.error.drawioParseFailed', { message: parseError.textContent || 'invalid xml' }));
559
559
  }
560
560
  const firstDiagram = parsed.querySelector('diagram');
561
561
  const graphModel = firstDiagram?.querySelector('mxGraphModel') || parsed.querySelector('mxGraphModel');
562
562
  if (!graphModel) {
563
- throw new Error('当前 Draw.io 文件没有可直接渲染的 mxGraphModel。');
563
+ throw new Error(t('drawing.error.drawioNoModel'));
564
564
  }
565
565
  const cells = Array.from(graphModel.querySelectorAll('mxCell'));
566
566
  const vertices = cells
@@ -574,7 +574,7 @@ const renderDrawioFallback = (documentRef, text, target) => {
574
574
  }))
575
575
  .filter(item => item.id && item.geometry);
576
576
  if (!vertices.length) {
577
- throw new Error('当前 Draw.io 文件没有可预览图元。');
577
+ throw new Error(t('drawing.error.drawioNoElements'));
578
578
  }
579
579
  const vertexById = new Map(vertices.map(vertex => [vertex.id, vertex]));
580
580
  const allX = vertices.flatMap(vertex => [vertex.geometry.x, vertex.geometry.x + vertex.geometry.width]);
@@ -716,9 +716,9 @@ const renderDrawioFallback = (documentRef, text, target) => {
716
716
  }
717
717
  appendRenderedSvg(target, svg, 'rough');
718
718
  };
719
- const renderOfficialDrawio = async (documentRef, text, target, scriptUrl) => {
719
+ const renderOfficialDrawio = async (documentRef, text, target, scriptUrl, t) => {
720
720
  const ownerWindow = documentRef.defaultView || (typeof window !== 'undefined' ? window : undefined);
721
- await loadDiagramsViewer(documentRef, scriptUrl);
721
+ await loadDiagramsViewer(documentRef, scriptUrl, t);
722
722
  await waitForFileViewerNextPaint(ownerWindow);
723
723
  const host = createElement(documentRef, 'div', 'mxgraph drawing-mxgraph');
724
724
  host.setAttribute('data-mxgraph', JSON.stringify({
@@ -736,31 +736,32 @@ const renderOfficialDrawio = async (documentRef, text, target, scriptUrl) => {
736
736
  }));
737
737
  target.appendChild(host);
738
738
  if (!ownerWindow?.GraphViewer) {
739
- throw new Error('diagrams.net viewer 未正确初始化');
739
+ throw new Error(t('drawing.error.viewerInitFailed'));
740
740
  }
741
741
  ownerWindow.GraphViewer.createViewerForElement(host);
742
742
  markRendered(target, 'official');
743
743
  };
744
- const renderDrawio = async (documentRef, text, target, options) => {
744
+ const renderDrawio = async (documentRef, text, target, options, t) => {
745
745
  if (options?.preferOfficial === false) {
746
- renderDrawioFallback(documentRef, text, target);
746
+ renderDrawioFallback(documentRef, text, target, t);
747
747
  return;
748
748
  }
749
749
  const scriptUrl = resolveDrawingViewerScriptUrl(options, documentRef);
750
750
  try {
751
- await runWithTimeout(renderOfficialDrawio(documentRef, text, target, scriptUrl), DRAWIO_OFFICIAL_TIMEOUT, 'diagrams.net 官方 Viewer 加载超时,自动切换本地 SVG 预览');
751
+ await runWithTimeout(renderOfficialDrawio(documentRef, text, target, scriptUrl, t), DRAWIO_OFFICIAL_TIMEOUT, t('drawing.error.drawioTimeout'));
752
752
  }
753
753
  catch (error) {
754
754
  console.warn(error);
755
755
  deleteDiagramsViewerPromise(documentRef, scriptUrl);
756
756
  delete target.dataset.drawingRendered;
757
757
  target.replaceChildren();
758
- renderDrawioFallback(documentRef, text, target);
758
+ renderDrawioFallback(documentRef, text, target, t);
759
759
  }
760
760
  };
761
761
  export default async function renderDrawing(buffer, target, type = 'drawio', context) {
762
762
  const documentRef = target.ownerDocument || document;
763
763
  const kind = normalizeDrawingType(type);
764
+ const t = createFileViewerTranslator(context?.options);
764
765
  const zoomEmitter = createFileViewerZoomChangeEmitter();
765
766
  let status = 'loading';
766
767
  let errorMessage = '';
@@ -772,23 +773,23 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
772
773
  const toolbar = createElement(documentRef, 'div', 'drawing-toolbar');
773
774
  const title = createElement(documentRef, 'div', 'drawing-title');
774
775
  title.append(createElement(documentRef, 'span', undefined, formatDrawingLabel(type)), createElement(documentRef, 'strong', undefined, kind === 'excalidraw'
775
- ? 'Excalidraw 官方 SVG 预览'
776
+ ? t('drawing.title.excalidraw')
776
777
  : kind === 'mermaid'
777
- ? 'Mermaid SVG 预览'
778
+ ? t('drawing.title.mermaid')
778
779
  : kind === 'plantuml'
779
- ? 'PlantUML SVG 预览'
780
- : 'Draw.io 离线 SVG 预览'));
780
+ ? t('drawing.title.plantuml')
781
+ : t('drawing.title.drawio')));
781
782
  const actions = createElement(documentRef, 'div', 'drawing-actions');
782
783
  const zoomOutButton = createElement(documentRef, 'button', undefined, '-');
783
784
  const zoomLabel = createElement(documentRef, 'span');
784
785
  const zoomInButton = createElement(documentRef, 'button', undefined, '+');
785
- const resetButton = createElement(documentRef, 'button', undefined, '适合');
786
+ const resetButton = createElement(documentRef, 'button', undefined, t('drawing.toolbar.fit'));
786
787
  [zoomOutButton, zoomInButton, resetButton].forEach(button => {
787
788
  button.type = 'button';
788
789
  });
789
- zoomOutButton.title = '缩小';
790
- zoomInButton.title = '放大';
791
- resetButton.title = '适合宽度';
790
+ zoomOutButton.title = t('drawing.toolbar.zoomOut');
791
+ zoomInButton.title = t('drawing.toolbar.zoomIn');
792
+ resetButton.title = t('drawing.toolbar.fitWidth');
792
793
  actions.append(zoomOutButton, zoomLabel, zoomInButton, resetButton);
793
794
  toolbar.append(title, actions);
794
795
  const stageWrapper = createElement(documentRef, 'div', 'drawing-stage');
@@ -843,7 +844,7 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
843
844
  state.classList.toggle('error', status === 'error');
844
845
  state.textContent = status === 'error'
845
846
  ? errorMessage
846
- : '正在加载绘图预览...';
847
+ : t('drawing.state.loading');
847
848
  applyZoom();
848
849
  };
849
850
  const loadDrawing = async () => {
@@ -858,7 +859,7 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
858
859
  return;
859
860
  }
860
861
  if (kind === 'excalidraw') {
861
- await renderExcalidraw(documentRef, text, canvas);
862
+ await renderExcalidraw(documentRef, text, canvas, t);
862
863
  }
863
864
  else if (kind === 'mermaid' || kind === 'plantuml') {
864
865
  const { renderDiagram } = await import('./diagram.js');
@@ -869,10 +870,11 @@ export default async function renderDrawing(buffer, target, type = 'drawio', con
869
870
  kind,
870
871
  options: context?.options?.drawing,
871
872
  theme: context?.options?.theme,
873
+ viewerOptions: context?.options,
872
874
  });
873
875
  }
874
876
  else {
875
- await renderDrawio(documentRef, text, canvas, context?.options?.drawing);
877
+ await renderDrawio(documentRef, text, canvas, context?.options?.drawing, t);
876
878
  }
877
879
  if (disposed) {
878
880
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/renderer-drawing",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone Draw.io, Excalidraw, Mermaid, and PlantUML renderer plugin for Flyfish File Viewer with pan/zoom support.",
@@ -57,7 +57,7 @@
57
57
  ],
58
58
  "dependencies": {
59
59
  "@excalidraw/excalidraw": "^0.18.1",
60
- "@file-viewer/core": "^2.1.2",
60
+ "@file-viewer/core": "^2.1.3",
61
61
  "@panzoom/panzoom": "^4.6.2",
62
62
  "mermaid": "^11.15.0",
63
63
  "plantuml-encoder": "^1.4.0",