@overtone-art/canvas-editor-core 0.0.1 → 0.2.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.
package/dist/index.d.mts CHANGED
@@ -9,6 +9,12 @@ interface LayerData {
9
9
  visible: boolean;
10
10
  locked: boolean;
11
11
  opacity: number;
12
+ /** Non-fabric metadata persisted with the layer (pattern config, etc). */
13
+ meta?: LayerMeta;
14
+ }
15
+ interface LayerMeta {
16
+ pattern?: PatternState;
17
+ [key: string]: unknown;
12
18
  }
13
19
  interface SerializedLayer extends LayerData {
14
20
  fabricObject: Record<string, unknown>;
@@ -21,6 +27,7 @@ interface EditorState {
21
27
  };
22
28
  layers: SerializedLayer[];
23
29
  background?: string;
30
+ mockup?: MockupConfig | null;
24
31
  }
25
32
  interface EditorConfig {
26
33
  width: number;
@@ -71,6 +78,53 @@ interface PrintifyPositioning {
71
78
  scale: number;
72
79
  angle: number;
73
80
  }
81
+ type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
82
+ interface PatternConfig {
83
+ mode: TileMode;
84
+ /** Extra horizontal gap between tiles, as % of tile width. */
85
+ horizontalSpacing: number;
86
+ /** Extra vertical gap between tiles, as % of tile height. */
87
+ verticalSpacing: number;
88
+ /** Rotation of the whole pattern, in degrees. */
89
+ angle: number;
90
+ /** Brick row/column shift, as % of tile size. */
91
+ horizontalOffset: number;
92
+ /** Added rotation per horizontal step, in degrees. */
93
+ rotationStepH: number;
94
+ /** Added rotation per vertical step, in degrees. */
95
+ rotationStepV: number;
96
+ }
97
+ /** Persisted on a layer's meta while it is rendered as a repeating pattern. */
98
+ interface PatternState {
99
+ config: PatternConfig;
100
+ /** Original (pre-pattern) image source, as a durable data URL when possible. */
101
+ originalSrc: string;
102
+ /** Original fabric transform, restored when the pattern is turned off. */
103
+ original: {
104
+ left: number;
105
+ top: number;
106
+ scaleX: number;
107
+ scaleY: number;
108
+ width: number;
109
+ height: number;
110
+ angle: number;
111
+ cropX: number;
112
+ cropY: number;
113
+ };
114
+ }
115
+ declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
116
+ interface MockupPrintArea {
117
+ left: number;
118
+ top: number;
119
+ width: number;
120
+ height: number;
121
+ }
122
+ interface MockupConfig {
123
+ /** Garment/product image rendered behind the design (preview only). */
124
+ image: string;
125
+ /** Print-area rectangle, in canvas pixels. Drawn as a guide. */
126
+ printArea?: MockupPrintArea;
127
+ }
74
128
  interface EditorEvents {
75
129
  'layer:added': {
76
130
  layer: LayerData;
@@ -97,6 +151,19 @@ interface EditorEvents {
97
151
  canUndo: boolean;
98
152
  canRedo: boolean;
99
153
  };
154
+ 'zoom:changed': {
155
+ zoom: number;
156
+ };
157
+ 'snap:changed': {
158
+ enabled: boolean;
159
+ };
160
+ 'crop:changed': {
161
+ active: boolean;
162
+ layerId: string | null;
163
+ };
164
+ 'mockup:changed': {
165
+ mockup: MockupConfig | null;
166
+ };
100
167
  'canvas:modified': Record<string, never>;
101
168
  'export:start': {
102
169
  format: string;
@@ -128,8 +195,11 @@ declare class Layer {
128
195
  visible: boolean;
129
196
  locked: boolean;
130
197
  opacity: number;
198
+ /** Non-fabric data (e.g. pattern config) that must persist with the layer. */
199
+ meta: LayerMeta;
131
200
  readonly fabricObject: FabricObject;
132
201
  constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
202
+ private hasMeta;
133
203
  toData(): LayerData;
134
204
  serialize(): SerializedLayer;
135
205
  }
@@ -175,15 +245,128 @@ declare class HistoryManager {
175
245
  saveImmediate(): void;
176
246
  undo(): Promise<void>;
177
247
  redo(): Promise<void>;
248
+ /** True while a restore (undo/redo/deserialize) is in flight. Managers that
249
+ * react to canvas events should skip mutating history during this window. */
250
+ isRestoring(): boolean;
178
251
  pause(): void;
179
252
  resume(): void;
180
253
  canUndo(): boolean;
181
254
  canRedo(): boolean;
182
255
  clear(): void;
256
+ private cancelPending;
183
257
  dispose(): void;
184
258
  private emitChanged;
185
259
  }
186
260
 
261
+ /**
262
+ * Snaps a dragged object's edges and centre to the canvas edges/centre and to
263
+ * other objects, drawing transient guide lines while it does. Switchable via
264
+ * {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.
265
+ */
266
+ declare class SnapManager {
267
+ private canvas;
268
+ private events;
269
+ private enabled;
270
+ private threshold;
271
+ private guides;
272
+ private readonly onMoving;
273
+ private readonly onAfterRender;
274
+ private readonly onModified;
275
+ constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
276
+ setEnabled(enabled: boolean): void;
277
+ isEnabled(): boolean;
278
+ setThreshold(px: number): void;
279
+ dispose(): void;
280
+ private handleMoving;
281
+ private drawGuides;
282
+ private clearGuides;
283
+ }
284
+
285
+ /**
286
+ * Interactive crop for image layers. {@link start} drops a draggable/resizable
287
+ * rectangle over the image; {@link apply} converts it into fabric crop props
288
+ * (cropX/cropY/width/height in element pixels) and keeps the displayed size in
289
+ * sync with the rectangle.
290
+ *
291
+ * Rotation is unsupported: an angled image is normalised to 0° on start.
292
+ */
293
+ declare class CropController {
294
+ private canvas;
295
+ private history;
296
+ private events;
297
+ private session;
298
+ private readonly onSelectionCleared;
299
+ constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
300
+ isActive(): boolean;
301
+ activeLayerId(): string | null;
302
+ start(layer: Layer): void;
303
+ apply(): void;
304
+ cancel(): void;
305
+ dispose(): void;
306
+ private finish;
307
+ }
308
+
309
+ /**
310
+ * Renders a single image layer as a repeating pattern that fills the canvas.
311
+ *
312
+ * The tiled result is rasterised onto an offscreen canvas and swapped in as the
313
+ * layer's image source, so it survives export, serialization and undo/redo with
314
+ * no extra machinery. The original source + transform are kept in `layer.meta`
315
+ * so the pattern can be turned back off.
316
+ */
317
+ declare class PatternManager {
318
+ private canvas;
319
+ private layers;
320
+ private history;
321
+ private chains;
322
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
323
+ isPattern(layerId: string): boolean;
324
+ getConfig(layerId: string): PatternConfig | null;
325
+ /** Turn a plain image layer into a pattern, or update an existing one. */
326
+ apply(layerId: string, config: PatternConfig): Promise<void>;
327
+ /** Restore the original image and drop the pattern. */
328
+ disable(layerId: string): Promise<void>;
329
+ /** Run `task` after any in-flight work for this layer, regardless of outcome. */
330
+ private enqueue;
331
+ private renderLayer;
332
+ }
333
+ /** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
334
+ declare function clearPatternImageCache(): void;
335
+ /**
336
+ * Draw the source image repeatedly across a `targetW × targetH` offscreen
337
+ * canvas and return the result as a PNG data URL.
338
+ *
339
+ * Exported for unit testing of the tile geometry.
340
+ */
341
+ declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
342
+ /** Placement of one tile, relative to the (already rotated) pattern centre. */
343
+ interface TilePlacement {
344
+ /** Tile-centre offset from the pattern centre, in px. */
345
+ x: number;
346
+ y: number;
347
+ /** Per-tile rotation, in radians. */
348
+ rotation: number;
349
+ }
350
+ /**
351
+ * Pure tile geometry: where each tile centre lands and how much it is rotated,
352
+ * for a config + target/base size. Covers the rotated bounding diagonal so
353
+ * corners stay filled at any pattern angle. Extracted for unit testing.
354
+ */
355
+ declare function computeTilePositions(config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): TilePlacement[];
356
+ /**
357
+ * Draw the tiled pattern onto a 2D context. The geometry lives in
358
+ * {@link computeTilePositions}; this just plays it out as canvas calls.
359
+ */
360
+ declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): void;
361
+ /** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
362
+ interface CanvasRenderingProtocol {
363
+ save(): void;
364
+ restore(): void;
365
+ translate(x: number, y: number): void;
366
+ rotate(angle: number): void;
367
+ drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
368
+ }
369
+
187
370
  declare class UnitConverter {
188
371
  private unit;
189
372
  private dpi;
@@ -211,8 +394,14 @@ declare class CanvasEditor {
211
394
  readonly history: HistoryManager;
212
395
  readonly events: EventEmitter<EditorEvents>;
213
396
  readonly units: UnitConverter;
397
+ readonly snapping: SnapManager;
398
+ readonly crop: CropController;
399
+ readonly patterns: PatternManager;
214
400
  private fileAdapter?;
215
401
  private imageProvider?;
402
+ private zoomLevel;
403
+ private mockup;
404
+ private designBackground;
216
405
  constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
217
406
  addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
218
407
  addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
@@ -221,11 +410,21 @@ declare class CanvasEditor {
221
410
  removeLayer(id: string): void;
222
411
  selectLayer(id: string | null): void;
223
412
  getSelectedLayer(): Layer | null;
413
+ /** Mirror a layer along the given axis. */
414
+ flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
415
+ /** Clone a layer (offset slightly) and select the copy. */
416
+ duplicateLayer(id: string): Promise<Layer | null>;
224
417
  toJSON(): EditorState;
225
418
  fromJSON(state: EditorState): Promise<void>;
226
419
  toPNG(options?: PngExportOptions): Promise<Blob>;
227
420
  toSVG(): string;
228
421
  toDataURL(format?: ImageFormat, multiplier?: number): string;
422
+ /**
423
+ * Run an export with the configured design background applied, even when a
424
+ * mockup preview has forced the live canvas transparent — so exports reflect
425
+ * the design, not the preview. Restores the preview state afterwards.
426
+ */
427
+ private withDesignBackground;
229
428
  toPrintifyPositioning(): Record<string, PrintifyPositioning>;
230
429
  save(filename: string, format: 'png' | 'svg' | 'json'): Promise<string | undefined>;
231
430
  uploadImage(file: File): Promise<ImageProviderResult | undefined>;
@@ -233,8 +432,22 @@ declare class CanvasEditor {
233
432
  setFileAdapter(adapter: FileAdapter): void;
234
433
  setImageProvider(provider: ImageProvider): void;
235
434
  setBackground(color: string): void;
435
+ getDesignBackground(): string;
236
436
  resize(width: number, height: number): void;
437
+ setZoom(level: number): void;
438
+ /** @deprecated use setZoom — kept for backward compatibility. */
237
439
  zoom(level: number): void;
440
+ getZoom(): number;
441
+ zoomIn(step?: number): void;
442
+ zoomOut(step?: number): void;
443
+ resetZoom(): void;
444
+ /** Fit the canvas inside a viewport (in px), accounting for padding. */
445
+ zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
446
+ applyPattern(layerId: string, config: PatternConfig): Promise<void>;
447
+ clearPattern(layerId: string): Promise<void>;
448
+ setMockup(mockup: MockupConfig | null): void;
449
+ clearMockup(): void;
450
+ getMockup(): MockupConfig | null;
238
451
  dispose(): void;
239
452
  private setupCanvasEvents;
240
453
  }
@@ -247,4 +460,4 @@ declare function round2(v: number): number;
247
460
  declare function serializeEditor(editor: CanvasEditor): EditorState;
248
461
  declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
249
462
 
250
- export { CanvasEditor, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerType, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, type TemplateDefinition, type TemplateParameter, type Unit, UnitConverter, clamp, deserializeEditor, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
463
+ export { CanvasEditor, CropController, DEFAULT_PATTERN_CONFIG, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerMeta, type LayerType, type MockupConfig, type MockupPrintArea, type PatternConfig, PatternManager, type PatternState, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, SnapManager, type TemplateDefinition, type TemplateParameter, type TileMode, type TilePlacement, type Unit, UnitConverter, buildPatternDataURL, clamp, clearPatternImageCache, computeTilePositions, deserializeEditor, drawTiles, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
package/dist/index.d.ts CHANGED
@@ -9,6 +9,12 @@ interface LayerData {
9
9
  visible: boolean;
10
10
  locked: boolean;
11
11
  opacity: number;
12
+ /** Non-fabric metadata persisted with the layer (pattern config, etc). */
13
+ meta?: LayerMeta;
14
+ }
15
+ interface LayerMeta {
16
+ pattern?: PatternState;
17
+ [key: string]: unknown;
12
18
  }
13
19
  interface SerializedLayer extends LayerData {
14
20
  fabricObject: Record<string, unknown>;
@@ -21,6 +27,7 @@ interface EditorState {
21
27
  };
22
28
  layers: SerializedLayer[];
23
29
  background?: string;
30
+ mockup?: MockupConfig | null;
24
31
  }
25
32
  interface EditorConfig {
26
33
  width: number;
@@ -71,6 +78,53 @@ interface PrintifyPositioning {
71
78
  scale: number;
72
79
  angle: number;
73
80
  }
81
+ type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
82
+ interface PatternConfig {
83
+ mode: TileMode;
84
+ /** Extra horizontal gap between tiles, as % of tile width. */
85
+ horizontalSpacing: number;
86
+ /** Extra vertical gap between tiles, as % of tile height. */
87
+ verticalSpacing: number;
88
+ /** Rotation of the whole pattern, in degrees. */
89
+ angle: number;
90
+ /** Brick row/column shift, as % of tile size. */
91
+ horizontalOffset: number;
92
+ /** Added rotation per horizontal step, in degrees. */
93
+ rotationStepH: number;
94
+ /** Added rotation per vertical step, in degrees. */
95
+ rotationStepV: number;
96
+ }
97
+ /** Persisted on a layer's meta while it is rendered as a repeating pattern. */
98
+ interface PatternState {
99
+ config: PatternConfig;
100
+ /** Original (pre-pattern) image source, as a durable data URL when possible. */
101
+ originalSrc: string;
102
+ /** Original fabric transform, restored when the pattern is turned off. */
103
+ original: {
104
+ left: number;
105
+ top: number;
106
+ scaleX: number;
107
+ scaleY: number;
108
+ width: number;
109
+ height: number;
110
+ angle: number;
111
+ cropX: number;
112
+ cropY: number;
113
+ };
114
+ }
115
+ declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
116
+ interface MockupPrintArea {
117
+ left: number;
118
+ top: number;
119
+ width: number;
120
+ height: number;
121
+ }
122
+ interface MockupConfig {
123
+ /** Garment/product image rendered behind the design (preview only). */
124
+ image: string;
125
+ /** Print-area rectangle, in canvas pixels. Drawn as a guide. */
126
+ printArea?: MockupPrintArea;
127
+ }
74
128
  interface EditorEvents {
75
129
  'layer:added': {
76
130
  layer: LayerData;
@@ -97,6 +151,19 @@ interface EditorEvents {
97
151
  canUndo: boolean;
98
152
  canRedo: boolean;
99
153
  };
154
+ 'zoom:changed': {
155
+ zoom: number;
156
+ };
157
+ 'snap:changed': {
158
+ enabled: boolean;
159
+ };
160
+ 'crop:changed': {
161
+ active: boolean;
162
+ layerId: string | null;
163
+ };
164
+ 'mockup:changed': {
165
+ mockup: MockupConfig | null;
166
+ };
100
167
  'canvas:modified': Record<string, never>;
101
168
  'export:start': {
102
169
  format: string;
@@ -128,8 +195,11 @@ declare class Layer {
128
195
  visible: boolean;
129
196
  locked: boolean;
130
197
  opacity: number;
198
+ /** Non-fabric data (e.g. pattern config) that must persist with the layer. */
199
+ meta: LayerMeta;
131
200
  readonly fabricObject: FabricObject;
132
201
  constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
202
+ private hasMeta;
133
203
  toData(): LayerData;
134
204
  serialize(): SerializedLayer;
135
205
  }
@@ -175,15 +245,128 @@ declare class HistoryManager {
175
245
  saveImmediate(): void;
176
246
  undo(): Promise<void>;
177
247
  redo(): Promise<void>;
248
+ /** True while a restore (undo/redo/deserialize) is in flight. Managers that
249
+ * react to canvas events should skip mutating history during this window. */
250
+ isRestoring(): boolean;
178
251
  pause(): void;
179
252
  resume(): void;
180
253
  canUndo(): boolean;
181
254
  canRedo(): boolean;
182
255
  clear(): void;
256
+ private cancelPending;
183
257
  dispose(): void;
184
258
  private emitChanged;
185
259
  }
186
260
 
261
+ /**
262
+ * Snaps a dragged object's edges and centre to the canvas edges/centre and to
263
+ * other objects, drawing transient guide lines while it does. Switchable via
264
+ * {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.
265
+ */
266
+ declare class SnapManager {
267
+ private canvas;
268
+ private events;
269
+ private enabled;
270
+ private threshold;
271
+ private guides;
272
+ private readonly onMoving;
273
+ private readonly onAfterRender;
274
+ private readonly onModified;
275
+ constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
276
+ setEnabled(enabled: boolean): void;
277
+ isEnabled(): boolean;
278
+ setThreshold(px: number): void;
279
+ dispose(): void;
280
+ private handleMoving;
281
+ private drawGuides;
282
+ private clearGuides;
283
+ }
284
+
285
+ /**
286
+ * Interactive crop for image layers. {@link start} drops a draggable/resizable
287
+ * rectangle over the image; {@link apply} converts it into fabric crop props
288
+ * (cropX/cropY/width/height in element pixels) and keeps the displayed size in
289
+ * sync with the rectangle.
290
+ *
291
+ * Rotation is unsupported: an angled image is normalised to 0° on start.
292
+ */
293
+ declare class CropController {
294
+ private canvas;
295
+ private history;
296
+ private events;
297
+ private session;
298
+ private readonly onSelectionCleared;
299
+ constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
300
+ isActive(): boolean;
301
+ activeLayerId(): string | null;
302
+ start(layer: Layer): void;
303
+ apply(): void;
304
+ cancel(): void;
305
+ dispose(): void;
306
+ private finish;
307
+ }
308
+
309
+ /**
310
+ * Renders a single image layer as a repeating pattern that fills the canvas.
311
+ *
312
+ * The tiled result is rasterised onto an offscreen canvas and swapped in as the
313
+ * layer's image source, so it survives export, serialization and undo/redo with
314
+ * no extra machinery. The original source + transform are kept in `layer.meta`
315
+ * so the pattern can be turned back off.
316
+ */
317
+ declare class PatternManager {
318
+ private canvas;
319
+ private layers;
320
+ private history;
321
+ private chains;
322
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
323
+ isPattern(layerId: string): boolean;
324
+ getConfig(layerId: string): PatternConfig | null;
325
+ /** Turn a plain image layer into a pattern, or update an existing one. */
326
+ apply(layerId: string, config: PatternConfig): Promise<void>;
327
+ /** Restore the original image and drop the pattern. */
328
+ disable(layerId: string): Promise<void>;
329
+ /** Run `task` after any in-flight work for this layer, regardless of outcome. */
330
+ private enqueue;
331
+ private renderLayer;
332
+ }
333
+ /** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
334
+ declare function clearPatternImageCache(): void;
335
+ /**
336
+ * Draw the source image repeatedly across a `targetW × targetH` offscreen
337
+ * canvas and return the result as a PNG data URL.
338
+ *
339
+ * Exported for unit testing of the tile geometry.
340
+ */
341
+ declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
342
+ /** Placement of one tile, relative to the (already rotated) pattern centre. */
343
+ interface TilePlacement {
344
+ /** Tile-centre offset from the pattern centre, in px. */
345
+ x: number;
346
+ y: number;
347
+ /** Per-tile rotation, in radians. */
348
+ rotation: number;
349
+ }
350
+ /**
351
+ * Pure tile geometry: where each tile centre lands and how much it is rotated,
352
+ * for a config + target/base size. Covers the rotated bounding diagonal so
353
+ * corners stay filled at any pattern angle. Extracted for unit testing.
354
+ */
355
+ declare function computeTilePositions(config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): TilePlacement[];
356
+ /**
357
+ * Draw the tiled pattern onto a 2D context. The geometry lives in
358
+ * {@link computeTilePositions}; this just plays it out as canvas calls.
359
+ */
360
+ declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): void;
361
+ /** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
362
+ interface CanvasRenderingProtocol {
363
+ save(): void;
364
+ restore(): void;
365
+ translate(x: number, y: number): void;
366
+ rotate(angle: number): void;
367
+ drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
368
+ }
369
+
187
370
  declare class UnitConverter {
188
371
  private unit;
189
372
  private dpi;
@@ -211,8 +394,14 @@ declare class CanvasEditor {
211
394
  readonly history: HistoryManager;
212
395
  readonly events: EventEmitter<EditorEvents>;
213
396
  readonly units: UnitConverter;
397
+ readonly snapping: SnapManager;
398
+ readonly crop: CropController;
399
+ readonly patterns: PatternManager;
214
400
  private fileAdapter?;
215
401
  private imageProvider?;
402
+ private zoomLevel;
403
+ private mockup;
404
+ private designBackground;
216
405
  constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
217
406
  addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
218
407
  addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
@@ -221,11 +410,21 @@ declare class CanvasEditor {
221
410
  removeLayer(id: string): void;
222
411
  selectLayer(id: string | null): void;
223
412
  getSelectedLayer(): Layer | null;
413
+ /** Mirror a layer along the given axis. */
414
+ flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
415
+ /** Clone a layer (offset slightly) and select the copy. */
416
+ duplicateLayer(id: string): Promise<Layer | null>;
224
417
  toJSON(): EditorState;
225
418
  fromJSON(state: EditorState): Promise<void>;
226
419
  toPNG(options?: PngExportOptions): Promise<Blob>;
227
420
  toSVG(): string;
228
421
  toDataURL(format?: ImageFormat, multiplier?: number): string;
422
+ /**
423
+ * Run an export with the configured design background applied, even when a
424
+ * mockup preview has forced the live canvas transparent — so exports reflect
425
+ * the design, not the preview. Restores the preview state afterwards.
426
+ */
427
+ private withDesignBackground;
229
428
  toPrintifyPositioning(): Record<string, PrintifyPositioning>;
230
429
  save(filename: string, format: 'png' | 'svg' | 'json'): Promise<string | undefined>;
231
430
  uploadImage(file: File): Promise<ImageProviderResult | undefined>;
@@ -233,8 +432,22 @@ declare class CanvasEditor {
233
432
  setFileAdapter(adapter: FileAdapter): void;
234
433
  setImageProvider(provider: ImageProvider): void;
235
434
  setBackground(color: string): void;
435
+ getDesignBackground(): string;
236
436
  resize(width: number, height: number): void;
437
+ setZoom(level: number): void;
438
+ /** @deprecated use setZoom — kept for backward compatibility. */
237
439
  zoom(level: number): void;
440
+ getZoom(): number;
441
+ zoomIn(step?: number): void;
442
+ zoomOut(step?: number): void;
443
+ resetZoom(): void;
444
+ /** Fit the canvas inside a viewport (in px), accounting for padding. */
445
+ zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
446
+ applyPattern(layerId: string, config: PatternConfig): Promise<void>;
447
+ clearPattern(layerId: string): Promise<void>;
448
+ setMockup(mockup: MockupConfig | null): void;
449
+ clearMockup(): void;
450
+ getMockup(): MockupConfig | null;
238
451
  dispose(): void;
239
452
  private setupCanvasEvents;
240
453
  }
@@ -247,4 +460,4 @@ declare function round2(v: number): number;
247
460
  declare function serializeEditor(editor: CanvasEditor): EditorState;
248
461
  declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
249
462
 
250
- export { CanvasEditor, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerType, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, type TemplateDefinition, type TemplateParameter, type Unit, UnitConverter, clamp, deserializeEditor, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
463
+ export { CanvasEditor, CropController, DEFAULT_PATTERN_CONFIG, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerMeta, type LayerType, type MockupConfig, type MockupPrintArea, type PatternConfig, PatternManager, type PatternState, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, SnapManager, type TemplateDefinition, type TemplateParameter, type TileMode, type TilePlacement, type Unit, UnitConverter, buildPatternDataURL, clamp, clearPatternImageCache, computeTilePositions, deserializeEditor, drawTiles, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };