@file-viewer/renderer-cad 3.0.1 → 3.0.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/README.en.md CHANGED
@@ -49,3 +49,27 @@ For private deployments, override them with `options.cad.wasmPath`, `options.cad
49
49
  ## Migration Note
50
50
 
51
51
  CAD preview has moved completely out of `@file-viewer/core`. Core now only keeps the asset manifest, shared types, and a compatibility error message, and it no longer installs `@flyfish-dev/cad-viewer` by default. Install this package and pass it through `renderers`, or use `@file-viewer/preset-all` for the complete CAD experience.
52
+
53
+ ## Monochrome plot mode
54
+
55
+ Set `cad.colorMode` to `source` or `monochrome`. Monochrome rendering uses the CAD engine's entity-color policy rather than a CSS filter, keeping Canvas, WebGL, text overlays and native DWF output consistent while preserving alpha, line types, line weights and source data.
56
+
57
+ Source mode defaults to a dark background; monochrome defaults to black lines on white paper. Adaptive contrast makes lines and text near the background color readable. Use `cad.canvasOptions.contrastMode: 'preserve'` for exact source colors. Explicit `cad.canvasOptions.background` / `cad.dwfBackground` values survive mode changes.
58
+
59
+ ```ts
60
+ {
61
+ cad: {
62
+ colorMode: 'monochrome',
63
+ monochromeColor: '#000000',
64
+ showColorModeToggle: true,
65
+ },
66
+ }
67
+ ```
68
+
69
+ ### Images, print and offline HTML
70
+
71
+ Select the color mode, then use Print or HTML in the shared toolbar. Output redraws and captures the current view, including WebGL lines and text overlays, without layer panels or controls. HTML embeds a PNG instead of a temporary blob URL. The print window supports the browser's Save as PDF and retains File Viewer permission checks, watermarks and masks.
72
+
73
+ PNG and JPEG buttons download the same rendered view, including configured text or image watermarks. Both `toolbar.permissions.download` and `toolbar.permissions['export-html']` must allow the operation. The owning viewer runs its normal `beforeOperation`, toolbar `beforeOperation` and `beforeDownload` hooks before capture; cancellation or a document/permission change prevents the download. Use `cad.showImageExport: false` to hide these renderer-local buttons. A missing watermark fails explicitly without breaking the live preview. Print masks apply to Print, not to image downloads.
74
+
75
+ This is a raster snapshot of the current camera view / current DWF page, not a vector conversion or batch export of every sheet. Use Fit first to include the full drawing. Original-file download never changes the input bytes.
package/README.md CHANGED
@@ -49,3 +49,27 @@ const options = {
49
49
  ## 迁移说明
50
50
 
51
51
  CAD 预览已经从 `@file-viewer/core` 中彻底移出,core 只保留资产 manifest、类型和兼容错误提示,不再默认安装 `@flyfish-dev/cad-viewer`。完整 CAD 能力请安装本包并传入 `renderers`,或直接使用 `@file-viewer/preset-all`。
52
+
53
+ ## 黑白出图模式
54
+
55
+ `cad.colorMode` 可设为 `source` 或 `monochrome`。黑白模式通过 CAD 引擎的实体颜色策略实现,不使用 CSS 滤镜,因此 Canvas、WebGL、文字覆盖层及原生 DWF 渲染可保持一致,同时保留透明度、线型、线宽和源文件数据。
56
+
57
+ 默认原色模式使用深色背景,黑白模式使用白纸黑线。自适应对比度会提高与背景过近的线条和文字的可见性;要求严格显示源颜色时可设 `cad.canvasOptions.contrastMode: 'preserve'`。显式设置的 `cad.canvasOptions.background` / `cad.dwfBackground` 不会被模式切换覆盖。
58
+
59
+ ```ts
60
+ {
61
+ cad: {
62
+ colorMode: 'monochrome',
63
+ monochromeColor: '#000000',
64
+ showColorModeToggle: true,
65
+ },
66
+ }
67
+ ```
68
+
69
+ ### 图片、打印与离线 HTML
70
+
71
+ 先选择原色或黑白模式,再使用统一工具栏的“打印”或“HTML”。输出会重新绘制并立即捕获当前视图,包含 WebGL 线条和文字覆盖层,不含图层面板或工具栏。HTML 内嵌 PNG,不依赖临时 blob 地址;打印窗口可使用浏览器的“另存为 PDF”,并保留 File Viewer 的权限检查、水印和遮罩。
72
+
73
+ CAD 工具栏的 PNG、JPEG 按钮下载同一视图,并保留配置的文本或图片水印。`toolbar.permissions.download` 与 `toolbar.permissions['export-html']` 都必须允许;捕获前由所属组件执行既有 `beforeOperation`、工具栏 `beforeOperation` 和 `beforeDownload` 钩子。取消操作、切换文档或撤销权限后不会下载旧快照。`cad.showImageExport: false` 可隐藏这两个格式专用按钮。水印资源不可读时明确失败,预览仍保持可用。打印遮罩仅作用于打印,不作用于图片下载。
74
+
75
+ 这里输出的是当前相机视图 / 当前 DWF 页的栅格快照,不是整个 CAD 文件的矢量转换,也不会自动批量打印其他图纸页。需要完整图纸时先点击“适配”。原文件下载始终保持输入字节不变。
package/dist/cad.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { CadViewer, inferEntityKind, } from '@flyfish-dev/cad-viewer';
2
2
  import { resolveFileViewerCadAssetUrls, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
3
- import { createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerLocale, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
3
+ import { createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, createFileViewerZoomChangeEmitter, createFileViewerCanvasImageBlob, isFileViewerSnapshotDownloadPermitted, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerLocale, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
4
+ import { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveFileViewerCadMonochromeColor, resolveFileViewerCadCanvasOptions, resolveCadViewerSourceDocument, supportsCadViewerColorMode, } from './colorMode.js';
5
+ import { captureFileViewerCadCanvas, createFileViewerCadExportAdapter } from './export.js';
4
6
  const CAD_WORKER_TIMEOUT = 120000;
5
7
  const CAD_DEFAULT_FIT_PADDING = 0.92;
6
8
  const CAD_BOUNDS_EPSILON = 1e-9;
@@ -8,12 +10,21 @@ const CAD_BEST_FIT_OUTLIER_RATIO = 8;
8
10
  const CAD_NATIVE_MIN_ZOOM_RATIO = 0.05;
9
11
  const CAD_NATIVE_MAX_ZOOM_RATIO = 64;
10
12
  const cadStyle = `
