@file-viewer/renderer-cad 3.0.0 → 3.0.2

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,17 @@ 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
+ ```ts
58
+ {
59
+ cad: {
60
+ colorMode: 'monochrome',
61
+ monochromeColor: '#000000',
62
+ showColorModeToggle: true,
63
+ },
64
+ }
65
+ ```
package/README.md CHANGED
@@ -49,3 +49,17 @@ 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
+ ```ts
58
+ {
59
+ cad: {
60
+ colorMode: 'monochrome',
61
+ monochromeColor: '#000000',
62
+ showColorModeToggle: true,
63
+ },
64
+ }
65
+ ```
package/dist/cad.js CHANGED
@@ -1,10 +1,13 @@
1
1
  import { CadViewer, inferEntityKind, } from '@flyfish-dev/cad-viewer';
2
2
  import { resolveFileViewerCadAssetUrls, resolveFileViewerRuntimeAssetBaseUrl, } from '@file-viewer/core/assets';
3
3
  import { createFileViewerViewStateChange, createFileViewerViewStateChangeEmitter, createFileViewerTranslator, createFileViewerZoomChangeEmitter, registerFileViewerViewStateProvider, registerFileViewerZoomProvider, resolveFileViewerLocale, unregisterFileViewerViewStateProvider, unregisterFileViewerZoomProvider, } from '@file-viewer/core';
4
+ import { applyCadViewerColorMode, normalizeFileViewerCadColorMode, resolveFileViewerCadMonochromeColor, resolveCadViewerSourceDocument, supportsCadViewerColorMode, } from './colorMode.js';
4
5
  const CAD_WORKER_TIMEOUT = 120000;
5
6
  const CAD_DEFAULT_FIT_PADDING = 0.92;
6
7
  const CAD_BOUNDS_EPSILON = 1e-9;
7
8
  const CAD_BEST_FIT_OUTLIER_RATIO = 8;
9
+ const CAD_NATIVE_MIN_ZOOM_RATIO = 0.05;
10
+ const CAD_NATIVE_MAX_ZOOM_RATIO = 64;
8
11
  const cadStyle = `
9
12
  .cad-shell{display:flex;height:100%;min-height:100%;flex-direction:column;background:#f5f7fb;color:#142335}
10
13
  .cad-shell *{box-sizing:border-box}
@@ -12,6 +15,9 @@ const cadStyle = `
12
15
  .cad-tools,.cad-meta{display:flex;align-items:center;gap:8px}
13
16
  .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}
