@dtducas/wh-forge-viewer 2.0.0-beta.2 → 3.0.0-beta.1

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/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // Definitions by: Duong Tran Quang <https://github.com/DTDucas>
4
4
  /// <reference types="react" />
5
5
  declare module '@dtducas/wh-forge-viewer' {
6
- import type { ReactElement, ReactNode } from 'react';
6
+ import type { ReactNode } from 'react';
7
7
  /**
8
8
  * Supported file extensions for the Forge Viewer
9
9
  */
@@ -68,15 +68,15 @@ declare module '@dtducas/wh-forge-viewer' {
68
68
  export type TMarkupToolType =
69
69
  | 'arrow'
70
70
  | 'rectangle'
71
- | 'ellipse' // Circle tool
71
+ | 'ellipse' // Circle tool
72
72
  | 'cloud'
73
- | 'label' // Text tool
73
+ | 'label' // Text tool
74
74
  | 'freehand' // Pen tool
75
75
  | 'line'
76
76
  | 'polyline'
77
77
  | 'polycloud'
78
78
  | 'callout'
79
- | 'image'; // Image/Stamp tool
79
+ | 'image'; // Image/Stamp tool
80
80
 
81
81
  /**
82
82
  * Markup style configuration
@@ -264,7 +264,7 @@ declare module '@dtducas/wh-forge-viewer' {
264
264
  constructor(
265
265
  viewer: Autodesk.Viewing.GuiViewer3D,
266
266
  eventBus: any,
267
- config?: IDrawingManagerConfig
267
+ config?: IDrawingManagerConfig,
268
268
  );
269
269
  enterEditMode(): Promise<void>;
270
270
  leaveEditMode(): void;
@@ -287,26 +287,47 @@ declare module '@dtducas/wh-forge-viewer' {
287
287
 
288
288
  // Collaborative Markup API
289
289
  getMarkupData(viewableGUID: string): IMarkupDataExport;
290
- loadMarkupData(data: IMarkupDataExport, options?: ILoadMarkupDataOptions): Promise<void>;
291
- onMarkupChange(callback: OnMarkupChangeCallback): () => void;
292
- applyDelta(delta: IMarkupDelta & { compactElement?: IMarkupElementCompact }): boolean;
293
- applyBatch(elements: IMarkupElementCompact[], clearExisting?: boolean): number;
290
+ loadMarkupData(
291
+ data: IMarkupDataExport,
292
+ options?: ILoadMarkupDataOptions,
293
+ ): Promise<void>;
294
294
  getMarkupSVG(): string;
295
295
 
296
296
  // Real-time Collaboration Rendering APIs
297
- renderFromSVG(svgString: string, options?: { clearExisting?: boolean; layerId?: string }): number;
297
+ renderFromSVG(
298
+ svgString: string,
299
+ options?: { clearExisting?: boolean; layerId?: string },
300
+ ): number;
298
301
  mergeFromSVG(svgString: string, layerId?: string): number;
299
302
  clearForPageChange(viewableGUID: string): IMarkupDataExport;
300
- restoreAfterPageChange(data: IMarkupDataExport, options?: ILoadMarkupDataOptions): Promise<void>;
303
+ restoreAfterPageChange(
304
+ data: IMarkupDataExport,
305
+ options?: ILoadMarkupDataOptions,
306
+ ): Promise<void>;
301
307
 
302
308
  // SVG/JSON Conversion APIs
303
309
  getMarkupDataAsJson(viewableGUID: string): IJsonMarkupData;
304
- loadMarkupDataFromJson(jsonData: IJsonMarkupData, options?: ILoadMarkupDataOptions): Promise<void>;
310
+ loadMarkupDataFromJson(
311
+ jsonData: IJsonMarkupData,
312
+ options?: ILoadMarkupDataOptions,
313
+ ): Promise<void>;
305
314
 
306
315
  // PDF Export API
307
- exportPDFWithMarkup(pdfSource: Blob | string, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<IExportResult>;
308
- exportAndDownloadPDF(pdfSource: Blob | string, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<boolean>;
309
- exportCurrentPagePDF(pdfSource: Blob | string, pageIndex?: number, options?: IExportPdfOptions): Promise<IExportResult>;
316
+ exportPDFWithMarkup(
317
+ pdfSource: Blob | string,
318
+ markupsByPage: IPageMarkupData[],
319
+ options?: IExportPdfOptions,
320
+ ): Promise<IExportResult>;
321
+ exportAndDownloadPDF(
322
+ pdfSource: Blob | string,
323
+ markupsByPage: IPageMarkupData[],
324
+ options?: IExportPdfOptions,
325
+ ): Promise<boolean>;
326
+ exportCurrentPagePDF(
327
+ pdfSource: Blob | string,
328
+ pageIndex?: number,
329
+ options?: IExportPdfOptions,
330
+ ): Promise<IExportResult>;
310
331
 
311
332
  // User Presence API
312
333
  updateUserCursor(cursor: IUserCursor): void;
@@ -392,15 +413,37 @@ declare module '@dtducas/wh-forge-viewer' {
392
413
  export class PolycloudTool extends MarkupTool {}
393
414
  export class CalloutTool extends MarkupTool {}
394
415
  export class ImageTool extends MarkupTool {
395
- setImage(imageData: string, width: number, height: number, type?: 'base64' | 'svg'): void;
396
- getPendingImage(): { data: string; width: number; height: number; type: 'base64' | 'svg'; storageId?: string } | null;
416
+ setImage(
417
+ imageData: string,
418
+ width: number,
419
+ height: number,
420
+ type?: 'base64' | 'svg',
421
+ ): void;
422
+ getPendingImage(): {
423
+ data: string;
424
+ width: number;
425
+ height: number;
426
+ type: 'base64' | 'svg';
427
+ storageId?: string;
428
+ } | null;
397
429
  clearPendingImage(): void;
398
- loadImageFile(file: File, options?: { storeInIndexedDB?: boolean }): Promise<string | void>;
430
+ loadImageFile(
431
+ file: File,
432
+ options?: { storeInIndexedDB?: boolean },
433
+ ): Promise<string | void>;
399
434
  loadSVGFile(file: File): Promise<void>;
400
435
  // IndexedDB Storage Methods
401
436
  initializeStorage(): Promise<void>;
402
437
  getStorageService(): ImageStorageService | null;
403
- storeImage(imageData: string, metadata?: { fileName?: string; mimeType?: string; width?: number; height?: number }): Promise<string>;
438
+ storeImage(
439
+ imageData: string,
440
+ metadata?: {
441
+ fileName?: string;
442
+ mimeType?: string;
443
+ width?: number;
444
+ height?: number;
445
+ },
446
+ ): Promise<string>;
404
447
  getStoredImage(storageId: string): Promise<string | null>;
405
448
  hasStoredImage(storageId: string): Promise<boolean>;
406
449
  deleteStoredImage(storageId: string): Promise<boolean>;
@@ -434,37 +477,6 @@ declare module '@dtducas/wh-forge-viewer' {
434
477
  // Viewer Component Props
435
478
  // ========================================
436
479
 
437
- /**
438
- * Props for ViewerForgePDF component
439
- */
440
- export interface IViewerForgePDFProps {
441
- /**
442
- * URL/path to the document to load
443
- */
444
- filePath: string;
445
- /**
446
- * File extension (pdf, dwf, dwfx, gltf, glb)
447
- */
448
- fileExt: TSupportedFileExtension;
449
- /**
450
- * Toolbar visibility options
451
- * Controls which toolbar buttons and controls are displayed
452
- */
453
- toolbarOptions?: IToolbarOptions;
454
- /**
455
- * Callback to receive viewer instance when initialized
456
- */
457
- setViewer?: (viewer: Autodesk.Viewing.GuiViewer3D | null) => void;
458
- /**
459
- * Enable custom markup toolbar
460
- * @default false
461
- */
462
- enableCustomMarkups?: boolean;
463
- /**
464
- * Configuration for DrawingManager
465
- */
466
- markupConfig?: IDrawingManagerConfig;
467
- }
468
480
  /**
469
481
  * ViewerForgePDF - React component for displaying PDF and CAD files using Autodesk Forge Viewer
470
482
  *
@@ -543,153 +555,6 @@ declare module '@dtducas/wh-forge-viewer' {
543
555
  timestamp: number;
544
556
  }
545
557
 
546
- /**
547
- * Markup change delta for real-time sync
548
- */
549
- export interface IMarkupDelta {
550
- type: 'create' | 'update' | 'delete';
551
- markupId: string;
552
- data?: Partial<IMarkupItem>;
553
- timestamp: number;
554
- /** Compact element for JSON-based sync (attached when using serializer) */
555
- compactElement?: IMarkupElementCompact;
556
- }
557
-
558
- // ========================================
559
- // JSON-based Sync Types (Compact Format)
560
- // ========================================
561
-
562
- /**
563
- * Compact markup element format for real-time sync
564
- * ~80 bytes vs ~500 bytes for SVG strings
565
- */
566
- export interface IMarkupElementCompact {
567
- /** Unique markup ID */
568
- id: string;
569
- /** Markup type */
570
- type: string;
571
- /** Position in markup coordinates [x, y] */
572
- pos: [number, number];
573
- /** Size in markup coordinates [width, height] */
574
- size: [number, number];
575
- /** Rotation in radians */
576
- rot: number;
577
- /** Style properties (compact keys) */
578
- style: ICompactStyle;
579
- /** Shape-specific data */
580
- shape?: IShapeData;
581
- /** Version number for CRDT conflict resolution */
582
- version: number;
583
- /** Tombstone flag for deletion */
584
- deleted?: boolean;
585
- /** Timestamp (Unix epoch ms) */
586
- ts: number;
587
- /** Created by user ID */
588
- createdBy?: string;
589
- /** Modified by user ID */
590
- modifiedBy?: string;
591
- }
592
-
593
- /**
594
- * Compact style properties (short keys for minimal payload)
595
- */
596
- export interface ICompactStyle {
597
- /** Stroke color (hex) */
598
- sc?: string;
599
- /** Stroke width */
600
- sw?: number;
601
- /** Stroke opacity (0-1) */
602
- so?: number;
603
- /** Stroke dash array */
604
- sd?: string;
605
- /** Fill color (hex) */
606
- fc?: string;
607
- /** Fill opacity (0-1) */
608
- fo?: number;
609
- /** Font size */
610
- fs?: number;
611
- /** Font family */
612
- ff?: string;
613
- /** Font weight */
614
- fw?: string;
615
- /** Font style */
616
- fi?: string;
617
- }
618
-
619
- /**
620
- * Shape-specific data for different markup types
621
- */
622
- export interface IShapeData {
623
- /** Points array (flat: [x1,y1,x2,y2,...]) */
624
- points?: number[];
625
- /** Text content */
626
- text?: string;
627
- /** Image data URI */
628
- imageData?: string;
629
- /** Cloud arc count */
630
- arcCount?: number;
631
- /** Path data string */
632
- pathData?: string;
633
- /** Arrow head configuration */
634
- head?: { type: string; size: number };
635
- /** Arrow tail configuration */
636
- tail?: { type: string; size: number };
637
- }
638
-
639
- /**
640
- * Serialize a Forge Markup object to compact JSON format
641
- */
642
- export function serializeMarkup(
643
- markup: any,
644
- userId?: string
645
- ): IMarkupElementCompact | null;
646
-
647
- /**
648
- * Deserialize compact style to Forge-compatible style object
649
- */
650
- export function deserializeStyle(compact: ICompactStyle): Record<string, any>;
651
-
652
- /**
653
- * Expand flat points array to {x, y} objects
654
- */
655
- export function expandPoints(flatPoints: number[]): Array<{ x: number; y: number }>;
656
-
657
- /**
658
- * Calculate byte size of serialized markup
659
- */
660
- export function getSerializedSize(compact: IMarkupElementCompact): number;
661
-
662
- /**
663
- * Render a compact markup element to the Forge Viewer canvas
664
- */
665
- export function renderMarkupElement(
666
- element: IMarkupElementCompact,
667
- markupsCore: any,
668
- mode?: 'create' | 'update'
669
- ): boolean;
670
-
671
- /**
672
- * Delete a markup element from the canvas
673
- */
674
- export function deleteMarkupElement(
675
- elementId: string,
676
- markupsCore: any
677
- ): boolean;
678
-
679
- /**
680
- * Render multiple markup elements as a batch
681
- */
682
- export function renderMarkupBatch(
683
- elements: IMarkupElementCompact[],
684
- markupsCore: any,
685
- clearExisting?: boolean
686
- ): number;
687
-
688
- /**
689
- * Clear all markups from the canvas
690
- */
691
- export function clearAllMarkups(markupsCore: any): void;
692
-
693
558
  /**
694
559
  * Options for loadMarkupData method
695
560
  */
@@ -697,11 +562,6 @@ declare module '@dtducas/wh-forge-viewer' {
697
562
  mode?: 'replace' | 'merge';
698
563
  }
699
564
 
700
- /**
701
- * Callback type for markup change subscription
702
- */
703
- export type OnMarkupChangeCallback = (delta: IMarkupDelta) => void;
704
-
705
565
  // ========================================
706
566
  // User Presence API Types
707
567
  // ========================================
@@ -817,9 +677,21 @@ declare module '@dtducas/wh-forge-viewer' {
817
677
  */
818
678
  export class MarkupExportService {
819
679
  constructor();
820
- exportPDFWithMarkup(originalPdfBlob: Blob, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<IExportResult>;
821
- exportPDFWithMarkupMap(originalPdfBlob: Blob, markupsByPage: Map<number, string>, options?: IExportPdfOptions): Promise<IExportResult>;
822
- exportAndDownload(originalPdfBlob: Blob, markupsByPage: IPageMarkupData[], options?: IExportPdfOptions): Promise<boolean>;
680
+ exportPDFWithMarkup(
681
+ originalPdfBlob: Blob,
682
+ markupsByPage: IPageMarkupData[],
683
+ options?: IExportPdfOptions,
684
+ ): Promise<IExportResult>;
685
+ exportPDFWithMarkupMap(
686
+ originalPdfBlob: Blob,
687
+ markupsByPage: Map<number, string>,
688
+ options?: IExportPdfOptions,
689
+ ): Promise<IExportResult>;
690
+ exportAndDownload(
691
+ originalPdfBlob: Blob,
692
+ markupsByPage: IPageMarkupData[],
693
+ options?: IExportPdfOptions,
694
+ ): Promise<boolean>;
823
695
  downloadPdf(blob: Blob, filename?: string): void;
824
696
  static fetchPdfBlob(pdfSource: Blob | string): Promise<Blob>;
825
697
  }
@@ -838,7 +710,11 @@ declare module '@dtducas/wh-forge-viewer' {
838
710
  * ```
839
711
  */
840
712
  export class SvgToPdfConverter {
841
- drawSvgOnPdfPage(svgString: string, pdfPage: any, options: ISvgToPdfOptions): Promise<void>;
713
+ drawSvgOnPdfPage(
714
+ svgString: string,
715
+ pdfPage: any,
716
+ options: ISvgToPdfOptions,
717
+ ): Promise<void>;
842
718
  }
843
719
 
844
720
  // ========================================
@@ -848,7 +724,12 @@ declare module '@dtducas/wh-forge-viewer' {
848
724
  /**
849
725
  * Toolbar button identifiers
850
726
  */
851
- export type TToolbarButtonId = 'pan' | 'docBrowser' | 'download' | 'markup' | 'pagination';
727
+ export type TToolbarButtonId =
728
+ | 'pan'
729
+ | 'docBrowser'
730
+ | 'download'
731
+ | 'markup'
732
+ | 'pagination';
852
733
 
853
734
  /**
854
735
  * Toolbar button visibility configuration
@@ -927,7 +808,10 @@ declare module '@dtducas/wh-forge-viewer' {
927
808
  export class ImageStorageService {
928
809
  static getInstance(config?: IImageStorageConfig): ImageStorageService;
929
810
  initialize(): Promise<void>;
930
- storeImage(imageData: string, metadata?: Partial<IStoredImage>): Promise<string>;
811
+ storeImage(
812
+ imageData: string,
813
+ metadata?: Partial<IStoredImage>,
814
+ ): Promise<string>;
931
815
  getImage(id: string): Promise<IStoredImage | null>;
932
816
  hasImage(id: string): Promise<boolean>;
933
817
  deleteImage(id: string): Promise<boolean>;
@@ -945,16 +829,12 @@ declare module '@dtducas/wh-forge-viewer' {
945
829
  * JSON markup data format for database storage
946
830
  * Coordinates are stored as-is (no scaling)
947
831
  */
832
+ /** @deprecated Use canvas-scene/2 (ICanvasMarkupSceneV2) for markup persistence. */
948
833
  export interface IJsonMarkupData {
949
- /** Format version for JSON schema compatibility */
950
834
  version: string;
951
- /** Viewable identifier - provided by the consuming app (any string format) */
952
835
  viewableGUID: string;
953
- /** Array of compact markup elements */
954
- elements: IMarkupElementCompact[];
955
- /** Optional metadata for custom data */
956
- metadata?: Record<string, any>;
957
- /** Timestamp when data was created (Unix epoch ms) */
836
+ elements: unknown[];
837
+ metadata?: Record<string, unknown>;
958
838
  timestamp: number;
959
839
  }
960
840
 
@@ -1112,13 +992,15 @@ declare module '@dtducas/wh-forge-viewer' {
1112
992
  */
1113
993
  export function validateMarkupCoordinates(
1114
994
  point: IPoint2D,
1115
- markupsCore: any
995
+ markupsCore: any,
1116
996
  ): ICoordinateValidationResult;
1117
997
 
1118
998
  /**
1119
999
  * Get coordinate space metadata for debugging
1120
1000
  */
1121
- export function getCoordinateSpaceInfo(markupsCore: any): ICoordinateSpaceInfo;
1001
+ export function getCoordinateSpaceInfo(
1002
+ markupsCore: any,
1003
+ ): ICoordinateSpaceInfo;
1122
1004
 
1123
1005
  /**
1124
1006
  * Convert coordinates between different coordinate spaces
@@ -1127,11 +1009,707 @@ declare module '@dtducas/wh-forge-viewer' {
1127
1009
  point: IPoint2D,
1128
1010
  from: TCoordinateSpace,
1129
1011
  to: TCoordinateSpace,
1130
- markupsCore: any
1012
+ markupsCore: any,
1131
1013
  ): IPoint2D;
1132
1014
 
1133
1015
  /**
1134
1016
  * Check if the coordinate system is normalized (zoom/pan independent)
1135
1017
  */
1136
1018
  export function isCoordinateSystemNormalized(markupsCore: any): boolean;
1019
+
1020
+ // ========================================
1021
+ // Advanced Features (v3.0.0)
1022
+ // ========================================
1023
+
1024
+ // ── Markup Engine Adapter Pattern ──────────────────────────────────────────
1025
+
1026
+ /**
1027
+ * Engine capabilities advertised by each IMarkupEngine implementation.
1028
+ */
1029
+ export interface IMarkupEngineCapabilities {
1030
+ supportsCollaboration: boolean;
1031
+ supportsBezierArcs: boolean;
1032
+ supportsImages: boolean;
1033
+ supportsExportPDF: boolean;
1034
+ supportsImportSVG: boolean;
1035
+ }
1036
+
1037
+ /**
1038
+ * Serialized engine data payload for persistence (V2: canvas-scene/2 only).
1039
+ */
1040
+ export interface IMarkupEngineData {
1041
+ format: 'canvas-scene/2';
1042
+ version: string;
1043
+ payload: string;
1044
+ }
1045
+
1046
+ /**
1047
+ * Engine type selector prop value.
1048
+ */
1049
+ export type TMarkupEngineType = 'canvas';
1050
+
1051
+ /**
1052
+ * Markup engine interface for the canvas-scene/2 engine.
1053
+ */
1054
+ export interface IMarkupEngine {
1055
+ initialize(): Promise<void>;
1056
+ destroy(): void;
1057
+ activateTool(tool: string): void;
1058
+ deactivateTool(): void;
1059
+ getActiveTool(): string | null;
1060
+ addShape(shape: unknown): void;
1061
+ removeShape(shape: unknown): void;
1062
+ clearLayer(): void;
1063
+ getShapes(): unknown[];
1064
+ undo(): void;
1065
+ redo(): void;
1066
+ getData(): IMarkupEngineData;
1067
+ loadData(data: IMarkupEngineData): void;
1068
+ selectShape(shape: unknown): void;
1069
+ getSelectedShape(): unknown | null;
1070
+ onSelectionChange(cb: (shape: unknown | null) => void): () => void;
1071
+ onShapeAdded(cb: (shape: unknown) => void): () => void;
1072
+ onShapeModified(cb: (shape: unknown) => void): () => void;
1073
+ onShapeRemoved(cb: (shape: unknown) => void): () => void;
1074
+ readonly capabilities: IMarkupEngineCapabilities;
1075
+ }
1076
+
1077
+ // ── Custom Geometry ────────────────────────────────────────────────────────
1078
+
1079
+ /**
1080
+ * Options for SceneBuilderService.createModel().
1081
+ */
1082
+ export interface ISceneModelOptions {
1083
+ /**
1084
+ * When true, only addGeometry/addMaterial/addFragment can be used.
1085
+ * When false (default), addMesh is also available.
1086
+ */
1087
+ conserveMemory?: boolean;
1088
+ modelNameOverride?: string;
1089
+ }
1090
+
1091
+ /**
1092
+ * Builder API returned by SceneBuilderService.createModel().
1093
+ * Use to add geometry, materials, and fragments to a custom model.
1094
+ */
1095
+ export interface IModelBuilderAPI {
1096
+ addMaterial(name: string, material: unknown): void;
1097
+ addGeometry(geometry: unknown): number;
1098
+ addFragment(
1099
+ geomIdOrGeom: number | unknown,
1100
+ material: unknown | string,
1101
+ transform: unknown,
1102
+ ): number;
1103
+ /** Only available when conserveMemory: false */
1104
+ addMesh(mesh: unknown): boolean;
1105
+ }
1106
+
1107
+ /**
1108
+ * Manages viewer.overlays scenes for decoration and transient visuals.
1109
+ *
1110
+ * **Use for:** non-selectable decoration, transient highlights, helper visuals.
1111
+ * **Do NOT use for:** objects requiring selection or dbId interaction.
1112
+ * See SceneBuilderService for those use cases.
1113
+ *
1114
+ * @example
1115
+ * ```typescript
1116
+ * const overlay = new OverlayManager(viewer);
1117
+ * overlay.createScene('highlights');
1118
+ * const sphere = overlay.createSphere(0.5, 0xff0000);
1119
+ * overlay.addMesh(sphere, 'highlights');
1120
+ * ```
1121
+ */
1122
+ export class OverlayManager {
1123
+ constructor(viewer: Autodesk.Viewing.GuiViewer3D);
1124
+ createScene(name: string): void;
1125
+ removeScene(name: string): void;
1126
+ hasScene(name: string): boolean;
1127
+ clearScene(name: string): void;
1128
+ addMesh(mesh: unknown, sceneName: string): void;
1129
+ removeMesh(mesh: unknown, sceneName: string): void;
1130
+ createSphere(radius: number, color: number): unknown;
1131
+ createBox(
1132
+ width: number,
1133
+ height: number,
1134
+ depth: number,
1135
+ color: number,
1136
+ ): unknown;
1137
+ createLine(from: unknown, to: unknown, color: number): unknown;
1138
+ dispose(): void;
1139
+ }
1140
+
1141
+ /**
1142
+ * Creates model-like geometry using Autodesk.Viewing.SceneBuilder.
1143
+ *
1144
+ * **Use for:** objects that need selection, dbId, model aggregate events.
1145
+ * **Do NOT use for:** simple decoration. Use OverlayManager instead.
1146
+ * **Limitations:** no 2D models, no property database, no instance tree.
1147
+ *
1148
+ * @example
1149
+ * ```typescript
1150
+ * const svc = new SceneBuilderService(viewer);
1151
+ * await svc.initialize();
1152
+ * const builder = await svc.createModel();
1153
+ * builder.addMaterial('red', material);
1154
+ * const geomId = builder.addGeometry(geometry);
1155
+ * builder.addFragment(geomId, 'red', transform);
1156
+ * ```
1157
+ */
1158
+ export class SceneBuilderService {
1159
+ constructor(viewer: Autodesk.Viewing.GuiViewer3D);
1160
+ initialize(): Promise<void>;
1161
+ createModel(options?: ISceneModelOptions): Promise<IModelBuilderAPI>;
1162
+ removeModel(builder: IModelBuilderAPI): void;
1163
+ isInitialized(): boolean;
1164
+ destroy(): void;
1165
+ }
1166
+
1167
+ // ── Property Database ──────────────────────────────────────────────────────
1168
+
1169
+ /**
1170
+ * A single resolved property entry from the property database.
1171
+ */
1172
+ export interface IPropertyEntry {
1173
+ name: string;
1174
+ value: string | number | boolean;
1175
+ category?: string;
1176
+ dataType?: number;
1177
+ units?: string;
1178
+ }
1179
+
1180
+ /**
1181
+ * Attribute definition from the property database.
1182
+ */
1183
+ export interface IAttributeDef {
1184
+ id: number;
1185
+ name: string;
1186
+ category?: string;
1187
+ dataType?: number;
1188
+ units?: string;
1189
+ }
1190
+
1191
+ /**
1192
+ * Query the Autodesk Forge Viewer property database (runs in web worker).
1193
+ *
1194
+ * ⚠️ `executeQuery` functions run in a web worker. They must be self-contained:
1195
+ * - No external variable references or imports
1196
+ * - No `this` context
1197
+ * - Return value must be JSON-serializable
1198
+ *
1199
+ * @example
1200
+ * ```typescript
1201
+ * const svc = new PropertyDatabaseService(viewer);
1202
+ * const count = await svc.executeQuery(function(pdb) {
1203
+ * var n = 0;
1204
+ * pdb.enumObjects(function() { n++; });
1205
+ * return n;
1206
+ * });
1207
+ * ```
1208
+ */
1209
+ export class PropertyDatabaseService {
1210
+ constructor(viewer: Autodesk.Viewing.GuiViewer3D);
1211
+ /** Returns false for GLTF/GLB models which have no property database. */
1212
+ isAvailable(): boolean;
1213
+ executeQuery<T>(userFunction: (pdb: unknown) => T): Promise<T>;
1214
+ getObjectProperties(dbId: number): Promise<IPropertyEntry[]>;
1215
+ findObjectsByProperty(
1216
+ propertyName: string,
1217
+ value: string | number | boolean,
1218
+ ): Promise<number[]>;
1219
+ getAllAttributes(): Promise<IAttributeDef[]>;
1220
+ }
1221
+
1222
+ // ── Selective Loading ──────────────────────────────────────────────────────
1223
+
1224
+ /**
1225
+ * Axis-aligned bounding box spatial primitive for spatial queries.
1226
+ */
1227
+ export interface ISpatialPrimitive {
1228
+ aabox: [
1229
+ minX: number,
1230
+ minY: number,
1231
+ minZ: number,
1232
+ maxX: number,
1233
+ maxY: number,
1234
+ maxZ: number,
1235
+ ];
1236
+ }
1237
+
1238
+ /**
1239
+ * Spatial query for selective loading.
1240
+ * Only applicable for SVF2 + loadDocumentNode() workflow.
1241
+ */
1242
+ export interface ISpatialQuery {
1243
+ $intersects?: [ISpatialPrimitive];
1244
+ $encloses?: [ISpatialPrimitive, unknown?, number?];
1245
+ $extent?: [number];
1246
+ $not?: ISpatialQuery;
1247
+ $or?: ISpatialQuery[];
1248
+ $and?: ISpatialQuery[];
1249
+ }
1250
+
1251
+ /**
1252
+ * Property-based query for selective loading.
1253
+ * Keys use '?' prefix for property names.
1254
+ * Example: `{ '?Base Constraint': "'Level 1'" }`
1255
+ */
1256
+ export interface IPropertyQuery {
1257
+ $or?: IPropertyQuery[];
1258
+ $and?: IPropertyQuery[];
1259
+ $not?: IPropertyQuery;
1260
+ [key: string]: unknown;
1261
+ }
1262
+
1263
+ /**
1264
+ * Load filter for selective loading.
1265
+ *
1266
+ * ⚠️ Only applicable for SVF2 + loadDocumentNode() workflow (cloud-hosted URN models).
1267
+ * Will throw UnsupportedCapabilityError for Local env (PDF/DWF direct file loading).
1268
+ * Check `enhancedViewer.capabilities.selectiveLoading` before using.
1269
+ */
1270
+ export interface ILoadFilter {
1271
+ spatial_query?: ISpatialQuery;
1272
+ property_query?: IPropertyQuery;
1273
+ root_condition?: 'and' | 'or';
1274
+ /** 'exact' is default but slower; 'immediate' is faster but less precise */
1275
+ spatial_behavior?: 'immediate' | 'exact';
1276
+ }
1277
+
1278
+ // ── Viewer Preset Manager ─────────────────────────────────────────────────
1279
+
1280
+ /**
1281
+ * Built-in viewer preset types.
1282
+ * AEC = Architecture, Engineering, Construction settings.
1283
+ * Navis = Navisworks-compatible settings.
1284
+ */
1285
+ export type TBuiltinPreset = 'AEC' | 'Navis';
1286
+
1287
+ /**
1288
+ * Viewer settings preset configuration.
1289
+ * Passed to ViewerPresetManager.applyPreset() or as `viewerPreset` prop.
1290
+ */
1291
+ export interface IViewerPresetSettings {
1292
+ name?: string;
1293
+ settings?: Record<string, boolean | number | string>;
1294
+ extensions?: {
1295
+ load?: string[];
1296
+ unload?: string[];
1297
+ };
1298
+ }
1299
+
1300
+ /**
1301
+ * Manages viewer behavior presets via Autodesk.Viewing.Profile / ProfileSettings.
1302
+ *
1303
+ * **Note:** This is NOT the Autodesk User Profile API. It controls viewer rendering
1304
+ * and behavior settings (ambient shadows, ground reflection, etc.).
1305
+ *
1306
+ * @example
1307
+ * ```typescript
1308
+ * const pm = new ViewerPresetManager(viewer);
1309
+ * pm.applyBuiltinPreset('AEC');
1310
+ * pm.cloneAndApply('AEC', { settings: { ambientShadow: false } });
1311
+ * ```
1312
+ */
1313
+ export class ViewerPresetManager {
1314
+ constructor(viewer: Autodesk.Viewing.GuiViewer3D);
1315
+ applyPreset(settings: IViewerPresetSettings): void;
1316
+ applyBuiltinPreset(type: TBuiltinPreset): void;
1317
+ cloneAndApply(
1318
+ baseType: TBuiltinPreset,
1319
+ overrides: Partial<IViewerPresetSettings>,
1320
+ ): void;
1321
+ registerFileTypePreset(
1322
+ fileType: string,
1323
+ settings: IViewerPresetSettings,
1324
+ ): void;
1325
+ resetToDefault(): void;
1326
+ getCurrentPreset(): unknown;
1327
+ }
1328
+
1329
+ // ── Capability Gating ──────────────────────────────────────────────────────
1330
+
1331
+ /**
1332
+ * Capabilities advertised by the enhanced viewer object.
1333
+ * Access via `enhancedViewer.capabilities`.
1334
+ */
1335
+ export interface IViewerCapabilities {
1336
+ /** true only for SVF2 + loadDocumentNode workflow; false for Local PDF/DWF */
1337
+ selectiveLoading: boolean;
1338
+ /** true when enableSceneBuilder=true and extension loaded successfully */
1339
+ sceneBuilder: boolean;
1340
+ /** true when canvas markup engine is initialized */
1341
+ canvas: boolean;
1342
+ /** true when model has a property database (false for GLTF/GLB) */
1343
+ propertyDatabase: boolean;
1344
+ }
1345
+
1346
+ // ── Markups Panel ─────────────────────────────────────────────────────────
1347
+
1348
+ /** Single markup item displayed in the MarkupsPanel */
1349
+ export interface IMarkupPanelItem {
1350
+ /** Unique entity identifier */
1351
+ id: string;
1352
+ /**
1353
+ * Markup kind — e.g. 'arrow' | 'rectangle' | 'ellipse' | 'polygon' |
1354
+ * 'polyline' | 'line' | 'cloud' | 'polycloud' | 'text' | 'callout' |
1355
+ * 'freehand' | 'highlighter' | 'image'
1356
+ */
1357
+ kind: string;
1358
+ /** Optional label override; defaults to capitalised kind */
1359
+ title?: string;
1360
+ /** Display name of the creator */
1361
+ authorName?: string;
1362
+ /** Company / organisation of the creator */
1363
+ authorCompany?: string;
1364
+ /** Unix epoch milliseconds */
1365
+ createdAt: number;
1366
+ /** Whether the markup has been published/saved to the server */
1367
+ isPublished?: boolean;
1368
+ /** Override icon stroke colour (default: #ec4a41) */
1369
+ color?: string;
1370
+ }
1371
+
1372
+ // ── User Presence ─────────────────────────────────────────────────────────
1373
+
1374
+ /** Online user presence info for sidebar presence indicator */
1375
+ export interface IUserPresence {
1376
+ userId: string;
1377
+ userName?: string;
1378
+ color: string;
1379
+ isActive: boolean;
1380
+ lastSeen: number;
1381
+ currentPageIndex?: number;
1382
+ avatarUrl?: string;
1383
+ }
1384
+
1385
+ // ── Collab Patch Types ────────────────────────────────────────────────────
1386
+
1387
+ export type TPatchOp = 'create' | 'update' | 'delete';
1388
+
1389
+ export interface ICanvasPatch {
1390
+ op: TPatchOp;
1391
+ shapeId: string;
1392
+ /** Full shape data (omitted for delete) */
1393
+ data?: unknown;
1394
+ /** ISO-8601 timestamp */
1395
+ timestamp: string;
1396
+ actorId: string;
1397
+ version: number;
1398
+ nonce: number;
1399
+ viewableGuid: string;
1400
+ patchId?: string;
1401
+ }
1402
+
1403
+ export interface ICanvasMarkupSceneV2 {
1404
+ format: 'canvas-scene/2';
1405
+ version: '2.0';
1406
+ viewableGuid: string;
1407
+ shapes: unknown[];
1408
+ viewportBounds?: unknown;
1409
+ createdAt: string;
1410
+ updatedAt: string;
1411
+ }
1412
+
1413
+ // ── Collab Adapter ────────────────────────────────────────────────────────
1414
+
1415
+ /** Identifies a collaboration room scoped to a single viewable page. */
1416
+ export interface ICollabRoom {
1417
+ viewableGuid: string;
1418
+ roomId: string;
1419
+ }
1420
+
1421
+ /**
1422
+ * Result of `ICollabAdapter.fetchScene`.
1423
+ * - `mode: 'full'` — full scene replacement; call `api.loadScene(scene)`.
1424
+ * - `mode: 'delta'` — incremental; call `api.applyPatches(deltaPatches)`.
1425
+ */
1426
+ export interface IFetchSceneResult {
1427
+ mode: 'full' | 'delta';
1428
+ scene: ICanvasMarkupSceneV2 | null;
1429
+ deltaPatches?: ICanvasPatch[];
1430
+ }
1431
+
1432
+ /** Transport-agnostic collab adapter — implement with Socket.IO, WebRTC, etc. */
1433
+ export interface ICollabAdapter {
1434
+ broadcastPatches(patches: ICanvasPatch[], room: ICollabRoom): Promise<void>;
1435
+ fetchScene(room: ICollabRoom): Promise<IFetchSceneResult>;
1436
+ onRemotePatches(room: ICollabRoom, cb: (patches: ICanvasPatch[]) => void): () => void;
1437
+ joinRoom(room: ICollabRoom): void | Promise<void>;
1438
+ leaveRoom(room: ICollabRoom): void | Promise<void>;
1439
+ /** Optional: subscribe to server-initiated full-scene replacements (e.g. version restore). */
1440
+ onRemoteSceneReplace?(room: ICollabRoom, cb: (scene: ICanvasMarkupSceneV2) => void): () => void;
1441
+ /**
1442
+ * Optional: drain the durable outbox for a room.
1443
+ * Called after bootstrap to replay unACKed patches from a previous session.
1444
+ */
1445
+ drainOutboxForRoom?(room: ICollabRoom): Promise<ICanvasPatch[]>;
1446
+ /** Optional: register a callback fired on transport reconnect for auto re-join. */
1447
+ onReconnect?(cb: () => void): () => void;
1448
+ }
1449
+
1450
+ export type TCollabStatus = 'idle' | 'joining' | 'connected' | 'disconnected' | 'error';
1451
+
1452
+ export interface ICollabStatusEvent {
1453
+ status: TCollabStatus;
1454
+ roomId?: string;
1455
+ error?: Error;
1456
+ }
1457
+
1458
+ // ── Updated ViewerForgePDF Props ──────────────────────────────────────────
1459
+
1460
+ /**
1461
+ * Props for ViewerForgePDF component (v3.0.0)
1462
+ */
1463
+ export interface IViewerForgePDFProps {
1464
+ /** URL/path to the document to load */
1465
+ filePath: string;
1466
+ /** File extension (pdf, dwf, dwfx, gltf, glb) */
1467
+ fileExt: TSupportedFileExtension;
1468
+ /** Toolbar visibility options */
1469
+ toolbarOptions?: IToolbarOptions;
1470
+ /** Callback to receive enhanced viewer instance when initialized */
1471
+ setViewer?: (viewer: Autodesk.Viewing.GuiViewer3D | null) => void;
1472
+ /** Enable custom markup toolbar (canvas engine). */
1473
+ enableCustomMarkups?: boolean;
1474
+ /** Configuration for DrawingManager. */
1475
+ markupConfig?: IDrawingManagerConfig;
1476
+ /**
1477
+ * Markup engine — only `'canvas'` (canvas-scene/2) is supported.
1478
+ * @default 'canvas' when enableCustomMarkups=true
1479
+ */
1480
+ markupEngine?: TMarkupEngineType;
1481
+ /**
1482
+ * Enable Autodesk.Viewing.SceneBuilder for model-like custom geometry.
1483
+ * Exposes `enhancedViewer.sceneBuilder` when true.
1484
+ * @default false
1485
+ */
1486
+ enableSceneBuilder?: boolean;
1487
+ /**
1488
+ * Load filter for selective loading.
1489
+ * ⚠️ Only applicable for SVF2 + loadDocumentNode() workflow.
1490
+ * Has no effect for Local env (PDF/DWF); check `capabilities.selectiveLoading`.
1491
+ */
1492
+ loadFilter?: ILoadFilter;
1493
+ /** Apply a viewer behavior preset on initialization. */
1494
+ viewerPreset?: IViewerPresetSettings;
1495
+ /**
1496
+ * Online users to display in the sidebar presence indicator.
1497
+ * Pass from your collaboration layer (e.g. WebSocket/Supabase Presence).
1498
+ * @default []
1499
+ */
1500
+ onlineUsers?: IUserPresence[];
1501
+ /**
1502
+ * Markup items to display in the Markups side panel.
1503
+ * Build from your collaborative state (IMarkupElementCompact → IMarkupPanelItem).
1504
+ * @default []
1505
+ */
1506
+ markupItems?: IMarkupPanelItem[];
1507
+ /** Called when user clicks a markup row in the Markups panel. */
1508
+ onMarkupItemClick?: (id: string) => void;
1509
+ /**
1510
+ * Called when a shape is selected or deselected on the canvas.
1511
+ * Receives the shape `entityId` on selection, or `null` on deselect / toolbar close.
1512
+ * Use this to look up per-shape metadata (author, timestamps) from your state store
1513
+ * and pass it back via `selectedShapeInfo`.
1514
+ */
1515
+ onShapeSelect?: (entityId: string | null) => void;
1516
+ /**
1517
+ * Metadata to display in the Markup Edit Drawer history section for the
1518
+ * currently selected shape. All fields are pre-formatted display strings so
1519
+ * the library stays format-agnostic.
1520
+ *
1521
+ * When `historyEntries` is provided it takes priority over `createdBy`/`updatedBy`
1522
+ * and renders the full timeline (newest-first, as ordered by the host app).
1523
+ * @example
1524
+ * selectedShapeInfo={{
1525
+ * historyEntries: [
1526
+ * 'Edited by Bob on 31 Mar 2026, 01:28',
1527
+ * 'Created by Alice on 17 Mar 2026, 09:40',
1528
+ * ],
1529
+ * }}
1530
+ * @example
1531
+ * // Legacy fallback (still supported)
1532
+ * selectedShapeInfo={{
1533
+ * createdBy: 'Created by Alice on 17 Mar 2026, 09:40',
1534
+ * updatedBy: 'Updated by Bob on 18 Mar 2026, 11:20',
1535
+ * }}
1536
+ */
1537
+ selectedShapeInfo?: {
1538
+ createdBy?: string;
1539
+ updatedBy?: string;
1540
+ /**
1541
+ * Full history timeline for the selected shape, newest-first.
1542
+ * Each entry is a pre-formatted string (e.g. 'Edited by Bob on 31 Mar 2026, 01:28').
1543
+ * When present, supersedes `createdBy`/`updatedBy`.
1544
+ */
1545
+ historyEntries?: string[];
1546
+ };
1547
+ /**
1548
+ * Enable canvas markup debug logger.
1549
+ * Logs shape lifecycle, selection, property changes, history, and scene operations
1550
+ * to the browser console. Exposes `window.__WH_MARKUP_DEBUG__` helpers at runtime.
1551
+ * @default false
1552
+ */
1553
+ enableMarkupDebug?: boolean;
1554
+ /** Load the Autodesk.BIM360.Minimap extension — shows a floating 2D minimap panel. Default: false */
1555
+ enableMinimap?: boolean;
1556
+ // ── Collaborative Markup ────────────────────────────────────────────────
1557
+ /**
1558
+ * Transport adapter for real-time collaborative markup.
1559
+ * Implement `ICollabAdapter` using Socket.IO, WebRTC, or any transport.
1560
+ * When provided (with `collabActorId` and `collabDrawingId`), the library
1561
+ * creates a `CanvasCollabSessionService` internally and manages room lifecycle.
1562
+ * If omitted, markup runs in offline mode.
1563
+ */
1564
+ collabAdapter?: ICollabAdapter;
1565
+ /**
1566
+ * Current user's actor ID for LWW conflict resolution and echo prevention.
1567
+ * Required when `collabAdapter` is provided.
1568
+ */
1569
+ collabActorId?: string;
1570
+ /**
1571
+ * Drawing/document identifier used to construct room IDs.
1572
+ * Room ID format: `${collabDrawingId}:${viewableGuid}`
1573
+ * Required when `collabAdapter` is provided.
1574
+ */
1575
+ collabDrawingId?: string;
1576
+ /**
1577
+ * Canonical viewable GUID from the host app (e.g. from `/pages` endpoint).
1578
+ * When provided, the library immediately joins the collab room for this page.
1579
+ * Changes to this prop trigger a room re-join. If null/undefined, collab stays idle.
1580
+ */
1581
+ collabViewableGuid?: string | null;
1582
+ /**
1583
+ * Called when collaborative session status changes.
1584
+ * @param evt - Status event with status, optional roomId, optional error
1585
+ */
1586
+ onCollabStatusChange?: (evt: ICollabStatusEvent) => void;
1587
+ /**
1588
+ * Called when a collaborative session error occurs.
1589
+ */
1590
+ onCollabError?: (error: Error) => void;
1591
+
1592
+ // ── Export with Markup ──────────────────────────────────────────────────
1593
+ /**
1594
+ * Optional override for the page list used during export.
1595
+ *
1596
+ * When provided, these GUIDs are passed to `fetchAllScenesForExport` instead of
1597
+ * the Forge runtime GUIDs — eliminating the namespace mismatch that occurs when
1598
+ * the BE persists scenes by canonical page UUIDs (different from Forge page GUIDs).
1599
+ *
1600
+ * Should return the same ordered page list you received from the `/pages` registration
1601
+ * endpoint, mapped by `pageIndex`.
1602
+ *
1603
+ * @example
1604
+ * ```tsx
1605
+ * getExportViewablePages={() =>
1606
+ * pagesRef.current.map(p => ({ pageIndex: p.pageIndex, viewableGuid: p.viewableGUID }))
1607
+ * }
1608
+ * ```
1609
+ */
1610
+ getExportViewablePages?: () => Array<{ pageIndex: number; viewableGuid: string }>;
1611
+
1612
+ /**
1613
+ * Async callback to fetch canvas-scene/2 data for ALL pages from the server
1614
+ * before merging markup into the exported PDF.
1615
+ *
1616
+ * Input: Array of every viewable GUID in the document.
1617
+ * Output: Record mapping each GUID to its scene or `null` (no markup on that page).
1618
+ *
1619
+ * Rules enforced by the library:
1620
+ * - Every GUID in the input must appear as a key in the output; missing keys throw.
1621
+ * - Non-null scenes must have `format === 'canvas-scene/2'` and `viewableGuid` matching the key.
1622
+ * - If all scenes are null/empty → original PDF is downloaded unchanged.
1623
+ * - If this prop is omitted → "Export with Markup" is a no-op (logs a warning).
1624
+ *
1625
+ * @example
1626
+ * ```tsx
1627
+ * fetchAllScenesForExport={async (guids) => {
1628
+ * const res = await api.getMarkupScenes({ viewableGuids: guids });
1629
+ * // res: { [guid]: ICanvasMarkupSceneV2 | null }
1630
+ * return res;
1631
+ * }}
1632
+ * ```
1633
+ */
1634
+ fetchAllScenesForExport?: (
1635
+ viewableGuids: string[],
1636
+ ) => Promise<Record<string, ICanvasMarkupSceneV2 | null>>;
1637
+
1638
+ /**
1639
+ * Called at key points in the export lifecycle.
1640
+ * Use this to show loading spinners, progress indicators, and error toasts.
1641
+ *
1642
+ * @example
1643
+ * ```tsx
1644
+ * onExportStatus={(evt) => {
1645
+ * if (evt.status === 'start') setExporting(true);
1646
+ * if (evt.status === 'success') setExporting(false);
1647
+ * if (evt.status === 'error') { setExporting(false); toast.error(evt.error?.message); }
1648
+ * }}
1649
+ * ```
1650
+ */
1651
+ onExportStatus?: (event: IExportStatusEvent) => void;
1652
+
1653
+ /**
1654
+ * Optional TTF font configuration for text export.
1655
+ *
1656
+ * Override when the default NotoSans TTF URLs are blocked by a CSP or network
1657
+ * policy. Must point to valid `.ttf`/`.otf` files — WOFF2 causes invisible text
1658
+ * in pdf-lib and should not be used.
1659
+ *
1660
+ * If omitted, the library fetches NotoSans TTF from Google Fonts CDN with an
1661
+ * 8 s timeout, falling back to Helvetica (Latin-only) on failure.
1662
+ *
1663
+ * @example
1664
+ * ```tsx
1665
+ * <ViewerForgePDF
1666
+ * exportFontConfig={{
1667
+ * fontUrls: ['https://my-cdn.example.com/fonts/noto-sans.ttf'],
1668
+ * fetchTimeoutMs: 5000,
1669
+ * }}
1670
+ * />
1671
+ * ```
1672
+ */
1673
+ exportFontConfig?: IExportFontConfig;
1674
+ }
1675
+
1676
+ /**
1677
+ * Font configuration for PDF text export.
1678
+ * Controls which TTF font file(s) are used when rendering text markups into PDF.
1679
+ */
1680
+ export interface IExportFontConfig {
1681
+ /**
1682
+ * Ordered list of TTF/OTF font URLs to try (primary first, then fallbacks).
1683
+ * WOFF2 is not supported — only TTF/OTF files are accepted.
1684
+ * @default NotoSans Regular from Google Fonts CDN
1685
+ */
1686
+ fontUrls?: string[];
1687
+ /**
1688
+ * Per-URL fetch timeout in milliseconds.
1689
+ * @default 8000
1690
+ */
1691
+ fetchTimeoutMs?: number;
1692
+ }
1693
+
1694
+ /**
1695
+ * Export lifecycle event emitted by the canvas export pipeline.
1696
+ */
1697
+ export interface IExportStatusEvent {
1698
+ /** Current stage of the export. */
1699
+ status: 'start' | 'success' | 'error';
1700
+ /** Present only when `status === 'error'`. */
1701
+ error?: Error;
1702
+ }
1703
+
1704
+ /**
1705
+ * Canvas-scene/2 markup scene for a single page.
1706
+ * Used as the element type in the `fetchAllScenesForExport` return value.
1707
+ */
1708
+ export interface ICanvasMarkupSceneV2 {
1709
+ format: 'canvas-scene/2';
1710
+ viewableGuid: string;
1711
+ shapes: unknown[];
1712
+ viewportBounds?: { x: number; y: number; width: number; height: number };
1713
+ [key: string]: unknown;
1714
+ }
1137
1715
  }