11
- .cad-shell{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f5f7fb;color:#142335}
13
+ .cad-shell{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f5f7fb;color:#142335;container-type:inline-size;container-name:file-viewer-cad}
12
14
  .cad-shell *{box-sizing:border-box}
13
- .cad-toolbar{display:flex;min-height:48px;align-items:center;justify-content:space-between;gap:16px;padding:0 14px;border-bottom:1px solid rgba(15,23,42,.08);background:#fff}
15
+ .cad-toolbar{display:flex;flex-shrink:0;min-height:48px;align-items:center;justify-content:space-between;gap:16px;padding:0 14px;border-bottom:1px solid rgba(15,23,42,.08);background:#fff}
14
16
  .cad-tools,.cad-meta{display:flex;align-items:center;gap:8px}
17
+ .cad-tools{flex-wrap:wrap;padding:6px 0}
18
+ .cad-tools button.cad-export-image{min-width:44px;min-height:40px;padding:0 10px;white-space:nowrap}
19
+ .cad-tools button[hidden]{display:none}
20
+ .cad-tools button:disabled{cursor:not-allowed;opacity:.46}
21
+ .cad-export-error{margin:0;padding:6px 14px;background:#fff4ed;color:#b42318;font-size:12px}
22
+ .cad-export-error[hidden]{display:none}
15
23
  .cad-tools button{min-width:34px;min-height:30px;border:0;border-radius:8px;background:rgba(15,23,42,.06);color:#25344c;cursor:pointer;font-weight:800;letter-spacing:0;transition:background-color .18s ease,color .18s ease}
16
24
  .cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}
25
+ .cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px}
26
+ .cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff}
27
+ .cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46}
17
28
  .cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}
18
29
  .cad-meta span{border-radius:999px;padding:5px 9px;background:rgba(15,23,42,.06)}
19
30
  .cad-body{display:grid;min-height:0;flex:1;grid-template-columns:minmax(176px,236px) minmax(0,1fr) minmax(142px,176px);background:#eef2f7}
@@ -94,7 +105,8 @@ const cadStyle = `
94
105
  [data-viewer-theme='dark'] .cad-canvas-wrap{background:linear-gradient(90deg,rgba(148,163,184,.08) 1px,transparent 1px),linear-gradient(180deg,rgba(148,163,184,.08) 1px,transparent 1px),#090d14;background-size:28px 28px}
95
106
  [data-viewer-theme='dark'] .cad-state{background:rgba(15,23,42,.92);color:#cbd5e1;box-shadow:0 18px 44px rgba(0,0,0,.34)}
96
107
  @media (prefers-color-scheme:dark){[data-viewer-theme='system'] .cad-shell{background:#111827;color:#e5edf6}[data-viewer-theme='system'] .cad-body{background:#0d1117}[data-viewer-theme='system'] .cad-toolbar,[data-viewer-theme='system'] .cad-layers,[data-viewer-theme='system'] .cad-inspector{border-color:rgba(139,148,158,.2);background:#111827;color:#e5edf6}[data-viewer-theme='system'] .cad-layers-head{border-color:rgba(139,148,158,.2);background:rgba(17,24,39,.96);color:#f8fafc}[data-viewer-theme='system'] .cad-tools button,[data-viewer-theme='system'] .cad-meta span,[data-viewer-theme='system'] .cad-inspector dl div{background:#1f2937;color:#cbd5e1}[data-viewer-theme='system'] .cad-layers button,[data-viewer-theme='system'] .cad-inspector strong,[data-viewer-theme='system'] .cad-inspector dd{color:#e5edf6}[data-viewer-theme='system'] .cad-layers button:hover{background:#1f2937}[data-viewer-theme='system'] .cad-zoom,[data-viewer-theme='system'] .cad-meta span,[data-viewer-theme='system'] .cad-inspector dt,[data-viewer-theme='system'] .cad-layers-head span{color:#94a3b8}[data-viewer-theme='system'] .cad-canvas-wrap{background:linear-gradient(90deg,rgba(148,163,184,.08) 1px,transparent 1px),linear-gradient(180deg,rgba(148,163,184,.08) 1px,transparent 1px),#090d14;background-size:28px 28px}[data-viewer-theme='system'] .cad-state{background:rgba(15,23,42,.92);color:#cbd5e1;box-shadow:0 18px 44px rgba(0,0,0,.34)}}
97
- @media (max-width:860px){.cad-body,.cad-body.without-layers{grid-template-columns:minmax(0,1fr)}.cad-layers,.cad-inspector{display:none}}
108
+ @media (max-width:860px){.cad-body,.cad-body.without-layers{grid-template-columns:minmax(0,1fr)}.cad-layers,.cad-inspector,.cad-meta{display:none}.cad-tools{flex:1}.cad-tools button{min-width:44px;min-height:40px}}
109
+ @container file-viewer-cad (max-width:600px){.cad-meta{display:none}.cad-tools{flex:1}.cad-tools button{min-width:44px;min-height:40px}}
98
110
  `;
99
111
  const createStyle = () => {
100
112
  const style = document.createElement('style');
@@ -643,11 +655,13 @@ const resolveLayerSourceNames = (document, layer) => {
643
655
  return Array.from(names);
644
656
  };
645
657
  export default async function renderCad(buffer, target, type = 'dxf', context) {
646
- var _a;
658
+ var _a, _b;
647
659
  const normalizedType = normalizeType(type);
648
660
  const options = ((_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.cad) || {};
649
661
  const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
650
662
  const locale = resolveFileViewerLocale(context === null || context === void 0 ? void 0 : context.options);
663
+ const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor);
664
+ let colorMode = normalizeFileViewerCadColorMode(options.colorMode);
651
665
  let status = 'loading';
652
666
  let progressMessage = t('cad.state.loadingViewer');
653
667
  let errorMessage = '';
@@ -663,6 +677,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
663
677
  let fitViewActive = true;
664
678
  let nativeZoomRatio = 1;
665
679
  let disposed = false;
680
+ let exportingImage = false;
666
681
  const style = createStyle();
667
682
  const shell = createElement('div', 'cad-shell');
668
683
  shell.dataset.viewerZoomProvider = 'cad';
@@ -672,18 +687,61 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
672
687
  const zoomOutButton = createElement('button', undefined, '-');
673
688
  const zoomText = createElement('span', 'cad-zoom', '100%');
674
689
  const zoomInButton = createElement('button', undefined, '+');
690
+ const colorModeButton = createElement('button', 'cad-color-mode');
691
+ colorModeButton.hidden = options.showColorModeToggle === false;
675
692
  const meta = createElement('div', 'cad-meta');
676
693
  const typeMeta = createElement('span', undefined, normalizedType.toUpperCase());
677
694
  const backendMeta = createElement('span', undefined, 'AUTO');
678
- [fitButton, zoomOutButton, zoomInButton].forEach(button => {
695
+ [fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => {
679
696
  button.type = 'button';
680
697
  });
681
698
  fitButton.title = t('cad.toolbar.fit');
682
699
  zoomOutButton.title = t('cad.toolbar.zoomOut');
683
700
  zoomInButton.title = t('cad.toolbar.zoomIn');
684
- tools.append(fitButton, zoomOutButton, zoomText, zoomInButton);
701
+ tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton);
702
+ const imageButtons = ['png', 'jpeg'].map(format => {
703
+ const button = createElement('button', `cad-export-image cad-export-${format}`, format.toUpperCase());
704
+ button.type = 'button';
705
+ button.title = t('cad.toolbar.exportImage', { format: format.toUpperCase() });
706
+ button.setAttribute('aria-label', button.title);
707
+ button.hidden = !(context === null || context === void 0 ? void 0 : context.requestSnapshotDownload) || options.showImageExport === false ||
708
+ !isFileViewerSnapshotDownloadPermitted(context === null || context === void 0 ? void 0 : context.options);
709
+ button.addEventListener('click', async () => {
710
+ var _a;
711
+ if (disposed || status !== 'ready' || exportingImage)
712
+ return;
713
+ exportingImage = true;
714
+ exportError.hidden = true;
715
+ syncState();
716
+ try {
717
+ await ((_a = context === null || context === void 0 ? void 0 : context.requestSnapshotDownload) === null || _a === void 0 ? void 0 : _a.call(context, async (watermark) => {
718
+ const snapshot = await captureFileViewerCadCanvas(() => viewer);
719
+ const blob = await createFileViewerCanvasImageBlob(snapshot, format, watermark, snapshot.width / stage.clientWidth);
720
+ const name = buildFileName().replace(/\.[^.]+$/, '') || 'drawing';
721
+ return { blob, filename: `${name}.${format === 'jpeg' ? 'jpg' : 'png'}` };
722
+ }));
723
+ }
724
+ catch (error) {
725
+ if (!disposed) {
726
+ exportError.textContent = t('cad.error.exportFailed', { message: error instanceof Error ? error.message : String(error) });
727
+ exportError.hidden = false;
728
+ console.error(error);
729
+ }
730
+ }
731
+ finally {
732
+ exportingImage = false;
733
+ if (!disposed)
734
+ syncState();
735
+ }
736
+ });
737
+ tools.append(button);
738
+ return button;
739
+ });
685
740
  meta.append(typeMeta, backendMeta);
686
741
  toolbar.append(tools, meta);
742
+ const exportError = createElement('p', 'cad-export-error');
743
+ exportError.setAttribute('role', 'alert');
744
+ exportError.hidden = true;
687
745
  const body = createElement('div', 'cad-body without-layers');
688
746
  const layersPanel = createElement('aside', 'cad-layers');
689
747
  layersPanel.hidden = true;
@@ -705,7 +763,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
705
763
  warningText.hidden = true;
706
764
  inspector.append(inspectorTitle, inspectorList, warningText);
707
765
  body.append(layersPanel, canvasWrap, inspector);
708
- shell.append(toolbar, body);
766
+ shell.append(toolbar, exportError, body);
709
767
  target.replaceChildren(style, shell);
710
768
  const buildFileName = () => {
711
769
  return (context === null || context === void 0 ? void 0 : context.filename) || `drawing.${normalizedType}`;
@@ -749,6 +807,8 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
749
807
  status,
750
808
  view: viewState ? { ...viewState } : null,
751
809
  backend: renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend,
810
+ colorMode,
811
+ monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined,
752
812
  layerCount: layers.length,
753
813
  visibleLayers: layers
754
814
  .filter(layer => layer.isVisible !== false && !layer.isFrozen)
@@ -885,12 +945,15 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
885
945
  : layer.name;
886
946
  button.setAttribute('aria-pressed', String(layerVisible));
887
947
  const color = createElement('span', 'cad-layer-color');
888
- if (typeof layer.color === 'string') {
948
+ if (colorMode === 'monochrome') {
949
+ color.style.background = monochromeColor;
950
+ }
951
+ else if (typeof layer.color === 'string') {
889
952
  color.style.background = layer.color;
890
953
  }
891
954
  button.append(color, createElement('span', undefined, layer.name));
892
955
  button.addEventListener('click', () => {
893
- const document = viewer === null || viewer === void 0 ? void 0 : viewer.getDocument();
956
+ const document = resolveCadViewerSourceDocument(viewer);
894
957
  if (!document) {
895
958
  return;
896
959
  }
@@ -915,8 +978,21 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
915
978
  }));
916
979
  };
917
980
  const syncState = () => {
981
+ imageButtons.forEach(button => {
982
+ button.disabled = status !== 'ready' || exportingImage || !viewer ||
983
+ typeof viewer.captureCanvas !== 'function';
984
+ });
918
985
  zoomText.textContent = `${getZoomPercent()}%`;
919
986
  backendMeta.textContent = ((renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend) || 'auto').toUpperCase();
987
+ const colorModeSupported = supportsCadViewerColorMode(viewer);
988
+ colorModeButton.disabled = status !== 'ready' || !colorModeSupported;
989
+ colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome'));
990
+ colorModeButton.textContent = t(colorMode === 'monochrome'
991
+ ? 'cad.toolbar.monochrome'
992
+ : 'cad.toolbar.colorSource');
993
+ colorModeButton.title = t(colorMode === 'monochrome'
994
+ ? 'cad.toolbar.colorSource'
995
+ : 'cad.toolbar.monochrome');
920
996
  state.hidden = status === 'ready';
921
997
  state.classList.toggle('error', status === 'error');
922
998
  if (status === 'loading') {
@@ -1054,20 +1130,21 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
1054
1130
  fitButton.addEventListener('click', () => fitToView());
1055
1131
  zoomInButton.addEventListener('click', zoomIn);
1056
1132
  zoomOutButton.addEventListener('click', zoomOut);
1133
+ colorModeButton.addEventListener('click', () => {
1134
+ const previousMode = colorMode;
1135
+ colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome';
1136
+ if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor, options)) {
1137
+ colorMode = previousMode;
1138
+ syncState();
1139
+ return;
1140
+ }
1141
+ syncUi();
1142
+ emitCadViewStateChange('cad-view-change', 'user');
1143
+ });
1057
1144
  const createViewer = () => {
1058
1145
  var _a, _b, _c, _d, _e, _f, _g;
1059
1146
  const { wasmPath, workerUrl, dwfWasmUrl } = resolveFileViewerCadAssetUrls(options, getCadDocumentBaseUrl(target));
1060
- const canvasOptions = {
1061
- background: '#f8fafc',
1062
- foreground: '#0f172a',
1063
- contrastMode: 'adaptive',
1064
- minColorContrast: 2.4,
1065
- showPageBounds: true,
1066
- showUnsupportedMarkers: true,
1067
- enableSpatialIndex: true,
1068
- maxVisibleTextLabels: 2400,
1069
- ...(options.canvasOptions || {}),
1070
- };
1147
+ const canvasOptions = resolveFileViewerCadCanvasOptions(options, colorMode);
1071
1148
  const nextViewer = new CadViewer({
1072
1149
  container: stage,
1073
1150
  nativeHost,
@@ -1084,7 +1161,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
1084
1161
  keepRaw: (_e = options.keepRaw) !== null && _e !== void 0 ? _e : false,
1085
1162
  dwfPreferWebgl: (_f = options.dwfPreferWebgl) !== null && _f !== void 0 ? _f : true,
1086
1163
  dwfPreferWasm: (_g = options.dwfPreferWasm) !== null && _g !== void 0 ? _g : true,
1087
- dwfBackground: options.dwfBackground || '#f8fafc',
1164
+ dwfBackground: options.dwfBackground,
1088
1165
  dwfMaxDevicePixelRatio: options.dwfMaxDevicePixelRatio,
1089
1166
  dwfMaxCanvasPixels: options.dwfMaxCanvasPixels,
1090
1167
  dwfMaxGpuCacheBytes: options.dwfMaxGpuCacheBytes,
@@ -1094,6 +1171,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
1094
1171
  dwfMaxOverviewStrokeCssPx: options.dwfMaxOverviewStrokeCssPx,
1095
1172
  dwfMinTextCssPx: options.dwfMinTextCssPx,
1096
1173
  dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,
1174
+ ...{ colorMode, monochromeColor },
1097
1175
  autoFit: true,
1098
1176
  canvasOptions,
1099
1177
  onLoadProgress: updateProgress,
@@ -1210,11 +1288,14 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
1210
1288
  resizeObserver.observe(stage);
1211
1289
  }
1212
1290
  syncUi();
1291
+ (_b = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _b === void 0 ? void 0 : _b.call(context, createFileViewerCadExportAdapter(() => viewer, context.filename, () => stage.querySelector('.dwfv-stage') || stage));
1213
1292
  void loadCad();
1214
1293
  return {
1215
1294
  $el: shell,
1216
1295
  unmount() {
1296
+ var _a;
1217
1297
  disposed = true;
1298
+ (_a = context === null || context === void 0 ? void 0 : context.registerExportAdapter) === null || _a === void 0 ? void 0 : _a.call(context, null);
1218
1299
  unregisterFileViewerViewStateProvider(shell);
1219
1300
  unregisterFileViewerZoomProvider(shell);
1220
1301
  abortController === null || abortController === void 0 ? void 0 : abortController.abort();
@@ -0,0 +1,15 @@
1
+ import type { FileViewerCadColorMode, FileViewerCadOptions } from '@file-viewer/core';
2
+ import type { CanvasViewerOptions } from '@flyfish-dev/cad-viewer';
3
+ export interface CadViewerColorModeAdapter {
4
+ setColorMode?: (mode: FileViewerCadColorMode, monochromeColor?: string) => void;
5
+ getColorMode?: () => FileViewerCadColorMode;
6
+ getMonochromeColor?: () => string | undefined;
7
+ setCanvasOptions?: (options: CanvasViewerOptions) => void;
8
+ isNativeRendererActive?: () => boolean;
9
+ }
10
+ export declare function normalizeFileViewerCadColorMode(value: unknown): FileViewerCadColorMode;
11
+ export declare function resolveFileViewerCadMonochromeColor(value: unknown, fallback?: string): string;
12
+ export declare function resolveFileViewerCadCanvasOptions(options: FileViewerCadOptions, mode: FileViewerCadColorMode): CanvasViewerOptions;
13
+ export declare function supportsCadViewerColorMode(value: unknown): value is CadViewerColorModeAdapter;
14
+ export declare function resolveCadViewerSourceDocument(viewer: unknown): unknown;
15
+ export declare function applyCadViewerColorMode(viewer: unknown, mode: FileViewerCadColorMode, monochromeColor: string, options?: FileViewerCadOptions): boolean;
@@ -0,0 +1,47 @@
1
+ export function normalizeFileViewerCadColorMode(value) {
2
+ return value === 'monochrome' ? 'monochrome' : 'source';
3
+ }
4
+ export function resolveFileViewerCadMonochromeColor(value, fallback = '#000000') {
5
+ if (typeof value === 'string' && value.trim())
6
+ return value.trim();
7
+ return fallback;
8
+ }
9
+ export function resolveFileViewerCadCanvasOptions(options, mode) {
10
+ return {
11
+ background: mode === 'monochrome' ? '#ffffff' : '#05070d',
12
+ foreground: mode === 'monochrome'
13
+ ? resolveFileViewerCadMonochromeColor(options.monochromeColor)
14
+ : '#f8fafc',
15
+ contrastMode: 'adaptive',
16
+ minColorContrast: 2.4,
17
+ showPageBounds: true,
18
+ showUnsupportedMarkers: true,
19
+ enableSpatialIndex: true,
20
+ maxVisibleTextLabels: 2400,
21
+ ...options.canvasOptions,
22
+ };
23
+ }
24
+ export function supportsCadViewerColorMode(value) {
25
+ return Boolean(value && typeof value.setColorMode === 'function');
26
+ }
27
+ export function resolveCadViewerSourceDocument(viewer) {
28
+ var _a, _b, _c;
29
+ const candidate = viewer;
30
+ return (_b = (_a = candidate === null || candidate === void 0 ? void 0 : candidate.getSourceDocument) === null || _a === void 0 ? void 0 : _a.call(candidate)) !== null && _b !== void 0 ? _b : (_c = candidate === null || candidate === void 0 ? void 0 : candidate.getDocument) === null || _c === void 0 ? void 0 : _c.call(candidate);
31
+ }
32
+ export function applyCadViewerColorMode(viewer, mode, monochromeColor, options) {
33
+ var _a, _b, _c;
34
+ if (!supportsCadViewerColorMode(viewer))
35
+ return false;
36
+ (_a = viewer.setColorMode) === null || _a === void 0 ? void 0 : _a.call(viewer, mode, monochromeColor);
37
+ if (options) {
38
+ const canvasOptions = resolveFileViewerCadCanvasOptions(options, mode);
39
+ // The native setter also forwards the canvas background to DWF. Keep an
40
+ // explicitly configured DWF background instead of overwriting it on toggle.
41
+ if (((_b = viewer.isNativeRendererActive) === null || _b === void 0 ? void 0 : _b.call(viewer)) && options.dwfBackground) {
42
+ canvasOptions.background = options.dwfBackground;
43
+ }
44
+ (_c = viewer.setCanvasOptions) === null || _c === void 0 ? void 0 : _c.call(viewer, canvasOptions);
45
+ }
46
+ return true;
47
+ }
@@ -0,0 +1,6 @@
1
+ import type { FileRenderExportAdapter } from '@file-viewer/core';
2
+ export interface CadCanvasCaptureAdapter {
3
+ captureCanvas?: () => Promise<HTMLCanvasElement>;
4
+ }
5
+ export declare function captureFileViewerCadCanvas(getViewer: () => CadCanvasCaptureAdapter | null): Promise<HTMLCanvasElement>;
6
+ export declare function createFileViewerCadExportAdapter(getViewer: () => CadCanvasCaptureAdapter | null, filename?: string, getPage?: () => HTMLElement): FileRenderExportAdapter;
package/dist/export.js ADDED
@@ -0,0 +1,28 @@
1
+ export async function captureFileViewerCadCanvas(getViewer) {
2
+ const viewer = getViewer();
3
+ if (!(viewer === null || viewer === void 0 ? void 0 : viewer.captureCanvas))
4
+ throw new Error('The CAD engine does not support canvas snapshots.');
5
+ const snapshot = await viewer.captureCanvas();
6
+ if (getViewer() !== viewer)
7
+ throw new Error('The CAD document changed during export.');
8
+ return snapshot;
9
+ }
10
+ export function createFileViewerCadExportAdapter(getViewer, filename = 'CAD drawing', getPage) {
11
+ return {
12
+ includeDocumentStyles: false,
13
+ getPrintMaskPages: getPage ? () => [getPage()] : undefined,
14
+ async toHtml() {
15
+ const snapshot = await captureFileViewerCadCanvas(getViewer);
16
+ const image = snapshot.ownerDocument.createElement('img');
17
+ image.src = snapshot.toDataURL('image/png');
18
+ image.alt = filename;
19
+ image.width = snapshot.width;
20
+ image.height = snapshot.height;
21
+ image.style.cssText = 'display:block;max-width:100%;height:auto;margin:0 auto;';
22
+ const page = snapshot.ownerDocument.createElement('div');
23
+ page.dataset.viewerPrintPageIndex = '0';
24
+ page.appendChild(image);
25
+ return page.outerHTML;
26
+ },
27
+ };
28
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { type FileRenderHandler, type FileViewerRenderedInstance, type FileViewerRendererPlugin, type RendererDefinition } from '@file-viewer/core';
2
+ export { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from './colorMode.js';
3
+ export type { CadViewerColorModeAdapter } from './colorMode.js';
2
4
  export declare const cadRendererDefinition: RendererDefinition;
3
5
  export declare const renderFileViewerCad: FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>;
4
6
  export declare const cadRenderer: FileViewerRendererPlugin<FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>>;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DEFAULT_RENDERER_DEFINITIONS, } from '@file-viewer/core';
2
+ export { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveCadViewerSourceDocument, resolveFileViewerCadMonochromeColor, supportsCadViewerColorMode, } from './colorMode.js';
2
3
  const cadDefinition = DEFAULT_RENDERER_DEFINITIONS.find(definition => definition.id === 'cad');
3
4
  if (!cadDefinition) {
4
5
  throw new Error('@file-viewer/renderer-cad could not locate the shared CAD format definition.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/renderer-cad",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Standalone CAD renderer plugin for File Viewer powered by @flyfish-dev/cad-viewer.",
@@ -56,8 +56,8 @@
56
56
  "LICENSE"
57
57
  ],
58
58
  "dependencies": {
59
- "@file-viewer/core": "3.0.1",
60
- "@flyfish-dev/cad-viewer": "0.8.0"
59
+ "@file-viewer/core": "3.0.3",
60
+ "@flyfish-dev/cad-viewer": "0.8.2"
61
61
  },
62
62
  "devDependencies": {
63
63
  "typescript": "^6.0.3"
@@ -65,6 +65,7 @@
65
65
  "license": "Apache-2.0",
66
66
  "scripts": {
67
67
  "build": "tsc -b tsconfig.json",
68
- "type-check": "tsc -b tsconfig.json"
68
+ "type-check": "tsc -b tsconfig.json",
69
+ "verify:color-mode": "node scripts/verify-color-mode.mjs"
69
70
  }
70
71
  }