14
17
  .cad-tools button:hover{background:rgba(31,150,110,.14);color:#0f8f62}
18
+ .cad-tools button.cad-color-mode{min-width:52px;padding:0 10px;font-size:12px}
19
+ .cad-tools button.cad-color-mode[aria-pressed='true']{background:#0f172a;color:#fff}
20
+ .cad-tools button.cad-color-mode:disabled{cursor:not-allowed;opacity:.46}
15
21
  .cad-zoom,.cad-meta span{color:#64748b;font-size:12px;font-weight:800;letter-spacing:0}
16
22
  .cad-meta span{border-radius:999px;padding:5px 9px;background:rgba(15,23,42,.06)}
17
23
  .cad-body{display:grid;min-height:0;flex:1;grid-template-columns:minmax(176px,236px) minmax(0,1fr) minmax(142px,176px);background:#eef2f7}
@@ -198,6 +204,105 @@ const getCadDocumentBaseUrl = (target) => {
198
204
  : 'file:///';
199
205
  };
200
206
  const CAD_DWG_WORKER_FILENAME = 'file-viewer-input.dwg';
207
+ const getCadPinchSnapshot = (points) => {
208
+ const [first, second] = Array.from(points.values());
209
+ if (!first || !second) {
210
+ return null;
211
+ }
212
+ return {
213
+ center: {
214
+ x: (first.x + second.x) / 2,
215
+ y: (first.y + second.y) / 2,
216
+ },
217
+ distance: Math.hypot(second.x - first.x, second.y - first.y),
218
+ };
219
+ };
220
+ /**
221
+ * The bundled CAD engines currently treat every touch pointer as the same
222
+ * drag. Coordinate two touch pointers before their target listeners run so a
223
+ * pinch becomes one anchored zoom operation instead of two competing pans.
224
+ */
225
+ const registerCadPinchZoom = (surface, onStart, onZoom) => {
226
+ const points = new Map();
227
+ let previous = null;
228
+ let suppressDragUntilRelease = false;
229
+ const suppressPointerEvent = (event) => {
230
+ event.preventDefault();
231
+ event.stopImmediatePropagation();
232
+ };
233
+ const handlePointerDown = (event) => {
234
+ if (event.pointerType !== 'touch') {
235
+ return;
236
+ }
237
+ points.set(event.pointerId, { x: event.clientX, y: event.clientY });
238
+ try {
239
+ surface.setPointerCapture(event.pointerId);
240
+ }
241
+ catch {
242
+ // Synthetic browser harness events may not create an active pointer.
243
+ }
244
+ if (points.size < 2) {
245
+ return;
246
+ }
247
+ suppressDragUntilRelease = true;
248
+ previous = getCadPinchSnapshot(points);
249
+ onStart();
250
+ suppressPointerEvent(event);
251
+ };
252
+ const handlePointerMove = (event) => {
253
+ if (event.pointerType !== 'touch' || !points.has(event.pointerId)) {
254
+ return;
255
+ }
256
+ points.set(event.pointerId, { x: event.clientX, y: event.clientY });
257
+ if (!suppressDragUntilRelease) {
258
+ return;
259
+ }
260
+ if (points.size >= 2) {
261
+ const current = getCadPinchSnapshot(points);
262
+ if (previous && current && previous.distance > 0 && current.distance > 0) {
263
+ onZoom({
264
+ center: current.center,
265
+ deltaX: current.center.x - previous.center.x,
266
+ deltaY: current.center.y - previous.center.y,
267
+ factor: Math.min(2, Math.max(0.5, current.distance / previous.distance)),
268
+ });
269
+ }
270
+ previous = current;
271
+ }
272
+ suppressPointerEvent(event);
273
+ };
274
+ const handlePointerEnd = (event) => {
275
+ if (event.pointerType !== 'touch' || !points.has(event.pointerId)) {
276
+ return;
277
+ }
278
+ points.delete(event.pointerId);
279
+ previous = points.size >= 2 ? getCadPinchSnapshot(points) : null;
280
+ if (points.size === 0) {
281
+ suppressDragUntilRelease = false;
282
+ }
283
+ try {
284
+ if (surface.hasPointerCapture(event.pointerId)) {
285
+ surface.releasePointerCapture(event.pointerId);
286
+ }
287
+ }
288
+ catch {
289
+ // The underlying engine may already have released this pointer.
290
+ }
291
+ // Do not stop pointerup/cancel: the engine must clear the single-pointer
292
+ // drag that began before the second finger started the pinch.
293
+ };
294
+ surface.addEventListener('pointerdown', handlePointerDown, { capture: true });
295
+ surface.addEventListener('pointermove', handlePointerMove, { capture: true });
296
+ surface.addEventListener('pointerup', handlePointerEnd, { capture: true });
297
+ surface.addEventListener('pointercancel', handlePointerEnd, { capture: true });
298
+ return () => {
299
+ surface.removeEventListener('pointerdown', handlePointerDown, { capture: true });
300
+ surface.removeEventListener('pointermove', handlePointerMove, { capture: true });
301
+ surface.removeEventListener('pointerup', handlePointerEnd, { capture: true });
302
+ surface.removeEventListener('pointercancel', handlePointerEnd, { capture: true });
303
+ points.clear();
304
+ };
305
+ };
201
306
  const createEmptyCadBounds = () => ({
202
307
  minX: Number.POSITIVE_INFINITY,
203
308
  minY: Number.POSITIVE_INFINITY,
@@ -547,6 +652,8 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
547
652
  const options = ((_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.cad) || {};
548
653
  const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
549
654
  const locale = resolveFileViewerLocale(context === null || context === void 0 ? void 0 : context.options);
655
+ const monochromeColor = resolveFileViewerCadMonochromeColor(options.monochromeColor);
656
+ let colorMode = normalizeFileViewerCadColorMode(options.colorMode);
550
657
  let status = 'loading';
551
658
  let progressMessage = t('cad.state.loadingViewer');
552
659
  let errorMessage = '';
@@ -557,7 +664,10 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
557
664
  let viewer = null;
558
665
  let resizeObserver = null;
559
666
  let abortController = null;
667
+ let disposeCadPinch = null;
668
+ let disposeNativeInteractions = null;
560
669
  let fitViewActive = true;
670
+ let nativeZoomRatio = 1;
561
671
  let disposed = false;
562
672
  const style = createStyle();
563
673
  const shell = createElement('div', 'cad-shell');
@@ -568,16 +678,18 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
568
678
  const zoomOutButton = createElement('button', undefined, '-');
569
679
  const zoomText = createElement('span', 'cad-zoom', '100%');
570
680
  const zoomInButton = createElement('button', undefined, '+');
681
+ const colorModeButton = createElement('button', 'cad-color-mode');
682
+ colorModeButton.hidden = options.showColorModeToggle === false;
571
683
  const meta = createElement('div', 'cad-meta');
572
684
  const typeMeta = createElement('span', undefined, normalizedType.toUpperCase());
573
685
  const backendMeta = createElement('span', undefined, 'AUTO');
574
- [fitButton, zoomOutButton, zoomInButton].forEach(button => {
686
+ [fitButton, zoomOutButton, zoomInButton, colorModeButton].forEach(button => {
575
687
  button.type = 'button';
576
688
  });
577
689
  fitButton.title = t('cad.toolbar.fit');
578
690
  zoomOutButton.title = t('cad.toolbar.zoomOut');
579
691
  zoomInButton.title = t('cad.toolbar.zoomIn');
580
- tools.append(fitButton, zoomOutButton, zoomText, zoomInButton);
692
+ tools.append(fitButton, zoomOutButton, zoomText, zoomInButton, colorModeButton);
581
693
  meta.append(typeMeta, backendMeta);
582
694
  toolbar.append(tools, meta);
583
695
  const body = createElement('div', 'cad-body without-layers');
@@ -615,8 +727,11 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
615
727
  };
616
728
  const getWarnings = () => (loadResult === null || loadResult === void 0 ? void 0 : loadResult.warnings) || (loadResult === null || loadResult === void 0 ? void 0 : loadResult.document.warnings) || [];
617
729
  const getZoomPercent = () => {
618
- var _a, _b, _c;
619
- const zoom = (_c = (_a = viewState === null || viewState === void 0 ? void 0 : viewState.zoomPercent) !== null && _a !== void 0 ? _a : (_b = viewer === null || viewer === void 0 ? void 0 : viewer.getZoomPercent) === null || _b === void 0 ? void 0 : _b.call(viewer)) !== null && _c !== void 0 ? _c : 100;
730
+ var _a, _b, _c, _d;
731
+ if ((_a = viewer === null || viewer === void 0 ? void 0 : viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
732
+ return Math.round(nativeZoomRatio * 100);
733
+ }
734
+ const zoom = (_d = (_b = viewState === null || viewState === void 0 ? void 0 : viewState.zoomPercent) !== null && _b !== void 0 ? _b : (_c = viewer === null || viewer === void 0 ? void 0 : viewer.getZoomPercent) === null || _c === void 0 ? void 0 : _c.call(viewer)) !== null && _d !== void 0 ? _d : 100;
620
735
  return Number.isFinite(zoom) ? Math.round(zoom) : 100;
621
736
  };
622
737
  const getCadZoomState = () => {
@@ -642,6 +757,8 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
642
757
  status,
643
758
  view: viewState ? { ...viewState } : null,
644
759
  backend: renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend,
760
+ colorMode,
761
+ monochromeColor: colorMode === 'monochrome' ? monochromeColor : undefined,
645
762
  layerCount: layers.length,
646
763
  visibleLayers: layers
647
764
  .filter(layer => layer.isVisible !== false && !layer.isFrozen)
@@ -655,6 +772,98 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
655
772
  }
656
773
  return state;
657
774
  };
775
+ const clampNativeZoomRatio = (ratio) => {
776
+ return Math.min(CAD_NATIVE_MAX_ZOOM_RATIO, Math.max(CAD_NATIVE_MIN_ZOOM_RATIO, ratio));
777
+ };
778
+ const notifyNativeZoomChange = (action) => {
779
+ cadZoomEmitter.emit();
780
+ syncState();
781
+ emitCadViewStateChange(action, 'user');
782
+ };
783
+ const bindNativeCadInteractions = () => {
784
+ disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
785
+ disposeNativeInteractions = null;
786
+ const surface = nativeHost.querySelector('.dwfv-overlay-canvas');
787
+ if (!surface) {
788
+ return;
789
+ }
790
+ let notificationQueued = false;
791
+ const queueNativeZoomChange = (action) => {
792
+ if (notificationQueued) {
793
+ return;
794
+ }
795
+ notificationQueued = true;
796
+ queueMicrotask(() => {
797
+ var _a;
798
+ notificationQueued = false;
799
+ if (!disposed && ((_a = viewer === null || viewer === void 0 ? void 0 : viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer))) {
800
+ notifyNativeZoomChange(action);
801
+ }
802
+ });
803
+ };
804
+ const applyNativeZoomFactor = (factor, action) => {
805
+ if (!Number.isFinite(factor) || factor <= 0) {
806
+ return;
807
+ }
808
+ nativeZoomRatio = clampNativeZoomRatio(nativeZoomRatio * factor);
809
+ queueNativeZoomChange(action);
810
+ };
811
+ const handleNativeClick = (event) => {
812
+ const eventTarget = event.target;
813
+ const button = eventTarget instanceof Element ? eventTarget.closest('button') : null;
814
+ if (!button || !nativeHost.contains(button)) {
815
+ return;
816
+ }
817
+ const label = (button.textContent || '').trim();
818
+ if (label === '+') {
819
+ applyNativeZoomFactor(1.25, 'zoom-in');
820
+ }
821
+ else if (label === '-' || label === '−') {
822
+ applyNativeZoomFactor(0.8, 'zoom-out');
823
+ }
824
+ else if (/适应|fit|reset/i.test(label)) {
825
+ nativeZoomRatio = 1;
826
+ queueNativeZoomChange('zoom-reset');
827
+ }
828
+ };
829
+ const handleNativeWheel = (event) => {
830
+ const rect = surface.getBoundingClientRect();
831
+ const delta = event.deltaMode === WheelEvent.DOM_DELTA_LINE
832
+ ? event.deltaY * 16
833
+ : event.deltaMode === WheelEvent.DOM_DELTA_PAGE
834
+ ? event.deltaY * Math.max(1, rect.height)
835
+ : event.deltaY;
836
+ applyNativeZoomFactor(Math.exp(-delta * 0.0015), 'cad-view-change');
837
+ };
838
+ const handleNativePageChange = (event) => {
839
+ if (event.target instanceof HTMLSelectElement && nativeHost.contains(event.target)) {
840
+ nativeZoomRatio = 1;
841
+ queueNativeZoomChange('zoom-reset');
842
+ }
843
+ };
844
+ const disposePinch = registerCadPinchZoom(surface, () => {
845
+ fitViewActive = false;
846
+ }, ({ center, factor }) => {
847
+ const deltaY = -Math.log(factor) / 0.0015;
848
+ surface.dispatchEvent(new WheelEvent('wheel', {
849
+ bubbles: true,
850
+ cancelable: true,
851
+ clientX: center.x,
852
+ clientY: center.y,
853
+ deltaMode: WheelEvent.DOM_DELTA_PIXEL,
854
+ deltaY,
855
+ }));
856
+ });
857
+ nativeHost.addEventListener('click', handleNativeClick);
858
+ nativeHost.addEventListener('change', handleNativePageChange);
859
+ surface.addEventListener('wheel', handleNativeWheel);
860
+ disposeNativeInteractions = () => {
861
+ disposePinch();
862
+ nativeHost.removeEventListener('click', handleNativeClick);
863
+ nativeHost.removeEventListener('change', handleNativePageChange);
864
+ surface.removeEventListener('wheel', handleNativeWheel);
865
+ };
866
+ };
658
867
  const syncInspector = () => {
659
868
  const summary = loadResult === null || loadResult === void 0 ? void 0 : loadResult.summary;
660
869
  const rows = [
@@ -686,12 +895,15 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
686
895
  : layer.name;
687
896
  button.setAttribute('aria-pressed', String(layerVisible));
688
897
  const color = createElement('span', 'cad-layer-color');
689
- if (typeof layer.color === 'string') {
898
+ if (colorMode === 'monochrome') {
899
+ color.style.background = monochromeColor;
900
+ }
901
+ else if (typeof layer.color === 'string') {
690
902
  color.style.background = layer.color;
691
903
  }
692
904
  button.append(color, createElement('span', undefined, layer.name));
693
905
  button.addEventListener('click', () => {
694
- const document = viewer === null || viewer === void 0 ? void 0 : viewer.getDocument();
906
+ const document = resolveCadViewerSourceDocument(viewer);
695
907
  if (!document) {
696
908
  return;
697
909
  }
@@ -718,6 +930,15 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
718
930
  const syncState = () => {
719
931
  zoomText.textContent = `${getZoomPercent()}%`;
720
932
  backendMeta.textContent = ((renderStats === null || renderStats === void 0 ? void 0 : renderStats.backend) || 'auto').toUpperCase();
933
+ const colorModeSupported = supportsCadViewerColorMode(viewer);
934
+ colorModeButton.disabled = status !== 'ready' || !colorModeSupported;
935
+ colorModeButton.setAttribute('aria-pressed', String(colorMode === 'monochrome'));
936
+ colorModeButton.textContent = t(colorMode === 'monochrome'
937
+ ? 'cad.toolbar.monochrome'
938
+ : 'cad.toolbar.colorSource');
939
+ colorModeButton.title = t(colorMode === 'monochrome'
940
+ ? 'cad.toolbar.colorSource'
941
+ : 'cad.toolbar.monochrome');
721
942
  state.hidden = status === 'ready';
722
943
  state.classList.toggle('error', status === 'error');
723
944
  if (status === 'loading') {
@@ -744,6 +965,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
744
965
  return false;
745
966
  }
746
967
  if ((_a = viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
968
+ nativeZoomRatio = 1;
747
969
  viewer.fit();
748
970
  return true;
749
971
  }
@@ -854,6 +1076,17 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
854
1076
  fitButton.addEventListener('click', () => fitToView());
855
1077
  zoomInButton.addEventListener('click', zoomIn);
856
1078
  zoomOutButton.addEventListener('click', zoomOut);
1079
+ colorModeButton.addEventListener('click', () => {
1080
+ const previousMode = colorMode;
1081
+ colorMode = colorMode === 'monochrome' ? 'source' : 'monochrome';
1082
+ if (!applyCadViewerColorMode(viewer, colorMode, monochromeColor)) {
1083
+ colorMode = previousMode;
1084
+ syncState();
1085
+ return;
1086
+ }
1087
+ syncUi();
1088
+ emitCadViewStateChange('cad-view-change', 'user');
1089
+ });
857
1090
  const createViewer = () => {
858
1091
  var _a, _b, _c, _d, _e, _f, _g;
859
1092
  const { wasmPath, workerUrl, dwfWasmUrl } = resolveFileViewerCadAssetUrls(options, getCadDocumentBaseUrl(target));
@@ -894,6 +1127,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
894
1127
  dwfMaxOverviewStrokeCssPx: options.dwfMaxOverviewStrokeCssPx,
895
1128
  dwfMinTextCssPx: options.dwfMinTextCssPx,
896
1129
  dwfMinFilledAreaCssPx: options.dwfMinFilledAreaCssPx,
1130
+ ...{ colorMode, monochromeColor },
897
1131
  autoFit: true,
898
1132
  canvasOptions,
899
1133
  onLoadProgress: updateProgress,
@@ -918,6 +1152,19 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
918
1152
  syncState();
919
1153
  },
920
1154
  });
1155
+ disposeCadPinch === null || disposeCadPinch === void 0 ? void 0 : disposeCadPinch();
1156
+ const renderer = nextViewer.renderer;
1157
+ disposeCadPinch = registerCadPinchZoom(nextViewer.canvas, () => {
1158
+ fitViewActive = false;
1159
+ }, ({ center, deltaX, deltaY, factor }) => {
1160
+ var _a, _b;
1161
+ const rect = nextViewer.canvas.getBoundingClientRect();
1162
+ (_a = renderer.panByScreenDelta) === null || _a === void 0 ? void 0 : _a.call(renderer, deltaX, deltaY);
1163
+ (_b = renderer.zoom) === null || _b === void 0 ? void 0 : _b.call(renderer, factor, {
1164
+ x: center.x - rect.left,
1165
+ y: center.y - rect.top,
1166
+ });
1167
+ });
921
1168
  if (options.preloadDwg !== false && normalizedType === 'dwg') {
922
1169
  void nextViewer.preloadDwg({ wasmPath, workerUrl }).catch(() => {
923
1170
  // 预热失败不阻断真实加载,loadBuffer 会返回完整错误上下文。
@@ -926,6 +1173,7 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
926
1173
  return nextViewer;
927
1174
  };
928
1175
  const loadCad = async () => {
1176
+ var _a;
929
1177
  status = 'loading';
930
1178
  progressMessage = t('cad.state.parsing');
931
1179
  errorMessage = '';
@@ -934,6 +1182,9 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
934
1182
  viewState = null;
935
1183
  layers = [];
936
1184
  fitViewActive = true;
1185
+ nativeZoomRatio = 1;
1186
+ disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
1187
+ disposeNativeInteractions = null;
937
1188
  syncUi();
938
1189
  abortController === null || abortController === void 0 ? void 0 : abortController.abort();
939
1190
  const controller = new AbortController();
@@ -956,6 +1207,9 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
956
1207
  loadResult = restoreLoadResultSourceName(result);
957
1208
  layers = collectLayers(result);
958
1209
  status = 'ready';
1210
+ if ((_a = viewer.isNativeRendererActive) === null || _a === void 0 ? void 0 : _a.call(viewer)) {
1211
+ bindNativeCadInteractions();
1212
+ }
959
1213
  syncUi();
960
1214
  queueMicrotask(() => {
961
1215
  applyCadFit();
@@ -999,6 +1253,10 @@ export default async function renderCad(buffer, target, type = 'dxf', context) {
999
1253
  unregisterFileViewerZoomProvider(shell);
1000
1254
  abortController === null || abortController === void 0 ? void 0 : abortController.abort();
1001
1255
  abortController = null;
1256
+ disposeCadPinch === null || disposeCadPinch === void 0 ? void 0 : disposeCadPinch();
1257
+ disposeCadPinch = null;
1258
+ disposeNativeInteractions === null || disposeNativeInteractions === void 0 ? void 0 : disposeNativeInteractions();
1259
+ disposeNativeInteractions = null;
1002
1260
  resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
1003
1261
  resizeObserver = null;
1004
1262
  viewer === null || viewer === void 0 ? void 0 : viewer.destroy();
@@ -0,0 +1,11 @@
1
+ import type { FileViewerCadColorMode } from '@file-viewer/core';
2
+ export interface CadViewerColorModeAdapter {
3
+ setColorMode?: (mode: FileViewerCadColorMode, monochromeColor?: string) => void;
4
+ getColorMode?: () => FileViewerCadColorMode;
5
+ getMonochromeColor?: () => string | undefined;
6
+ }
7
+ export declare function normalizeFileViewerCadColorMode(value: unknown): FileViewerCadColorMode;
8
+ export declare function resolveFileViewerCadMonochromeColor(value: unknown, fallback?: string): string;
9
+ export declare function supportsCadViewerColorMode(value: unknown): value is CadViewerColorModeAdapter;
10
+ export declare function resolveCadViewerSourceDocument(viewer: unknown): unknown;
11
+ export declare function applyCadViewerColorMode(viewer: unknown, mode: FileViewerCadColorMode, monochromeColor: string): boolean;
@@ -0,0 +1,23 @@
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 supportsCadViewerColorMode(value) {
10
+ return Boolean(value && typeof value.setColorMode === 'function');
11
+ }
12
+ export function resolveCadViewerSourceDocument(viewer) {
13
+ var _a, _b, _c;
14
+ const candidate = viewer;
15
+ 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);
16
+ }
17
+ export function applyCadViewerColorMode(viewer, mode, monochromeColor) {
18
+ var _a;
19
+ if (!supportsCadViewerColorMode(viewer))
20
+ return false;
21
+ (_a = viewer.setColorMode) === null || _a === void 0 ? void 0 : _a.call(viewer, mode, monochromeColor);
22
+ return true;
23
+ }
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.0",
3
+ "version": "3.0.2",
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.0",
60
- "@flyfish-dev/cad-viewer": "0.8.0"
59
+ "@file-viewer/core": "3.0.2",
60
+ "@flyfish-dev/cad-viewer": "0.8.1"
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
  }