@dtducas/wh-forge-viewer 1.0.8-beta → 2.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 { FC } from 'react';
6
+ import type { ReactElement, ReactNode } from 'react';
7
7
  /**
8
8
  * Supported file extensions for the Forge Viewer
9
9
  */
@@ -43,6 +43,10 @@ declare module '@dtducas/wh-forge-viewer' {
43
43
  setTool(toolName: string): void;
44
44
  toolbar: any;
45
45
  model: any;
46
+ /** The WebGL canvas element used for rendering */
47
+ canvas: HTMLCanvasElement;
48
+ /** The viewer's DOM container element */
49
+ container: HTMLElement;
46
50
  }
47
51
  export interface Extension {
48
52
  load(): boolean;
@@ -54,6 +58,382 @@ declare module '@dtducas/wh-forge-viewer' {
54
58
  export const TOOLBAR_CREATED_EVENT: string;
55
59
  }
56
60
  }
61
+ // ========================================
62
+ // Drawing Types
63
+ // ========================================
64
+
65
+ /**
66
+ * Supported markup tool types
67
+ */
68
+ export type TMarkupToolType =
69
+ | 'arrow'
70
+ | 'rectangle'
71
+ | 'ellipse' // Circle tool
72
+ | 'cloud'
73
+ | 'label' // Text tool
74
+ | 'freehand' // Pen tool
75
+ | 'line'
76
+ | 'polyline'
77
+ | 'polycloud'
78
+ | 'callout'
79
+ | 'image'; // Image/Stamp tool
80
+
81
+ /**
82
+ * Markup style configuration
83
+ */
84
+ export interface IMarkupStyle {
85
+ strokeColor: string;
86
+ strokeWidth: number;
87
+ strokeOpacity: number;
88
+ fillColor: string;
89
+ fillOpacity: number;
90
+ }
91
+
92
+ /**
93
+ * Markup data structure
94
+ */
95
+ export interface IMarkupData {
96
+ version: string;
97
+ markups: any[];
98
+ metadata?: {
99
+ createdAt: string;
100
+ modifiedAt: string;
101
+ };
102
+ }
103
+
104
+ /**
105
+ * DrawingManager configuration
106
+ */
107
+ export interface IDrawingManagerConfig {
108
+ autoEnterEditMode?: boolean;
109
+ defaultTool?: TMarkupToolType;
110
+ defaultStyles?: Partial<IMarkupStyle>;
111
+ }
112
+
113
+ /**
114
+ * MarkupToolbar component props
115
+ */
116
+ export interface IMarkupToolbarProps {
117
+ drawingManager: DrawingManager;
118
+ onClose?: () => void;
119
+ position?: 'top' | 'bottom';
120
+ theme?: 'light' | 'dark';
121
+ }
122
+
123
+ // ========================================
124
+ // Property Panel Types
125
+ // ========================================
126
+
127
+ /**
128
+ * Property control types
129
+ */
130
+ export type TPropertyControlType =
131
+ | 'color'
132
+ | 'slider'
133
+ | 'select'
134
+ | 'button-group'
135
+ | 'toggle'
136
+ | 'action-button';
137
+
138
+ /**
139
+ * Property value types
140
+ */
141
+ export type TPropertyValue = string | number | boolean;
142
+
143
+ /**
144
+ * Property option for select/button-group controls
145
+ */
146
+ export interface IPropertyOption {
147
+ value: string | number;
148
+ label: string;
149
+ icon?: ReactNode;
150
+ tooltip?: string;
151
+ }
152
+
153
+ /**
154
+ * Base property definition
155
+ */
156
+ export interface IPropertyDefinition {
157
+ key: string;
158
+ label: string;
159
+ controlType: TPropertyControlType;
160
+ defaultValue: TPropertyValue;
161
+ category: 'stroke' | 'fill' | 'style' | 'text' | 'layer' | 'action';
162
+ tooltip?: string;
163
+ }
164
+
165
+ /**
166
+ * Color property
167
+ */
168
+ export interface IColorProperty extends IPropertyDefinition {
169
+ controlType: 'color';
170
+ defaultValue: string;
171
+ presetColors?: string[];
172
+ }
173
+
174
+ /**
175
+ * Slider property
176
+ */
177
+ export interface ISliderProperty extends IPropertyDefinition {
178
+ controlType: 'slider';
179
+ defaultValue: number;
180
+ min: number;
181
+ max: number;
182
+ step: number;
183
+ marks?: Record<number, string>;
184
+ }
185
+
186
+ /**
187
+ * Select property
188
+ */
189
+ export interface ISelectProperty extends IPropertyDefinition {
190
+ controlType: 'select';
191
+ defaultValue: string | number;
192
+ options: IPropertyOption[];
193
+ }
194
+
195
+ /**
196
+ * Button group property
197
+ */
198
+ export interface IButtonGroupProperty extends IPropertyDefinition {
199
+ controlType: 'button-group';
200
+ defaultValue: string | number;
201
+ options: IPropertyOption[];
202
+ exclusive?: boolean;
203
+ }
204
+
205
+ /**
206
+ * Toggle property
207
+ */
208
+ export interface IToggleProperty extends IPropertyDefinition {
209
+ controlType: 'toggle';
210
+ defaultValue: boolean;
211
+ }
212
+
213
+ /**
214
+ * Action button property
215
+ */
216
+ export interface IActionButtonProperty extends IPropertyDefinition {
217
+ controlType: 'action-button';
218
+ defaultValue: never;
219
+ action: string;
220
+ icon?: ReactNode;
221
+ variant?: 'default' | 'danger' | 'primary';
222
+ }
223
+
224
+ /**
225
+ * Union type of all property types
226
+ */
227
+ export type TProperty =
228
+ | IColorProperty
229
+ | ISliderProperty
230
+ | ISelectProperty
231
+ | IButtonGroupProperty
232
+ | IToggleProperty
233
+ | IActionButtonProperty;
234
+
235
+ /**
236
+ * Tool property configuration
237
+ */
238
+ export interface IToolPropertyConfig {
239
+ toolType: TMarkupToolType;
240
+ displayName: string;
241
+ properties: TProperty[];
242
+ onPropertyChange?: (key: string, value: TPropertyValue) => void;
243
+ onAction?: (action: string) => void;
244
+ }
245
+
246
+ /**
247
+ * PropertyPanel component props
248
+ */
249
+ export interface IPropertyPanelProps {
250
+ config: IToolPropertyConfig | null;
251
+ values: Record<string, TPropertyValue>;
252
+ onPropertyChange: (key: string, value: TPropertyValue) => void;
253
+ onAction: (action: string) => void;
254
+ visible?: boolean;
255
+ position?: 'left' | 'right';
256
+ theme?: 'light' | 'dark';
257
+ }
258
+
259
+ /**
260
+ * DrawingManager class
261
+ * Manages Forge Viewer markup functionality
262
+ */
263
+ export class DrawingManager {
264
+ constructor(
265
+ viewer: Autodesk.Viewing.GuiViewer3D,
266
+ eventBus: any,
267
+ config?: IDrawingManagerConfig
268
+ );
269
+ enterEditMode(): Promise<void>;
270
+ leaveEditMode(): void;
271
+ isEditMode(): boolean;
272
+ setActiveTool(toolType: TMarkupToolType): void;
273
+ getActiveTool(): TMarkupToolType | null;
274
+ setStrokeStyle(color: string, width: number, opacity: number): void;
275
+ setFillStyle(color: string, opacity: number): void;
276
+ saveMarkups(): IMarkupData;
277
+ loadMarkups(data: IMarkupData): void;
278
+ clearMarkups(): void;
279
+ exportToSVG(): string;
280
+ undo(): void;
281
+ redo(): void;
282
+ getCurrentStyles(): IMarkupStyle;
283
+ getCurrentToolPropertyConfig(): IToolPropertyConfig | null;
284
+ handlePropertyChange(key: string, value: any): void;
285
+ handleAction(action: string): void;
286
+ destroy(): void;
287
+
288
+ // Collaborative Markup API
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;
294
+ getMarkupSVG(): string;
295
+
296
+ // Real-time Collaboration Rendering APIs
297
+ renderFromSVG(svgString: string, options?: { clearExisting?: boolean; layerId?: string }): number;
298
+ mergeFromSVG(svgString: string, layerId?: string): number;
299
+ clearForPageChange(viewableGUID: string): IMarkupDataExport;
300
+ restoreAfterPageChange(data: IMarkupDataExport, options?: ILoadMarkupDataOptions): Promise<void>;
301
+
302
+ // SVG/JSON Conversion APIs
303
+ getMarkupDataAsJson(viewableGUID: string): IJsonMarkupData;
304
+ loadMarkupDataFromJson(jsonData: IJsonMarkupData, options?: ILoadMarkupDataOptions): Promise<void>;
305
+
306
+ // 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>;
310
+
311
+ // User Presence API
312
+ updateUserCursor(cursor: IUserCursor): void;
313
+ removeUserCursor(userId: string): void;
314
+ getRemoteCursors(): Map<string, IUserCursor>;
315
+ onLocalCursorMove(callback: OnLocalCursorMoveCallback): () => void;
316
+ clearAllCursors(): void;
317
+ }
318
+
319
+ /**
320
+ * MarkupToolbar component
321
+ */
322
+ export function MarkupToolbar(props: IMarkupToolbarProps): JSX.Element;
323
+
324
+ /**
325
+ * PropertyPanel component
326
+ */
327
+ export function PropertyPanel(props: IPropertyPanelProps): JSX.Element;
328
+
329
+ /**
330
+ * Markup tool constants
331
+ */
332
+ export const MARKUP_TOOLS: {
333
+ ARROW: 'arrow';
334
+ RECTANGLE: 'rectangle';
335
+ CIRCLE: 'ellipse';
336
+ CLOUD: 'cloud';
337
+ TEXT: 'label';
338
+ PEN: 'freehand';
339
+ /** @deprecated Use PEN instead */
340
+ FREEHAND: 'freehand';
341
+ LINE: 'line';
342
+ POLYLINE: 'polyline';
343
+ POLYCLOUD: 'polycloud';
344
+ CALLOUT: 'callout';
345
+ IMAGE: 'image';
346
+ };
347
+
348
+ /**
349
+ * Default markup styles
350
+ */
351
+ export const DEFAULT_MARKUP_STYLES: IMarkupStyle;
352
+
353
+ /**
354
+ * Preset colors
355
+ */
356
+ export const PRESET_COLORS: readonly string[];
357
+
358
+ // ========================================
359
+ // Markup Tools (OOP Architecture)
360
+ // ========================================
361
+
362
+ /**
363
+ * Abstract base class for all markup tools
364
+ */
365
+ export abstract class MarkupTool {
366
+ constructor(markupsCore: any);
367
+ getToolId(): string;
368
+ getEditModeClassName(): string;
369
+ getDisplayName(): string;
370
+ activate(styles?: IMarkupStyle): void;
371
+ deactivate(): void;
372
+ supportsFillColor(): boolean;
373
+ getMetadata(): Record<string, any>;
374
+ getPropertyConfig(): IToolPropertyConfig | null;
375
+ onPropertyChange(key: string, value: any): void;
376
+ onAction(action: string): void;
377
+ }
378
+
379
+ /**
380
+ * Concrete tool implementations
381
+ */
382
+ export class ArrowTool extends MarkupTool {}
383
+ export class RectangleTool extends MarkupTool {}
384
+ export class CircleTool extends MarkupTool {}
385
+ export class CloudTool extends MarkupTool {}
386
+ export class TextTool extends MarkupTool {}
387
+ export class FreehandTool extends MarkupTool {}
388
+ /** Alias for FreehandTool */
389
+ export class PenTool extends MarkupTool {}
390
+ export class LineTool extends MarkupTool {}
391
+ export class PolylineTool extends MarkupTool {}
392
+ export class PolycloudTool extends MarkupTool {}
393
+ export class CalloutTool extends MarkupTool {}
394
+ 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;
397
+ clearPendingImage(): void;
398
+ loadImageFile(file: File, options?: { storeInIndexedDB?: boolean }): Promise<string | void>;
399
+ loadSVGFile(file: File): Promise<void>;
400
+ // IndexedDB Storage Methods
401
+ initializeStorage(): Promise<void>;
402
+ getStorageService(): ImageStorageService | null;
403
+ storeImage(imageData: string, metadata?: { fileName?: string; mimeType?: string; width?: number; height?: number }): Promise<string>;
404
+ getStoredImage(storageId: string): Promise<string | null>;
405
+ hasStoredImage(storageId: string): Promise<boolean>;
406
+ deleteStoredImage(storageId: string): Promise<boolean>;
407
+ getCurrentStorageId(): string;
408
+ loadFromStorage(storageId: string): Promise<void>;
409
+ }
410
+
411
+ /**
412
+ * Tool Factory for creating tool instances
413
+ */
414
+ export class ToolFactory {
415
+ constructor(markupsCore: any);
416
+ createTool(toolType: TMarkupToolType): MarkupTool | null;
417
+ getAvailableTools(): TMarkupToolType[];
418
+ static registerCustomTool(toolType: TMarkupToolType, toolClass: any): void;
419
+ clearInstances(): void;
420
+ getToolInstance(toolType: TMarkupToolType): MarkupTool | undefined;
421
+ }
422
+
423
+ /**
424
+ * Tool Registry for managing tool types
425
+ */
426
+ export class ToolRegistry {
427
+ static registerTool(toolType: TMarkupToolType, toolClass: any): void;
428
+ static getToolConstructor(toolType: TMarkupToolType): any;
429
+ static getAllToolTypes(): TMarkupToolType[];
430
+ static hasToolType(toolType: TMarkupToolType): boolean;
431
+ }
432
+
433
+ // ========================================
434
+ // Viewer Component Props
435
+ // ========================================
436
+
57
437
  /**
58
438
  * Props for ViewerForgePDF component
59
439
  */
@@ -75,6 +455,15 @@ declare module '@dtducas/wh-forge-viewer' {
75
455
  * Callback to receive viewer instance when initialized
76
456
  */
77
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;
78
467
  }
79
468
  /**
80
469
  * ViewerForgePDF - React component for displaying PDF and CAD files using Autodesk Forge Viewer
@@ -97,5 +486,652 @@ declare module '@dtducas/wh-forge-viewer' {
97
486
  * }
98
487
  * ```
99
488
  */
100
- export const ViewerForgePDF: FC<IViewerForgePDFProps>;
489
+ export function ViewerForgePDF(props: IViewerForgePDFProps): JSX.Element;
490
+
491
+ // ========================================
492
+ // EventBus for page change events
493
+ // ========================================
494
+
495
+ /**
496
+ * Event names for EventBus subscriptions
497
+ */
498
+ export const EVENT_NAMES: {
499
+ PAGE_CHANGING: 'page:changing';
500
+ PAGE_CHANGED: 'page:changed';
501
+ VIEWABLES_SET: 'viewables:set';
502
+ DOC_BROWSER_OPENED: 'docBrowser:opened';
503
+ DOC_BROWSER_CLOSED: 'docBrowser:closed';
504
+ MARKUP_CHANGED: 'markup:changed';
505
+ };
506
+
507
+ /**
508
+ * EventBus singleton for cross-component communication
509
+ */
510
+ export class EventBus {
511
+ static getInstance(): EventBus;
512
+ on(event: string, callback: (...args: any[]) => void): void;
513
+ off(event: string, callback: (...args: any[]) => void): void;
514
+ emit(event: string, ...args: any[]): void;
515
+ once(event: string, callback: (...args: any[]) => void): void;
516
+ }
517
+
518
+ // ========================================
519
+ // Collaborative Markup API Types
520
+ // ========================================
521
+
522
+ /**
523
+ * Individual markup item
524
+ */
525
+ export interface IMarkupItem {
526
+ id: string;
527
+ type: string;
528
+ position: { x: number; y: number };
529
+ size: { x: number; y: number };
530
+ rotation: number;
531
+ style: Record<string, any>;
532
+ }
533
+
534
+ /**
535
+ * Markup data export format for persistence
536
+ */
537
+ export interface IMarkupDataExport {
538
+ version: string;
539
+ /** Viewable identifier - provided by the consuming app (any string format) */
540
+ viewableGUID: string;
541
+ svgString: string;
542
+ markups: IMarkupItem[];
543
+ timestamp: number;
544
+ }
545
+
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
+ /**
694
+ * Options for loadMarkupData method
695
+ */
696
+ export interface ILoadMarkupDataOptions {
697
+ mode?: 'replace' | 'merge';
698
+ }
699
+
700
+ /**
701
+ * Callback type for markup change subscription
702
+ */
703
+ export type OnMarkupChangeCallback = (delta: IMarkupDelta) => void;
704
+
705
+ // ========================================
706
+ // User Presence API Types
707
+ // ========================================
708
+
709
+ /**
710
+ * User cursor data for collaborative presence
711
+ */
712
+ export interface IUserCursor {
713
+ userId: string;
714
+ userName: string;
715
+ color: string;
716
+ position: { x: number; y: number };
717
+ timestamp: number;
718
+ }
719
+
720
+ /**
721
+ * Callback for local cursor movement
722
+ */
723
+ export type OnLocalCursorMoveCallback = (payload: {
724
+ position: { x: number; y: number };
725
+ screenPosition: { x: number; y: number };
726
+ timestamp: number;
727
+ }) => void;
728
+
729
+ /**
730
+ * CursorOverlay component props
731
+ */
732
+ export interface ICursorOverlayProps {
733
+ cursors: Map<string, IUserCursor>;
734
+ containerRef?: React.RefObject<HTMLElement>;
735
+ }
736
+
737
+ /**
738
+ * CursorOverlay component for displaying remote user cursors
739
+ */
740
+ export function CursorOverlay(props: ICursorOverlayProps): JSX.Element;
741
+
742
+ // ========================================
743
+ // PDF Export Services
744
+ // ========================================
745
+
746
+ /**
747
+ * Export options for PDF with markup
748
+ */
749
+ export interface IExportPdfOptions {
750
+ /** Output filename without extension @default 'document-with-markup' */
751
+ filename?: string;
752
+ /** Preserve original PDF metadata @default true */
753
+ preserveMetadata?: boolean;
754
+ /** Flatten markups (cannot be edited later) @default true */
755
+ flattenMarkups?: boolean;
756
+ }
757
+
758
+ /**
759
+ * Markup data for a single page
760
+ */
761
+ export interface IPageMarkupData {
762
+ /** Page index (0-based) */
763
+ pageIndex: number;
764
+ /** SVG string of markups for this page */
765
+ svgString: string;
766
+ /** SVG viewBox dimensions (extracted from SVG if not provided) */
767
+ viewBox?: { x: number; y: number; width: number; height: number };
768
+ /** Model bounding box from Forge Viewer (PDF page extent in viewer coords) */
769
+ modelBounds?: { minX: number; minY: number; maxX: number; maxY: number };
770
+ }
771
+
772
+ /**
773
+ * Export result
774
+ */
775
+ export interface IExportResult {
776
+ /** Whether export was successful */
777
+ success: boolean;
778
+ /** Error message if failed */
779
+ error?: string;
780
+ /** Resulting PDF blob */
781
+ blob?: Blob;
782
+ /** Number of pages processed */
783
+ pagesProcessed: number;
784
+ }
785
+
786
+ /**
787
+ * Conversion options for SVG to PDF
788
+ */
789
+ export interface ISvgToPdfOptions {
790
+ /** PDF page width in points */
791
+ pageWidth: number;
792
+ /** PDF page height in points */
793
+ pageHeight: number;
794
+ /** SVG viewBox dimensions */
795
+ svgViewBox: { x: number; y: number; width: number; height: number };
796
+ /** Model bounding box (PDF page extent in viewer coords) - used instead of viewBox for mapping */
797
+ modelBounds?: { minX: number; minY: number; maxX: number; maxY: number };
798
+ /** Scale factor @default 1 */
799
+ scale?: number;
800
+ /** Offset for positioning */
801
+ offset?: { x: number; y: number };
802
+ }
803
+
804
+ /**
805
+ * Service for exporting PDF with markup overlaid as vector graphics
806
+ * Uses pdf-lib and SvgToPdfConverter for client-side PDF manipulation
807
+ *
808
+ * @example
809
+ * ```typescript
810
+ * const exportService = new MarkupExportService();
811
+ * const result = await exportService.exportPDFWithMarkup(
812
+ * pdfBlob,
813
+ * [{ pageIndex: 0, svgString: svgMarkup }],
814
+ * { filename: 'annotated-document' }
815
+ * );
816
+ * ```
817
+ */
818
+ export class MarkupExportService {
819
+ 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>;
823
+ downloadPdf(blob: Blob, filename?: string): void;
824
+ static fetchPdfBlob(pdfSource: Blob | string): Promise<Blob>;
825
+ }
826
+
827
+ /**
828
+ * SVG to PDF Converter
829
+ * Converts SVG markup elements to PDF drawing operations using pdf-lib
830
+ *
831
+ * @example
832
+ * ```typescript
833
+ * const converter = new SvgToPdfConverter();
834
+ * await converter.drawSvgOnPdfPage(svgString, pdfPage, {
835
+ * pageWidth: 612, pageHeight: 792,
836
+ * svgViewBox: { x: 0, y: 0, width: 1000, height: 1000 }
837
+ * });
838
+ * ```
839
+ */
840
+ export class SvgToPdfConverter {
841
+ drawSvgOnPdfPage(svgString: string, pdfPage: any, options: ISvgToPdfOptions): Promise<void>;
842
+ }
843
+
844
+ // ========================================
845
+ // Toolbar Visibility API Types
846
+ // ========================================
847
+
848
+ /**
849
+ * Toolbar button identifiers
850
+ */
851
+ export type TToolbarButtonId = 'pan' | 'docBrowser' | 'download' | 'markup' | 'pagination';
852
+
853
+ /**
854
+ * Toolbar button visibility configuration
855
+ */
856
+ export interface IToolbarVisibilityConfig {
857
+ pan?: boolean;
858
+ docBrowser?: boolean;
859
+ download?: boolean;
860
+ markup?: boolean;
861
+ pagination?: boolean;
862
+ }
863
+
864
+ /**
865
+ * Toolbar visibility API interface
866
+ */
867
+ export interface IToolbarVisibilityAPI {
868
+ getVisibilityConfig(): IToolbarVisibilityConfig;
869
+ setVisibilityConfig(config: IToolbarVisibilityConfig): void;
870
+ showButton(buttonId: TToolbarButtonId): void;
871
+ hideButton(buttonId: TToolbarButtonId): void;
872
+ showAllButtons(): void;
873
+ hideAllButtons(): void;
874
+ isButtonVisible(buttonId: TToolbarButtonId): boolean;
875
+ }
876
+
877
+ /**
878
+ * Default toolbar visibility configuration (all visible)
879
+ */
880
+ export const DEFAULT_TOOLBAR_VISIBILITY: Required<IToolbarVisibilityConfig>;
881
+
882
+ // ========================================
883
+ // Image Storage Service (IndexedDB)
884
+ // ========================================
885
+
886
+ /**
887
+ * Stored image data structure
888
+ */
889
+ export interface IStoredImage {
890
+ id: string;
891
+ data: string;
892
+ mimeType: string;
893
+ fileName?: string;
894
+ width: number;
895
+ height: number;
896
+ sizeBytes: number;
897
+ createdAt: number;
898
+ lastAccessedAt: number;
899
+ expiresAt?: number;
900
+ }
901
+
902
+ /**
903
+ * Image storage configuration
904
+ */
905
+ export interface IImageStorageConfig {
906
+ dbName?: string;
907
+ maxStorageSize?: number;
908
+ defaultExpiryMs?: number;
909
+ enableAutoCleanup?: boolean;
910
+ cleanupIntervalMs?: number;
911
+ }
912
+
913
+ /**
914
+ * Storage statistics
915
+ */
916
+ export interface IStorageStats {
917
+ totalImages: number;
918
+ totalSizeBytes: number;
919
+ oldestImage?: number;
920
+ newestImage?: number;
921
+ expiredCount: number;
922
+ }
923
+
924
+ /**
925
+ * Image storage service using IndexedDB
926
+ */
927
+ export class ImageStorageService {
928
+ static getInstance(config?: IImageStorageConfig): ImageStorageService;
929
+ initialize(): Promise<void>;
930
+ storeImage(imageData: string, metadata?: Partial<IStoredImage>): Promise<string>;
931
+ getImage(id: string): Promise<IStoredImage | null>;
932
+ hasImage(id: string): Promise<boolean>;
933
+ deleteImage(id: string): Promise<boolean>;
934
+ cleanupExpiredImages(): Promise<number>;
935
+ clearAll(): Promise<void>;
936
+ getStorageStats(): Promise<IStorageStats>;
937
+ destroy(): void;
938
+ }
939
+
940
+ // ========================================
941
+ // Markup Converter Service (SVG ↔ JSON)
942
+ // ========================================
943
+
944
+ /**
945
+ * JSON markup data format for database storage
946
+ * Coordinates are stored as-is (no scaling)
947
+ */
948
+ export interface IJsonMarkupData {
949
+ /** Format version for JSON schema compatibility */
950
+ version: string;
951
+ /** Viewable identifier - provided by the consuming app (any string format) */
952
+ 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) */
958
+ timestamp: number;
959
+ }
960
+
961
+ /**
962
+ * SVG validation result
963
+ */
964
+ export interface ISvgValidationResult {
965
+ valid: boolean;
966
+ errors: string[];
967
+ markupCount: number;
968
+ }
969
+
970
+ /**
971
+ * JSON validation result
972
+ */
973
+ export interface IJsonValidationResult {
974
+ valid: boolean;
975
+ errors: string[];
976
+ }
977
+
978
+ /**
979
+ * Service for converting between SVG and JSON markup formats
980
+ *
981
+ * ID FORMAT:
982
+ * Element IDs use compact format: {toolCode}-{timestamp}-{random4}
983
+ * Example: "1-1770285843573-a7f3" (freehand=1)
984
+ *
985
+ * @example
986
+ * ```typescript
987
+ * // SVG to JSON
988
+ * const svg = markupsCore.generateData();
989
+ * const json = MarkupConverterService.svgToJson(svg, 'my-page-id');
990
+ *
991
+ * // JSON to SVG (for restoring)
992
+ * const svg = MarkupConverterService.jsonToSvg(json);
993
+ * markupsCore.loadMarkups(svg, 'restored-layer');
994
+ * ```
995
+ */
996
+ export class MarkupConverterService {
997
+ static svgToJson(svgString: string, viewableGUID: string): IJsonMarkupData;
998
+ static jsonToSvg(jsonData: IJsonMarkupData, layerId?: string): string;
999
+ static validateJsonData(data: unknown): IJsonValidationResult;
1000
+ static validateSvgString(svgString: string): ISvgValidationResult;
1001
+ static isValidJsonData(data: unknown): data is IJsonMarkupData;
1002
+ static getCurrentVersion(): string;
1003
+ static isVersionCompatible(version: string): boolean;
1004
+ static mergeJsonData(dataSets: IJsonMarkupData[]): IJsonMarkupData;
1005
+ }
1006
+
1007
+ /**
1008
+ * Generate UUIDv7 - time-ordered UUID
1009
+ * Utility function, can be used if you need a UUID identifier
1010
+ * Note: viewableGUID can be any string, UUIDv7 is not required
1011
+ *
1012
+ * @example
1013
+ * ```typescript
1014
+ * const id = generateUUIDv7();
1015
+ * // "0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e"
1016
+ * ```
1017
+ */
1018
+ export function generateUUIDv7(): string;
1019
+
1020
+ /**
1021
+ * Validate if a string is a valid UUID format (v4 or v7)
1022
+ * Format: xxxxxxxx-xxxx-Vxxx-yxxx-xxxxxxxxxxxx
1023
+ *
1024
+ * @param uuid - String to validate
1025
+ * @returns True if valid UUID format
1026
+ *
1027
+ * @example
1028
+ * ```typescript
1029
+ * isValidUUID('0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e'); // true
1030
+ * isValidUUID('test-viewable-guid'); // false
1031
+ * ```
1032
+ */
1033
+ export function isValidUUID(uuid: string): boolean;
1034
+
1035
+ /**
1036
+ * Validate if a string is a valid UUIDv7 format
1037
+ * Format: xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx
1038
+ * Version 7 indicated by '7' at position 14
1039
+ *
1040
+ * @param uuid - String to validate
1041
+ * @returns True if valid UUIDv7 format
1042
+ *
1043
+ * @example
1044
+ * ```typescript
1045
+ * isValidUUIDv7('0192d4e5-7f8a-7b3c-9d1e-2f4a6b8c0d2e'); // true (if version is 7)
1046
+ * isValidUUIDv7('550e8400-e29b-41d4-a716-446655440000'); // false (version 4)
1047
+ * ```
1048
+ */
1049
+ export function isValidUUIDv7(uuid: string): boolean;
1050
+
1051
+ /**
1052
+ * Coordinate scale factor for precision calculations (1e7)
1053
+ * Use this constant when performing math operations that need precision
1054
+ * Note: Coordinates are NOT scaled in storage
1055
+ */
1056
+ export const MARKUP_COORDINATE_SCALE: number;
1057
+
1058
+ /**
1059
+ * Tool type to numeric code mapping for compact ID generation
1060
+ * Used in element ID format: {toolCode}-{timestamp}-{random4}
1061
+ */
1062
+ export const MARKUP_TOOL_CODES: Record<string, number>;
1063
+
1064
+ // ========================================
1065
+ // Coordinate System Utilities
1066
+ // ========================================
1067
+
1068
+ /**
1069
+ * Coordinate space types
1070
+ */
1071
+ export type TCoordinateSpace = 'screen' | 'markup' | 'page';
1072
+
1073
+ /**
1074
+ * 2D point interface
1075
+ */
1076
+ export interface IPoint2D {
1077
+ x: number;
1078
+ y: number;
1079
+ }
1080
+
1081
+ /**
1082
+ * 2D bounds interface
1083
+ */
1084
+ export interface IBounds2D {
1085
+ min: IPoint2D;
1086
+ max: IPoint2D;
1087
+ }
1088
+
1089
+ /**
1090
+ * Coordinate validation result
1091
+ */
1092
+ export interface ICoordinateValidationResult {
1093
+ valid: boolean;
1094
+ space: TCoordinateSpace;
1095
+ message?: string;
1096
+ normalized?: IPoint2D;
1097
+ }
1098
+
1099
+ /**
1100
+ * Coordinate space information for debugging
1101
+ */
1102
+ export interface ICoordinateSpaceInfo {
1103
+ viewBox: { x: number; y: number; width: number; height: number };
1104
+ bounds: IBounds2D | null;
1105
+ currentZoom: number;
1106
+ currentPan: IPoint2D;
1107
+ ctmMatrix: DOMMatrix | null;
1108
+ }
1109
+
1110
+ /**
1111
+ * Validate coordinates in markup space
1112
+ */
1113
+ export function validateMarkupCoordinates(
1114
+ point: IPoint2D,
1115
+ markupsCore: any
1116
+ ): ICoordinateValidationResult;
1117
+
1118
+ /**
1119
+ * Get coordinate space metadata for debugging
1120
+ */
1121
+ export function getCoordinateSpaceInfo(markupsCore: any): ICoordinateSpaceInfo;
1122
+
1123
+ /**
1124
+ * Convert coordinates between different coordinate spaces
1125
+ */
1126
+ export function convertCoordinates(
1127
+ point: IPoint2D,
1128
+ from: TCoordinateSpace,
1129
+ to: TCoordinateSpace,
1130
+ markupsCore: any
1131
+ ): IPoint2D;
1132
+
1133
+ /**
1134
+ * Check if the coordinate system is normalized (zoom/pan independent)
1135
+ */
1136
+ export function isCoordinateSystemNormalized(markupsCore: any): boolean;
101
1137
  }