@deckedout/visual-editor 1.0.0

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.
@@ -0,0 +1,1045 @@
1
+ import React$1 from 'react';
2
+
3
+ /**
4
+ * Visual Editor - Core Type Definitions
5
+ *
6
+ * This file contains all the type definitions for the extensible visual editor.
7
+ * The editor supports multiple modes (Card Editor, Playground, etc.) through
8
+ * a flexible, schema-driven architecture.
9
+ */
10
+ /**
11
+ * Base interface for all visual elements in the editor.
12
+ * @template TProps - Custom properties specific to the element type
13
+ */
14
+ interface EditorElement<TProps = any> {
15
+ /** Unique identifier for the element */
16
+ id: string;
17
+ /** Type identifier (e.g., "text", "image", "pile", "card") */
18
+ type: string;
19
+ /** Position on the canvas */
20
+ position: {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ /** Size of the element */
25
+ size: {
26
+ width: number;
27
+ height: number;
28
+ };
29
+ /** Rotation angle in degrees */
30
+ rotation: number;
31
+ /** Opacity (0-1, where 0 is transparent and 1 is opaque) */
32
+ opacity: number;
33
+ /** Layer order (higher = on top) */
34
+ zIndex: number;
35
+ /** Whether the element is visible */
36
+ visible?: boolean;
37
+ /** Whether the element is locked (cannot be selected/moved) */
38
+ locked?: boolean;
39
+ /** Display name for layers panel */
40
+ displayName?: string;
41
+ /** Element-specific properties */
42
+ props: TProps;
43
+ }
44
+ /**
45
+ * Common text element properties - matches CardChildText
46
+ */
47
+ interface TextElementProps {
48
+ content: string;
49
+ fontSize: number;
50
+ fontFamily?: string;
51
+ color: string;
52
+ strokeColor?: string;
53
+ strokeWidth?: number;
54
+ align?: "left" | "center" | "right";
55
+ verticalAlign?: "top" | "middle" | "bottom";
56
+ bold?: boolean;
57
+ italic?: boolean;
58
+ underline?: boolean;
59
+ overline?: boolean;
60
+ strikethrough?: boolean;
61
+ wordWrap?: "break-word";
62
+ textOverflow?: "clip" | "ellipsis" | "visible";
63
+ }
64
+ /**
65
+ * Common image element properties
66
+ */
67
+ interface ImageElementProps {
68
+ src: string;
69
+ fit?: "contain" | "cover" | "fill";
70
+ }
71
+ /**
72
+ * Defines how an element type should be rendered and configured.
73
+ * This is the core abstraction that makes the editor extensible.
74
+ */
75
+ interface ElementRenderer<TProps = any> {
76
+ /** Unique type identifier */
77
+ type: string;
78
+ /** Display name for UI */
79
+ displayName: string;
80
+ /** Render function for the element (for non-Konva contexts) */
81
+ render: (element: EditorElement<TProps>) => React.ReactNode;
82
+ /** React component for Konva canvas rendering */
83
+ renderComponent?: React.ComponentType<{
84
+ element: EditorElement<TProps>;
85
+ isSelected: boolean;
86
+ onSelect: () => void;
87
+ onTransform: (updates: Partial<EditorElement>) => void;
88
+ allElements?: EditorElement[];
89
+ canvasSize?: {
90
+ width: number;
91
+ height: number;
92
+ };
93
+ onSnapGuides?: (guides: any) => void;
94
+ onClearSnapGuides?: () => void;
95
+ [key: string]: any;
96
+ }>;
97
+ /** Default properties when creating a new element of this type */
98
+ defaultProps: TProps;
99
+ /** Default size for new elements */
100
+ defaultSize?: {
101
+ width: number;
102
+ height: number;
103
+ };
104
+ /** Schema for the property inspector */
105
+ inspectorSchema?: InspectorFieldSchema[];
106
+ /** Optional icon for element type selector */
107
+ icon?: React.ReactNode;
108
+ }
109
+ /**
110
+ * Supported field types in the property inspector
111
+ */
112
+ type InspectorFieldType = "string" | "number" | "color" | "select" | "boolean" | "slider" | "image" | "custom";
113
+ /**
114
+ * Props passed to custom renderer components
115
+ */
116
+ interface CustomRendererProps {
117
+ /** Current field value */
118
+ value: any;
119
+ /** Callback to update the value */
120
+ onChange: (value: any) => void;
121
+ /** Field schema */
122
+ field: InspectorFieldSchema;
123
+ /** All element props (for context) */
124
+ elementProps: any;
125
+ /** Editor mode (for accessing mode context) */
126
+ mode?: EditorMode;
127
+ }
128
+ /**
129
+ * Schema definition for a single inspector field
130
+ */
131
+ interface InspectorFieldSchema {
132
+ /** Property name in element.props */
133
+ name: string;
134
+ /** Field type */
135
+ type: InspectorFieldType;
136
+ /** Display label */
137
+ label: string;
138
+ /** Optional description/help text */
139
+ description?: string;
140
+ /** For select fields - available options */
141
+ options?: {
142
+ value: any;
143
+ label: string;
144
+ }[];
145
+ /** For number/slider fields */
146
+ min?: number;
147
+ max?: number;
148
+ step?: number;
149
+ /** Default value */
150
+ defaultValue?: any;
151
+ /** For custom type - custom renderer component */
152
+ customRenderer?: React.ComponentType<CustomRendererProps>;
153
+ }
154
+ /**
155
+ * Core API for manipulating elements in the editor.
156
+ * This API is exposed to modes and external code.
157
+ */
158
+ interface EditorAPI {
159
+ /** Add a new element to the canvas */
160
+ addElement: (element: EditorElement) => void;
161
+ /** Update an existing element */
162
+ updateElement: (id: string, updates: Partial<EditorElement>) => void;
163
+ /** Remove an element from the canvas */
164
+ removeElement: (id: string) => void;
165
+ /** Select an element (or null to deselect) */
166
+ selectElement: (id: string | null) => void;
167
+ /** Get the currently selected element */
168
+ getSelectedElement: () => EditorElement | null;
169
+ /** Get all elements */
170
+ getAllElements: () => EditorElement[];
171
+ /** Move an element by delta */
172
+ moveElement: (id: string, deltaX: number, deltaY: number) => void;
173
+ /** Rotate an element */
174
+ rotateElement: (id: string, angle: number) => void;
175
+ /** Resize an element */
176
+ resizeElement: (id: string, width: number, height: number) => void;
177
+ /** Update element's z-index */
178
+ updateZIndex: (id: string, zIndex: number) => void;
179
+ /** Reorder an element to a new position in the array */
180
+ reorderElement: (id: string, newIndex: number) => void;
181
+ /** Export canvas to JSON */
182
+ exportJSON: () => CanvasExport;
183
+ /** Import canvas from JSON */
184
+ importJSON: (data: CanvasExport) => void;
185
+ /** Clear all elements */
186
+ clear: () => void;
187
+ /** Clear undo/redo history */
188
+ clearHistory: () => void;
189
+ /** Load elements without recording history (for initial load) */
190
+ loadElements: (elements: EditorElement[]) => void;
191
+ /** Copy an element to clipboard (returns element data) */
192
+ copyElement: (id?: string | null) => EditorElement | null;
193
+ /** Duplicate the selected element with an offset */
194
+ duplicateElement: (id?: string | null, offset?: {
195
+ x: number;
196
+ y: number;
197
+ }) => void;
198
+ /** Paste a copied element with an offset */
199
+ pasteElement: (copiedElement: EditorElement, offset?: {
200
+ x: number;
201
+ y: number;
202
+ }) => void;
203
+ }
204
+ /**
205
+ * Format for exporting/importing canvas data
206
+ */
207
+ interface CanvasExport {
208
+ /** Canvas dimensions */
209
+ width: number;
210
+ height: number;
211
+ /** All elements on the canvas */
212
+ elements: EditorElement[];
213
+ /** Optional metadata */
214
+ metadata?: {
215
+ version?: string;
216
+ mode?: string;
217
+ created?: string;
218
+ modified?: string;
219
+ [key: string]: any;
220
+ };
221
+ }
222
+ /**
223
+ * Base interface for all custom editor actions
224
+ */
225
+ interface CustomEditorActionBase {
226
+ /** Unique identifier */
227
+ id: string;
228
+ /** Display label/tooltip */
229
+ label: string;
230
+ /** Disabled state */
231
+ disabled?: boolean | ((api: EditorAPI) => boolean);
232
+ }
233
+ /**
234
+ * Button action - Simple click handler
235
+ */
236
+ interface CustomEditorButtonAction extends CustomEditorActionBase {
237
+ type: "button";
238
+ /** Icon component */
239
+ icon?: React.ReactNode;
240
+ /** Keyboard shortcut hint */
241
+ shortcut?: string;
242
+ /** Click handler */
243
+ onClick: (api: EditorAPI) => void;
244
+ }
245
+ /**
246
+ * Dropdown action - Select from options
247
+ */
248
+ interface CustomEditorDropdownAction extends CustomEditorActionBase {
249
+ type: "dropdown";
250
+ /** Icon component (optional) */
251
+ icon?: React.ReactNode;
252
+ /** Dropdown options */
253
+ options: Array<{
254
+ value: string;
255
+ label: string;
256
+ icon?: React.ReactNode;
257
+ }>;
258
+ /** Current selected value */
259
+ value?: string;
260
+ /** Change handler */
261
+ onChange: (value: string, api: EditorAPI) => void;
262
+ /** Placeholder text when no value selected */
263
+ placeholder?: string;
264
+ }
265
+ /**
266
+ * Input action - Text input field
267
+ */
268
+ interface CustomEditorInputAction extends CustomEditorActionBase {
269
+ type: "input";
270
+ /** Input type (text, number, etc.) */
271
+ inputType?: "text" | "number" | "email" | "password" | "search";
272
+ /** Current value */
273
+ value: string;
274
+ /** Change handler */
275
+ onChange: (value: string, api: EditorAPI) => void;
276
+ /** Placeholder text */
277
+ placeholder?: string;
278
+ /** Min/max for number inputs */
279
+ min?: number;
280
+ max?: number;
281
+ step?: number;
282
+ }
283
+ /**
284
+ * Color picker action - Color selection
285
+ */
286
+ interface CustomEditorColorAction extends CustomEditorActionBase {
287
+ type: "color";
288
+ /** Current color value */
289
+ value: string;
290
+ /** Change handler */
291
+ onChange: (color: string, api: EditorAPI) => void;
292
+ /** Show alpha channel */
293
+ showAlpha?: boolean;
294
+ }
295
+ /**
296
+ * Toggle action - On/off switch
297
+ */
298
+ interface CustomEditorToggleAction extends CustomEditorActionBase {
299
+ type: "toggle";
300
+ /** Icon component (optional) */
301
+ icon?: React.ReactNode;
302
+ /** Current toggle state */
303
+ value: boolean;
304
+ /** Change handler */
305
+ onChange: (value: boolean, api: EditorAPI) => void;
306
+ }
307
+ /**
308
+ * Separator - Visual divider (no interaction)
309
+ */
310
+ interface CustomEditorSeparator {
311
+ type: "separator";
312
+ id: string;
313
+ }
314
+ /**
315
+ * Union type for all custom editor actions
316
+ */
317
+ type CustomEditorAction = CustomEditorButtonAction | CustomEditorDropdownAction | CustomEditorInputAction | CustomEditorColorAction | CustomEditorToggleAction | CustomEditorSeparator;
318
+ /**
319
+ * Configuration for topbar controls visibility
320
+ */
321
+ interface TopbarConfig {
322
+ /** Show undo button */
323
+ showUndo?: boolean;
324
+ /** Show redo button */
325
+ showRedo?: boolean;
326
+ /** Show delete button */
327
+ showDelete?: boolean;
328
+ /** Show copy button */
329
+ showCopy?: boolean;
330
+ /** Show paste button */
331
+ showPaste?: boolean;
332
+ /** Show duplicate button */
333
+ showDuplicate?: boolean;
334
+ /** Show export button */
335
+ showExport?: boolean;
336
+ /** Show import button */
337
+ showImport?: boolean;
338
+ /** Show canvas size controls */
339
+ showCanvasSize?: boolean;
340
+ /** Show snap guides toggle */
341
+ showSnapGuides?: boolean;
342
+ /** Custom actions to add before default controls (left side) */
343
+ actionsStart?: CustomEditorAction[];
344
+ /** Custom actions to add after default controls (right side) */
345
+ actionsEnd?: CustomEditorAction[];
346
+ /** Custom CSS classes for the start actions container */
347
+ actionsStartClassName?: string;
348
+ /** Custom CSS classes for the end actions container */
349
+ actionsEndClassName?: string;
350
+ /** @deprecated Use actionsEnd instead. Custom actions to add to topbar (defaults to end) */
351
+ customActions?: CustomEditorAction[];
352
+ }
353
+ /**
354
+ * Configuration for toolbar controls visibility
355
+ */
356
+ interface ToolbarConfig {
357
+ /** Show element creation tools */
358
+ showElementTools?: boolean;
359
+ /** Specific element types to hide from toolbar (by type string) */
360
+ hiddenElementTypes?: string[];
361
+ /** Custom tools to add before default element tools (top) */
362
+ toolsStart?: CustomEditorAction[];
363
+ /** Custom tools to add after default element tools (bottom) */
364
+ toolsEnd?: CustomEditorAction[];
365
+ /** Custom CSS classes for the start tools container */
366
+ toolsStartClassName?: string;
367
+ /** Custom CSS classes for the end tools container */
368
+ toolsEndClassName?: string;
369
+ /** @deprecated Use toolsEnd instead. Custom tools to add to toolbar (defaults to end) */
370
+ customTools?: CustomEditorAction[];
371
+ }
372
+ /**
373
+ * Configuration for different editor modes (Card Editor, Playground, etc.)
374
+ */
375
+ interface EditorMode {
376
+ /** Mode identifier */
377
+ name: string;
378
+ /** Display name for UI */
379
+ displayName: string;
380
+ /**
381
+ * Elements available in this mode (optional)
382
+ * If omitted, defaultElements will be used
383
+ * If provided, will be merged with defaultElements
384
+ */
385
+ registeredElements?: ElementRenderer[];
386
+ /** Default canvas size */
387
+ defaultCanvasSize: {
388
+ width: number;
389
+ height: number;
390
+ };
391
+ /** Whether the canvas size can be changed */
392
+ canResizeCanvas?: boolean;
393
+ /** Whether elements can be added/removed */
394
+ readonly?: boolean;
395
+ /** Whether to show grid */
396
+ showGrid?: boolean;
397
+ /** Grid size in pixels */
398
+ gridSize?: number;
399
+ /** Whether to snap to grid */
400
+ snapToGrid?: boolean;
401
+ /** Background color */
402
+ backgroundColor?: string;
403
+ /** Background image (asset filename) */
404
+ backgroundImage?: string;
405
+ /** Optional context data to pass to element renderers */
406
+ context?: Record<string, any>;
407
+ /** Custom asset picker component */
408
+ assetPickerComponent?: React.ComponentType<any>;
409
+ /** Props to pass to the custom asset picker */
410
+ assetPickerProps?: Record<string, any>;
411
+ /** Asset picker height (CSS class like "h-64", "h-[40%]", "flex-1", etc.) */
412
+ assetPickerHeight?: string;
413
+ /** Asset picker position - 'bottom' shows below inspector, 'right' shows as separate panel */
414
+ assetPickerPosition?: "bottom" | "right";
415
+ /** Custom inspector placeholder component (shown when no element is selected) */
416
+ inspectorPlaceholder?: React.ComponentType<any>;
417
+ /** Configuration for topbar controls (hide/show specific actions) */
418
+ topbarConfig?: TopbarConfig;
419
+ /** Configuration for toolbar controls (hide/show specific tools) */
420
+ toolbarConfig?: ToolbarConfig;
421
+ /** Optional mode-specific behavior hooks */
422
+ onModeActivate?: (api: EditorAPI) => void;
423
+ onModeDeactivate?: (api: EditorAPI) => void;
424
+ onElementAdded?: (element: EditorElement, api: EditorAPI) => void;
425
+ onElementRemoved?: (element: EditorElement, api: EditorAPI) => void;
426
+ }
427
+ /**
428
+ * Main configuration for the Visual Editor component
429
+ */
430
+ interface VisualEditorProps {
431
+ /** Current editor mode */
432
+ mode?: EditorMode;
433
+ /** Initial canvas data */
434
+ initialData?: CanvasExport;
435
+ /** Canvas width (overrides mode default) */
436
+ width?: number;
437
+ /** Canvas height (overrides mode default) */
438
+ height?: number;
439
+ /** Whether the editor is in readonly mode */
440
+ readonly?: boolean;
441
+ /** Callback when data changes */
442
+ onChange?: (data: CanvasExport) => void;
443
+ /** Callback when an element is selected */
444
+ onSelectionChange?: (element: EditorElement | null) => void;
445
+ /** Callback for export action */
446
+ onExport?: (data: CanvasExport) => void;
447
+ /** Custom element renderers (extends mode elements) */
448
+ customElements?: ElementRenderer[];
449
+ /** Whether to show the toolbar */
450
+ showToolbar?: boolean;
451
+ /** Whether to show the inspector panel */
452
+ showInspector?: boolean;
453
+ /** Custom CSS class */
454
+ className?: string;
455
+ /** Custom styles */
456
+ style?: React.CSSProperties;
457
+ }
458
+ /**
459
+ * Internal editor state (not exposed externally)
460
+ */
461
+ interface EditorState {
462
+ elements: EditorElement[];
463
+ selectedElementId: string | null;
464
+ canvasSize: {
465
+ width: number;
466
+ height: number;
467
+ };
468
+ zoom: number;
469
+ pan: {
470
+ x: number;
471
+ y: number;
472
+ };
473
+ mode: EditorMode | null;
474
+ history: {
475
+ past: EditorElement[][];
476
+ future: EditorElement[][];
477
+ };
478
+ }
479
+ /**
480
+ * Actions for state management
481
+ */
482
+ type EditorAction = {
483
+ type: "ADD_ELEMENT";
484
+ element: EditorElement;
485
+ } | {
486
+ type: "UPDATE_ELEMENT";
487
+ id: string;
488
+ updates: Partial<EditorElement>;
489
+ } | {
490
+ type: "REMOVE_ELEMENT";
491
+ id: string;
492
+ } | {
493
+ type: "SELECT_ELEMENT";
494
+ id: string | null;
495
+ } | {
496
+ type: "SET_ELEMENTS";
497
+ elements: EditorElement[];
498
+ } | {
499
+ type: "LOAD_ELEMENTS";
500
+ elements: EditorElement[];
501
+ } | {
502
+ type: "REORDER_ELEMENT";
503
+ elementId: string;
504
+ newIndex: number;
505
+ } | {
506
+ type: "SET_CANVAS_SIZE";
507
+ width: number;
508
+ height: number;
509
+ } | {
510
+ type: "SET_ZOOM";
511
+ zoom: number;
512
+ } | {
513
+ type: "SET_PAN";
514
+ x: number;
515
+ y: number;
516
+ } | {
517
+ type: "SET_MODE";
518
+ mode: EditorMode;
519
+ } | {
520
+ type: "CLEAR";
521
+ } | {
522
+ type: "UNDO";
523
+ } | {
524
+ type: "REDO";
525
+ };
526
+
527
+ /**
528
+ * Visual Editor - Main Editor Component
529
+ *
530
+ * The core editor component that integrates all functionality:
531
+ * - Canvas rendering with Konva
532
+ * - Element management
533
+ * - Selection and transformation
534
+ * - Mode switching
535
+ */
536
+
537
+ /**
538
+ * Main Visual Editor Component
539
+ */
540
+ declare const VisualEditor: React$1.FC<VisualEditorProps>;
541
+
542
+ /**
543
+ * Inspector Component
544
+ *
545
+ * Schema-driven property panel for editing selected element properties.
546
+ * Dynamically renders fields based on the element's inspectorSchema.
547
+ */
548
+
549
+ interface InspectorProps {
550
+ /** Currently selected element */
551
+ selectedElement: EditorElement | null;
552
+ /** Element renderer for the selected element */
553
+ elementRenderer: ElementRenderer | null;
554
+ /** Editor API for updating elements */
555
+ api: EditorAPI;
556
+ /** Editor mode (for custom placeholder and context) */
557
+ mode?: EditorMode;
558
+ /** Canvas size (passed to placeholder component) */
559
+ canvasSize?: {
560
+ width: number;
561
+ height: number;
562
+ };
563
+ /** Function to set canvas size */
564
+ setCanvasSize?: (width: number, height: number) => void;
565
+ /** Optional custom style */
566
+ style?: React$1.CSSProperties;
567
+ /** Optional className */
568
+ className?: string;
569
+ }
570
+ /**
571
+ * Inspector component that renders property fields based on element schema
572
+ */
573
+ declare const Inspector: React$1.FC<InspectorProps>;
574
+ /**
575
+ * Render a single inspector field based on its type
576
+ */
577
+ declare function renderField(field: InspectorFieldSchema, props: any, editingValues: Record<string, string>, onChange: (name: string, value: any) => void, onColorChange: (name: string, value: string) => void, mode?: EditorMode): React$1.ReactNode;
578
+
579
+ /**
580
+ * Layers Panel Component
581
+ *
582
+ * Displays all elements in the canvas with controls to show/hide, lock/unlock,
583
+ * reorder, and delete elements.
584
+ */
585
+
586
+ interface LayersPanelProps {
587
+ /** All elements in the canvas */
588
+ elements: EditorElement[];
589
+ /** Currently selected element ID */
590
+ selectedElementId: string | null;
591
+ /** Editor API for manipulating elements */
592
+ api: EditorAPI;
593
+ /** Element registry to get renderer info */
594
+ elementRenderers: Map<string, ElementRenderer>;
595
+ /** Optional custom style */
596
+ style?: React$1.CSSProperties;
597
+ /** Optional className */
598
+ className?: string;
599
+ }
600
+ /**
601
+ * Layers Panel component
602
+ */
603
+ declare const LayersPanel: React$1.FC<LayersPanelProps>;
604
+
605
+ /**
606
+ * Visual Editor Workspace
607
+ *
608
+ * Integrated workspace that combines Toolbar, Canvas (VisualEditor), and Inspector.
609
+ * This component creates a complete editor experience by coordinating all three parts.
610
+ */
611
+
612
+ interface VisualEditorWorkspaceProps {
613
+ /** Editor mode configuration */
614
+ mode?: EditorMode;
615
+ /** Initial canvas data */
616
+ initialData?: CanvasExport;
617
+ /** Canvas width (overrides mode default) */
618
+ width?: number;
619
+ /** Canvas height (overrides mode default) */
620
+ height?: number;
621
+ /** Whether the editor is in readonly mode */
622
+ readonly?: boolean;
623
+ /** Callback when data changes */
624
+ onChange?: (data: CanvasExport) => void;
625
+ /** Custom element renderers (extends mode elements) */
626
+ customElements?: any[];
627
+ /** Whether to show the toolbar */
628
+ showToolbar?: boolean;
629
+ /** Whether to show the topbar (canvas size, undo, redo, delete, import, export) */
630
+ showTopbar?: boolean;
631
+ /** Whether to show the inspector panel */
632
+ showInspector?: boolean;
633
+ /** Whether to show the layers panel */
634
+ showLayers?: boolean;
635
+ /** Whether to show the asset picker (if defined in mode) */
636
+ showAssetPicker?: boolean;
637
+ /** Whether to show the canvas */
638
+ showCanvas?: boolean;
639
+ /** Whether to enable snap guides */
640
+ enableSnapGuides?: boolean;
641
+ /** Whether to enable pan and zoom controls */
642
+ enablePanZoom?: boolean;
643
+ /** Optional background image URL - replaces solid background color when provided */
644
+ backgroundImageUrl?: string;
645
+ /** Whether to hide all elements on the canvas */
646
+ hideElements?: boolean;
647
+ /** Custom CSS class */
648
+ className?: string;
649
+ /** Ref to access the editor API */
650
+ apiRef?: React$1.Ref<EditorAPI>;
651
+ }
652
+ /**
653
+ * Complete visual editor workspace with toolbar, canvas, and inspector
654
+ */
655
+ declare const VisualEditorWorkspace: React$1.FC<VisualEditorWorkspaceProps>;
656
+
657
+ /**
658
+ * Asset Picker Panel
659
+ *
660
+ * Displays project assets that can be dragged/clicked to use in the editor.
661
+ * Integrates with useProjectAssets to show game assets.
662
+ */
663
+
664
+ interface AssetPickerProps {
665
+ /** List of assets to display */
666
+ assets: Array<{
667
+ name: string;
668
+ path: string;
669
+ type?: string;
670
+ }>;
671
+ /** Callback when an asset is selected */
672
+ onAssetSelect?: (assetPath: string) => void;
673
+ /** Custom render function for asset items */
674
+ renderAsset?: (asset: {
675
+ name: string;
676
+ path: string;
677
+ type?: string;
678
+ }) => React$1.ReactNode;
679
+ /** Custom CSS class */
680
+ className?: string;
681
+ /** Title for the panel */
682
+ title?: string;
683
+ }
684
+ /**
685
+ * Asset Picker component that displays available assets
686
+ */
687
+ declare const AssetPicker: React$1.FC<AssetPickerProps>;
688
+
689
+ /**
690
+ * Visual Editor - Core State Management
691
+ *
692
+ * Provides the state management logic for the visual editor using useReducer.
693
+ * This hook encapsulates all state mutations and provides a clean API.
694
+ */
695
+
696
+ /**
697
+ * Custom hook for managing editor state
698
+ */
699
+ declare const useEditorState: (initialMode?: EditorMode | null) => {
700
+ state: EditorState;
701
+ api: EditorAPI;
702
+ setCanvasSize: (width: number, height: number) => void;
703
+ setMode: (mode: EditorMode) => void;
704
+ undo: () => void;
705
+ redo: () => void;
706
+ canUndo: boolean;
707
+ canRedo: boolean;
708
+ };
709
+
710
+ /**
711
+ * Visual Editor - Element Registry
712
+ *
713
+ * Manages registration and retrieval of element renderers.
714
+ * This is what makes the editor extensible - new element types
715
+ * can be registered dynamically.
716
+ */
717
+
718
+ /**
719
+ * Registry class for managing element renderers
720
+ */
721
+ declare class ElementRegistry {
722
+ private renderers;
723
+ /**
724
+ * Register a new element renderer
725
+ */
726
+ register(renderer: ElementRenderer): void;
727
+ /**
728
+ * Register multiple element renderers at once
729
+ */
730
+ registerMany(renderers: ElementRenderer[]): void;
731
+ /**
732
+ * Get a renderer by type
733
+ */
734
+ get(type: string): ElementRenderer | undefined;
735
+ /**
736
+ * Check if a renderer exists for a type
737
+ */
738
+ has(type: string): boolean;
739
+ /**
740
+ * Get all registered renderers
741
+ */
742
+ getAll(): ElementRenderer[];
743
+ /**
744
+ * Get the internal renderers map
745
+ */
746
+ getMap(): Map<string, ElementRenderer>;
747
+ /**
748
+ * Get all registered types
749
+ */
750
+ getAllTypes(): string[];
751
+ /**
752
+ * Unregister a renderer
753
+ */
754
+ unregister(type: string): boolean;
755
+ /**
756
+ * Clear all registered renderers
757
+ */
758
+ clear(): void;
759
+ /**
760
+ * Get the number of registered renderers
761
+ */
762
+ get size(): number;
763
+ }
764
+ /**
765
+ * Create a global singleton registry (can be used across the app)
766
+ */
767
+ declare const globalElementRegistry: ElementRegistry;
768
+ declare const useElementRegistry: (initialRenderers?: ElementRenderer[]) => ElementRegistry;
769
+
770
+ /**
771
+ * Snapping Utilities
772
+ *
773
+ * Helper functions for snapping elements to guides, other elements, and canvas edges.
774
+ */
775
+
776
+ interface SnapGuide {
777
+ /** Position of the guide line */
778
+ position: number;
779
+ /** Orientation of the guide (vertical or horizontal) */
780
+ orientation: "vertical" | "horizontal";
781
+ /** Snap type (element edge, center, or canvas edge) */
782
+ type: "edge" | "center" | "canvas";
783
+ }
784
+ interface SnapResult {
785
+ /** Snapped x position */
786
+ x: number;
787
+ /** Snapped y position */
788
+ y: number;
789
+ /** Vertical guides to display */
790
+ verticalGuides: SnapGuide[];
791
+ /** Horizontal guides to display */
792
+ horizontalGuides: SnapGuide[];
793
+ }
794
+ interface SnapOptions {
795
+ /** Snap threshold in pixels */
796
+ threshold?: number;
797
+ /** Whether to snap to other elements */
798
+ snapToElements?: boolean;
799
+ /** Whether to snap to canvas edges */
800
+ snapToCanvas?: boolean;
801
+ /** Canvas size */
802
+ canvasSize?: {
803
+ width: number;
804
+ height: number;
805
+ };
806
+ }
807
+ /**
808
+ * Calculate snapping for an element being dragged
809
+ */
810
+ declare function getSnappingPosition(draggedElement: EditorElement, x: number, y: number, allElements: EditorElement[], options?: SnapOptions): SnapResult;
811
+
812
+ /**
813
+ * Visual Editor - Text Element Renderer
814
+ *
815
+ * Built-in text element renderer using Konva.
816
+ */
817
+
818
+ /**
819
+ * Text element renderer component
820
+ */
821
+ declare const TextElementRenderer: React$1.FC<{
822
+ element: EditorElement<TextElementProps>;
823
+ isSelected: boolean;
824
+ onSelect: () => void;
825
+ onTransform: (updates: Partial<EditorElement>) => void;
826
+ allElements?: EditorElement[];
827
+ canvasSize?: {
828
+ width: number;
829
+ height: number;
830
+ };
831
+ onSnapGuides?: (guides: {
832
+ vertical: SnapGuide[];
833
+ horizontal: SnapGuide[];
834
+ }) => void;
835
+ onClearSnapGuides?: () => void;
836
+ elementId?: string;
837
+ }>;
838
+ /**
839
+ * Text element renderer definition
840
+ */
841
+ declare const textElementRenderer: ElementRenderer<TextElementProps>;
842
+
843
+ /**
844
+ * Visual Editor - Image Element Renderer
845
+ *
846
+ * Built-in image element renderer using Konva.
847
+ */
848
+
849
+ /**
850
+ * Image element renderer component
851
+ */
852
+ declare const ImageElementRenderer: React$1.FC<{
853
+ element: EditorElement<ImageElementProps>;
854
+ isSelected: boolean;
855
+ onSelect: () => void;
856
+ onTransform: (updates: Partial<EditorElement>) => void;
857
+ allElements?: EditorElement[];
858
+ canvasSize?: {
859
+ width: number;
860
+ height: number;
861
+ };
862
+ onSnapGuides?: (guides: {
863
+ vertical: SnapGuide[];
864
+ horizontal: SnapGuide[];
865
+ }) => void;
866
+ onClearSnapGuides?: () => void;
867
+ imageUrls?: Map<string, string>;
868
+ elementId?: string;
869
+ onNodeUpdate?: () => void;
870
+ }>;
871
+ /**
872
+ * Image element renderer definition
873
+ */
874
+ declare const imageElementRenderer: ElementRenderer<ImageElementProps>;
875
+
876
+ declare const defaultElements: (ElementRenderer<TextElementProps> | ElementRenderer<ImageElementProps>)[];
877
+
878
+ /**
879
+ * Visual Editor - Utility Functions
880
+ *
881
+ * Common utility functions used throughout the visual editor.
882
+ */
883
+
884
+ /**
885
+ * Generate a unique ID for an element
886
+ */
887
+ declare const generateElementId: () => string;
888
+ /**
889
+ * Create a new element with default values
890
+ */
891
+ declare const createElement: <TProps = any>(type: string, props: TProps, options?: {
892
+ position?: {
893
+ x: number;
894
+ y: number;
895
+ };
896
+ size?: {
897
+ width: number;
898
+ height: number;
899
+ };
900
+ rotation?: number;
901
+ opacity?: number;
902
+ zIndex?: number;
903
+ visible?: boolean;
904
+ locked?: boolean;
905
+ displayName?: string;
906
+ }) => EditorElement<TProps>;
907
+ /**
908
+ * Deep clone an element
909
+ */
910
+ declare const cloneElement: <TProps = any>(element: EditorElement<TProps>) => EditorElement<TProps>;
911
+ /**
912
+ * Duplicate an element with a slight offset
913
+ */
914
+ declare const duplicateElement: <TProps = any>(element: EditorElement<TProps>, offset?: {
915
+ x: number;
916
+ y: number;
917
+ }) => EditorElement<TProps>;
918
+ /**
919
+ * Sort elements by z-index (ascending)
920
+ */
921
+ declare const sortByZIndex: (elements: EditorElement[]) => EditorElement[];
922
+ /**
923
+ * Get the highest z-index among elements
924
+ */
925
+ declare const getMaxZIndex: (elements: EditorElement[]) => number;
926
+ /**
927
+ * Bring an element to front
928
+ */
929
+ declare const bringToFront: (elements: EditorElement[], elementId: string) => EditorElement[];
930
+ /**
931
+ * Send an element to back
932
+ */
933
+ declare const sendToBack: (elements: EditorElement[], elementId: string) => EditorElement[];
934
+ /**
935
+ * Check if two rectangles overlap
936
+ */
937
+ declare const checkOverlap: (rect1: {
938
+ x: number;
939
+ y: number;
940
+ width: number;
941
+ height: number;
942
+ }, rect2: {
943
+ x: number;
944
+ y: number;
945
+ width: number;
946
+ height: number;
947
+ }) => boolean;
948
+ /**
949
+ * Check if a point is inside a rectangle
950
+ */
951
+ declare const pointInRect: (point: {
952
+ x: number;
953
+ y: number;
954
+ }, rect: {
955
+ x: number;
956
+ y: number;
957
+ width: number;
958
+ height: number;
959
+ }) => boolean;
960
+ /**
961
+ * Snap a value to grid
962
+ */
963
+ declare const snapToGrid: (value: number, gridSize: number) => number;
964
+ /**
965
+ * Snap position to grid
966
+ */
967
+ declare const snapPositionToGrid: (position: {
968
+ x: number;
969
+ y: number;
970
+ }, gridSize: number) => {
971
+ x: number;
972
+ y: number;
973
+ };
974
+ /**
975
+ * Constrain a value between min and max
976
+ */
977
+ declare const clamp: (value: number, min: number, max: number) => number;
978
+ /**
979
+ * Constrain position within canvas bounds
980
+ */
981
+ declare const constrainToCanvas: (position: {
982
+ x: number;
983
+ y: number;
984
+ }, size: {
985
+ width: number;
986
+ height: number;
987
+ }, canvasSize: {
988
+ width: number;
989
+ height: number;
990
+ }) => {
991
+ x: number;
992
+ y: number;
993
+ };
994
+ /**
995
+ * Calculate bounding box for rotated rectangle
996
+ */
997
+ declare const getRotatedBoundingBox: (x: number, y: number, width: number, height: number, rotation: number) => {
998
+ x: number;
999
+ y: number;
1000
+ width: number;
1001
+ height: number;
1002
+ };
1003
+ /**
1004
+ * Export canvas to JSON string
1005
+ */
1006
+ declare const exportToJSON: (data: CanvasExport) => string;
1007
+ /**
1008
+ * Import canvas from JSON string
1009
+ */
1010
+ declare const importFromJSON: (json: string) => CanvasExport;
1011
+ /**
1012
+ * Calculate center point of an element
1013
+ */
1014
+ declare const getElementCenter: (element: EditorElement) => {
1015
+ x: number;
1016
+ y: number;
1017
+ };
1018
+ /**
1019
+ * Calculate distance between two points
1020
+ */
1021
+ declare const distance: (p1: {
1022
+ x: number;
1023
+ y: number;
1024
+ }, p2: {
1025
+ x: number;
1026
+ y: number;
1027
+ }) => number;
1028
+ /**
1029
+ * Degrees to radians
1030
+ */
1031
+ declare const degToRad: (degrees: number) => number;
1032
+ /**
1033
+ * Radians to degrees
1034
+ */
1035
+ declare const radToDeg: (radians: number) => number;
1036
+ /**
1037
+ * Validate element data
1038
+ */
1039
+ declare const isValidElement: (element: any) => element is EditorElement;
1040
+ /**
1041
+ * Validate canvas export data
1042
+ */
1043
+ declare const isValidCanvasExport: (data: any) => data is CanvasExport;
1044
+
1045
+ export { AssetPicker, type AssetPickerProps, type CanvasExport, type CustomRendererProps, type EditorAPI, type EditorAction, type EditorElement, type EditorMode, type EditorState, ElementRegistry, type ElementRenderer, type ImageElementProps, ImageElementRenderer, Inspector, type InspectorFieldSchema, type InspectorFieldType, LayersPanel, type SnapGuide, type SnapOptions, type SnapResult, type TextElementProps, TextElementRenderer, VisualEditor, type VisualEditorProps, VisualEditorWorkspace, bringToFront, checkOverlap, clamp, cloneElement, constrainToCanvas, createElement, defaultElements, degToRad, distance, duplicateElement, exportToJSON, generateElementId, getElementCenter, getMaxZIndex, getRotatedBoundingBox, getSnappingPosition, globalElementRegistry, imageElementRenderer, importFromJSON, isValidCanvasExport, isValidElement, pointInRect, radToDeg, renderField, sendToBack, snapPositionToGrid, snapToGrid, sortByZIndex, textElementRenderer, useEditorState, useElementRegistry };