@overtone-art/canvas-editor-core 0.2.6 → 0.2.8
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/LICENSE +21 -0
- package/dist/chunk-ORZZ6MGQ.mjs +228 -0
- package/dist/chunk-ORZZ6MGQ.mjs.map +1 -0
- package/dist/index.d.mts +297 -225
- package/dist/index.d.ts +297 -225
- package/dist/index.global.js +506 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1719 -99
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1501 -94
- package/dist/index.mjs.map +1 -1
- package/dist/node.d.mts +86 -0
- package/dist/node.d.ts +86 -0
- package/dist/node.js +814 -0
- package/dist/node.js.map +1 -0
- package/dist/node.mjs +675 -0
- package/dist/node.mjs.map +1 -0
- package/dist/types-D60CfxL9.d.mts +461 -0
- package/dist/types-D60CfxL9.d.ts +461 -0
- package/package.json +49 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,221 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
type LayerType = 'image' | 'text' | 'shape' | 'template' | 'group';
|
|
5
|
-
interface LayerData {
|
|
6
|
-
id: string;
|
|
7
|
-
type: LayerType;
|
|
8
|
-
name: string;
|
|
9
|
-
visible: boolean;
|
|
10
|
-
locked: boolean;
|
|
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;
|
|
18
|
-
}
|
|
19
|
-
interface SerializedLayer extends LayerData {
|
|
20
|
-
fabricObject: Record<string, unknown>;
|
|
21
|
-
}
|
|
22
|
-
interface EditorState {
|
|
23
|
-
version: string;
|
|
24
|
-
canvas: {
|
|
25
|
-
width: number;
|
|
26
|
-
height: number;
|
|
27
|
-
};
|
|
28
|
-
layers: SerializedLayer[];
|
|
29
|
-
background?: string;
|
|
30
|
-
mockup?: MockupConfig | null;
|
|
31
|
-
}
|
|
32
|
-
interface EditorConfig {
|
|
33
|
-
width: number;
|
|
34
|
-
height: number;
|
|
35
|
-
backgroundColor?: string;
|
|
36
|
-
fileAdapter?: FileAdapter;
|
|
37
|
-
imageProvider?: ImageProvider;
|
|
38
|
-
preserveObjectStacking?: boolean;
|
|
39
|
-
unit?: Unit;
|
|
40
|
-
dpi?: number;
|
|
41
|
-
}
|
|
42
|
-
type ExportFormat = 'png' | 'svg' | 'json';
|
|
43
|
-
interface FileAdapter {
|
|
44
|
-
save(data: Blob | string, filename: string, format: ExportFormat): Promise<string>;
|
|
45
|
-
}
|
|
46
|
-
interface ImageProviderResult {
|
|
47
|
-
url: string;
|
|
48
|
-
width: number;
|
|
49
|
-
height: number;
|
|
50
|
-
}
|
|
51
|
-
interface ImageProvider {
|
|
52
|
-
upload(file: File): Promise<ImageProviderResult>;
|
|
53
|
-
browse?(): Promise<ImageProviderResult | null>;
|
|
54
|
-
}
|
|
55
|
-
interface ShapePlugin {
|
|
56
|
-
name: string;
|
|
57
|
-
icon: string;
|
|
58
|
-
category?: string;
|
|
59
|
-
create(options?: Record<string, unknown>): FabricObject;
|
|
60
|
-
}
|
|
61
|
-
interface TemplateParameter {
|
|
62
|
-
key: string;
|
|
63
|
-
label: string;
|
|
64
|
-
type: 'text' | 'color' | 'number' | 'font';
|
|
65
|
-
default: string | number;
|
|
66
|
-
}
|
|
67
|
-
interface TemplateDefinition {
|
|
68
|
-
id: string;
|
|
69
|
-
name: string;
|
|
70
|
-
category: string;
|
|
71
|
-
svg: string;
|
|
72
|
-
parameters: TemplateParameter[];
|
|
73
|
-
preview?: string;
|
|
74
|
-
}
|
|
75
|
-
interface PrintifyPositioning {
|
|
76
|
-
x: number;
|
|
77
|
-
y: number;
|
|
78
|
-
scale: number;
|
|
79
|
-
angle: number;
|
|
80
|
-
}
|
|
81
|
-
type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
|
|
82
|
-
interface PatternConfig {
|
|
83
|
-
mode: TileMode;
|
|
84
|
-
/**
|
|
85
|
-
* Tile size as a % of the source image's on-canvas size (100 = natural).
|
|
86
|
-
* Smaller values pack more repeats across the print area; larger values make
|
|
87
|
-
* fewer, bigger tiles. Independent of how the source layer was placed.
|
|
88
|
-
*/
|
|
89
|
-
scale: number;
|
|
90
|
-
/** Extra horizontal gap between tiles, as % of tile width. */
|
|
91
|
-
horizontalSpacing: number;
|
|
92
|
-
/** Extra vertical gap between tiles, as % of tile height. */
|
|
93
|
-
verticalSpacing: number;
|
|
94
|
-
/** Rotation of the whole pattern, in degrees. */
|
|
95
|
-
angle: number;
|
|
96
|
-
/** Brick row/column shift, as % of tile size. */
|
|
97
|
-
horizontalOffset: number;
|
|
98
|
-
/**
|
|
99
|
-
* Phase shift of the whole tile grid inside the print area, as % of tile
|
|
100
|
-
* width. The pattern object itself is pinned to the print area (it can't be
|
|
101
|
-
* dragged — that would expose bare edges), so this is how the tiling is
|
|
102
|
-
* nudged into alignment. Clamped to ±100% so coverage is never broken.
|
|
103
|
-
*/
|
|
104
|
-
offsetX: number;
|
|
105
|
-
/** Phase shift of the tile grid, as % of tile height. See {@link offsetX}. */
|
|
106
|
-
offsetY: number;
|
|
107
|
-
/** Added rotation per horizontal step, in degrees. */
|
|
108
|
-
rotationStepH: number;
|
|
109
|
-
/** Added rotation per vertical step, in degrees. */
|
|
110
|
-
rotationStepV: number;
|
|
111
|
-
}
|
|
112
|
-
/** Fabric interaction flags frozen while a layer is rendered as a pattern. */
|
|
113
|
-
interface PatternLocks {
|
|
114
|
-
lockMovementX: boolean;
|
|
115
|
-
lockMovementY: boolean;
|
|
116
|
-
lockScalingX: boolean;
|
|
117
|
-
lockScalingY: boolean;
|
|
118
|
-
lockRotation: boolean;
|
|
119
|
-
hasControls: boolean;
|
|
120
|
-
}
|
|
121
|
-
/** Persisted on a layer's meta while it is rendered as a repeating pattern. */
|
|
122
|
-
interface PatternState {
|
|
123
|
-
config: PatternConfig;
|
|
124
|
-
/** Original (pre-pattern) image source, as a durable data URL when possible. */
|
|
125
|
-
originalSrc: string;
|
|
126
|
-
/**
|
|
127
|
-
* Serialized `clipPath` the image carried before it became a pattern, or null
|
|
128
|
-
* if it had none. A pattern must fill the whole print area, so any pre-pattern
|
|
129
|
-
* clip (e.g. a template crop sized to the original box) is stripped while the
|
|
130
|
-
* pattern is on and re-applied when it is turned off. Persisted so it survives
|
|
131
|
-
* serialization / reload / undo.
|
|
132
|
-
*/
|
|
133
|
-
originalClip?: Record<string, unknown> | null;
|
|
134
|
-
/**
|
|
135
|
-
* Interaction flags the object carried before it became a pattern. A pattern
|
|
136
|
-
* fills the whole print area, so while it is on the object is locked in place
|
|
137
|
-
* (a drag/resize would slide the tiled bitmap off the area and leave a bare
|
|
138
|
-
* band); the captured flags are restored when the pattern is turned off.
|
|
139
|
-
*/
|
|
140
|
-
originalLocks?: PatternLocks;
|
|
141
|
-
/** Original fabric transform, restored when the pattern is turned off. */
|
|
142
|
-
original: {
|
|
143
|
-
left: number;
|
|
144
|
-
top: number;
|
|
145
|
-
scaleX: number;
|
|
146
|
-
scaleY: number;
|
|
147
|
-
width: number;
|
|
148
|
-
height: number;
|
|
149
|
-
angle: number;
|
|
150
|
-
cropX: number;
|
|
151
|
-
cropY: number;
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
|
|
155
|
-
interface MockupPrintArea {
|
|
156
|
-
left: number;
|
|
157
|
-
top: number;
|
|
158
|
-
width: number;
|
|
159
|
-
height: number;
|
|
160
|
-
}
|
|
161
|
-
interface MockupConfig {
|
|
162
|
-
/** Garment/product image rendered behind the design (preview only). */
|
|
163
|
-
image: string;
|
|
164
|
-
/** Print-area rectangle, in canvas pixels. Drawn as a guide. */
|
|
165
|
-
printArea?: MockupPrintArea;
|
|
166
|
-
}
|
|
167
|
-
interface EditorEvents {
|
|
168
|
-
'layer:added': {
|
|
169
|
-
layer: LayerData;
|
|
170
|
-
};
|
|
171
|
-
'layer:removed': {
|
|
172
|
-
layerId: string;
|
|
173
|
-
};
|
|
174
|
-
'layer:selected': {
|
|
175
|
-
layerId: string | null;
|
|
176
|
-
};
|
|
177
|
-
'layer:modified': {
|
|
178
|
-
layerId: string;
|
|
179
|
-
};
|
|
180
|
-
'layer:reordered': {
|
|
181
|
-
layerIds: string[];
|
|
182
|
-
};
|
|
183
|
-
'layers:changed': {
|
|
184
|
-
layers: LayerData[];
|
|
185
|
-
};
|
|
186
|
-
'selection:changed': {
|
|
187
|
-
selected: string[];
|
|
188
|
-
};
|
|
189
|
-
'history:changed': {
|
|
190
|
-
canUndo: boolean;
|
|
191
|
-
canRedo: boolean;
|
|
192
|
-
};
|
|
193
|
-
'zoom:changed': {
|
|
194
|
-
zoom: number;
|
|
195
|
-
};
|
|
196
|
-
'snap:changed': {
|
|
197
|
-
enabled: boolean;
|
|
198
|
-
};
|
|
199
|
-
'crop:changed': {
|
|
200
|
-
active: boolean;
|
|
201
|
-
layerId: string | null;
|
|
202
|
-
};
|
|
203
|
-
'mockup:changed': {
|
|
204
|
-
mockup: MockupConfig | null;
|
|
205
|
-
};
|
|
206
|
-
'canvas:modified': Record<string, never>;
|
|
207
|
-
'export:start': {
|
|
208
|
-
format: string;
|
|
209
|
-
};
|
|
210
|
-
'export:complete': {
|
|
211
|
-
format: string;
|
|
212
|
-
url?: string;
|
|
213
|
-
};
|
|
214
|
-
error: {
|
|
215
|
-
message: string;
|
|
216
|
-
error?: unknown;
|
|
217
|
-
};
|
|
218
|
-
}
|
|
1
|
+
import { Canvas, FabricObject, ImageFormat } from 'fabric';
|
|
2
|
+
import { b as EditorEvents, l as LayerType, k as LayerMeta, L as LayerData, U as SerializedLayer, G as PatternSourceResolver, P as PatternConfig, A as PatternLocks, _ as Unit, z as MockupPrintArea, v as MockupConfig, e as FontDefinition, m as LicenseConfig, o as LicenseStatus, Q as ProjectState, M as MaskBrushOptions, p as MaskPoint, r as MaskRefinementProvider, q as MaskRefinementPrompt, t as MaskRefinementResult, E as EditorConfig, V as ShapePlugin, X as TemplateDefinition, I as ImageAdjustments, c as EditorState, S as SemanticExportOptions, W as SvgExportOptions, K as PrintifyPositioning, N as NormalizedLayerPosition, J as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, T as SerializedBackgroundImageOptions, B as BackgroundImageOptions, R as ResizeOptions, a as DpiIssue, C as CanvasSizePreset, w as MockupDisplacement } from './types-D60CfxL9.mjs';
|
|
3
|
+
export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, n as LicensePayload, s as MaskRefinementRequest, u as MockupBlendMode, x as MockupDisplacementChannel, y as MockupOverlay, H as PatternState, O as ProjectPage, Y as TemplateParameter, Z as TileMode } from './types-D60CfxL9.mjs';
|
|
219
4
|
|
|
220
5
|
type EventHandler<T> = (data: T) => void;
|
|
221
6
|
declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
|
|
@@ -236,7 +21,7 @@ declare class Layer {
|
|
|
236
21
|
opacity: number;
|
|
237
22
|
/** Non-fabric data (e.g. pattern config) that must persist with the layer. */
|
|
238
23
|
meta: LayerMeta;
|
|
239
|
-
|
|
24
|
+
fabricObject: FabricObject;
|
|
240
25
|
constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
|
|
241
26
|
private hasMeta;
|
|
242
27
|
toData(): LayerData;
|
|
@@ -246,9 +31,13 @@ declare class LayerManager {
|
|
|
246
31
|
private canvas;
|
|
247
32
|
private events;
|
|
248
33
|
private layers;
|
|
34
|
+
private onPropertyChanged?;
|
|
249
35
|
constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
|
|
36
|
+
setHistoryCallback(callback: () => void): void;
|
|
250
37
|
add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer;
|
|
251
38
|
remove(id: string): boolean;
|
|
39
|
+
/** Replace a layer's render object while preserving its immutable ID and panel state. */
|
|
40
|
+
replaceObject(id: string, fabricObject: FabricObject): boolean;
|
|
252
41
|
reorder(id: string, newIndex: number): boolean;
|
|
253
42
|
select(id: string | null): void;
|
|
254
43
|
get(id: string): Layer | undefined;
|
|
@@ -264,24 +53,35 @@ declare class LayerManager {
|
|
|
264
53
|
}
|
|
265
54
|
|
|
266
55
|
declare class HistoryManager {
|
|
56
|
+
private static readonly ASSET_KEY;
|
|
267
57
|
private undoStack;
|
|
268
58
|
private redoStack;
|
|
59
|
+
private assets;
|
|
60
|
+
private assetIds;
|
|
61
|
+
private nextAssetId;
|
|
269
62
|
private maxSize;
|
|
63
|
+
private maxBytes;
|
|
270
64
|
private paused;
|
|
271
65
|
private debounceTimer;
|
|
272
66
|
private debounceMs;
|
|
273
67
|
private getState;
|
|
274
68
|
private restoreState;
|
|
275
69
|
private events;
|
|
70
|
+
private transactionDepth;
|
|
71
|
+
private transactionDirty;
|
|
276
72
|
constructor(opts: {
|
|
277
73
|
getState: () => string;
|
|
278
74
|
restoreState: (state: string) => Promise<void>;
|
|
279
75
|
events: EventEmitter<EditorEvents>;
|
|
280
76
|
maxSize?: number;
|
|
77
|
+
maxBytes?: number;
|
|
281
78
|
debounceMs?: number;
|
|
282
79
|
});
|
|
283
80
|
save(): void;
|
|
284
81
|
saveImmediate(): void;
|
|
82
|
+
beginTransaction(): void;
|
|
83
|
+
endTransaction(): void;
|
|
84
|
+
transaction<T>(operation: () => T | Promise<T>): Promise<T>;
|
|
285
85
|
undo(): Promise<void>;
|
|
286
86
|
redo(): Promise<void>;
|
|
287
87
|
/** True while a restore (undo/redo/deserialize) is in flight. Managers that
|
|
@@ -292,9 +92,27 @@ declare class HistoryManager {
|
|
|
292
92
|
canUndo(): boolean;
|
|
293
93
|
canRedo(): boolean;
|
|
294
94
|
clear(): void;
|
|
95
|
+
getSnapshotBytes(): number;
|
|
295
96
|
private cancelPending;
|
|
296
97
|
dispose(): void;
|
|
297
98
|
private emitChanged;
|
|
99
|
+
private snapshotBytes;
|
|
100
|
+
private trimToBudget;
|
|
101
|
+
/**
|
|
102
|
+
* History is internal and can content-address large raster strings without
|
|
103
|
+
* changing the public EditorState wire format. Unchanged images are retained
|
|
104
|
+
* once even when dozens of snapshots reference them.
|
|
105
|
+
*/
|
|
106
|
+
private compactState;
|
|
107
|
+
private expandState;
|
|
108
|
+
/**
|
|
109
|
+
* Runs on every commit, so it scans for the serialized reference marker
|
|
110
|
+
* instead of re-parsing every snapshot — parsing multi-megabyte raster states
|
|
111
|
+
* per save would cost more than the retention it reclaims. `JSON.stringify`
|
|
112
|
+
* emits the marker verbatim; the same text inside user data is escaped and
|
|
113
|
+
* therefore cannot match.
|
|
114
|
+
*/
|
|
115
|
+
private pruneAssets;
|
|
298
116
|
}
|
|
299
117
|
|
|
300
118
|
/**
|
|
@@ -357,8 +175,10 @@ declare class PatternManager {
|
|
|
357
175
|
private canvas;
|
|
358
176
|
private layers;
|
|
359
177
|
private history;
|
|
178
|
+
private events;
|
|
179
|
+
private sourceResolver?;
|
|
360
180
|
private chains;
|
|
361
|
-
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
|
|
181
|
+
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>, sourceResolver?: PatternSourceResolver | undefined);
|
|
362
182
|
isPattern(layerId: string): boolean;
|
|
363
183
|
getConfig(layerId: string): PatternConfig | null;
|
|
364
184
|
/** Turn a plain image layer into a pattern, or update an existing one. */
|
|
@@ -388,6 +208,7 @@ declare function applyPatternLocks(obj: FabricObject): void;
|
|
|
388
208
|
* leaving it frozen forever.
|
|
389
209
|
*/
|
|
390
210
|
declare function restoreLocks(obj: FabricObject, locks: PatternLocks | undefined): void;
|
|
211
|
+
declare function loadPatternImage(src: string, resolver?: PatternSourceResolver): Promise<HTMLImageElement>;
|
|
391
212
|
/** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
|
|
392
213
|
declare function clearPatternImageCache(): void;
|
|
393
214
|
/**
|
|
@@ -396,7 +217,7 @@ declare function clearPatternImageCache(): void;
|
|
|
396
217
|
*
|
|
397
218
|
* Exported for unit testing of the tile geometry.
|
|
398
219
|
*/
|
|
399
|
-
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
|
|
220
|
+
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, sourceResolver?: PatternSourceResolver): Promise<string>;
|
|
400
221
|
/** Placement of one tile, relative to the (already rotated) pattern centre. */
|
|
401
222
|
interface TilePlacement {
|
|
402
223
|
/** Tile-centre offset from the pattern centre, in px. */
|
|
@@ -442,10 +263,124 @@ interface PngExportOptions {
|
|
|
442
263
|
format?: ImageFormat;
|
|
443
264
|
quality?: number;
|
|
444
265
|
}
|
|
266
|
+
interface CoverPlacement {
|
|
267
|
+
left: number;
|
|
268
|
+
top: number;
|
|
269
|
+
width: number;
|
|
270
|
+
height: number;
|
|
271
|
+
}
|
|
272
|
+
declare function computePrintAreaClip(area: MockupPrintArea, scaleX: number, scaleY: number, targetWidth: number, targetHeight: number): MockupPrintArea;
|
|
273
|
+
/** Object-fit: cover geometry, exported for deterministic preview/composite tests. */
|
|
274
|
+
declare function computeCoverPlacement(sourceWidth: number, sourceHeight: number, targetWidth: number, targetHeight: number): CoverPlacement;
|
|
445
275
|
declare function exportPNG(canvas: Canvas, options?: PngExportOptions): Promise<Blob>;
|
|
276
|
+
/** Rasterize the browser mockup preview together with the transparent design. */
|
|
277
|
+
declare function exportMockup(canvas: Canvas, mockup: MockupConfig, options?: PngExportOptions): Promise<Blob>;
|
|
446
278
|
declare function exportSVG(canvas: Canvas): string;
|
|
447
279
|
declare function exportDataURL(canvas: Canvas, format?: ImageFormat, multiplier?: number): string;
|
|
448
280
|
|
|
281
|
+
/** Browser font loader and SVG embedding registry. */
|
|
282
|
+
declare class FontRegistry {
|
|
283
|
+
private definitions;
|
|
284
|
+
private loads;
|
|
285
|
+
register(definition: FontDefinition): void;
|
|
286
|
+
unregister(family: string): boolean;
|
|
287
|
+
getAll(): FontDefinition[];
|
|
288
|
+
load(family: string): Promise<FontFace>;
|
|
289
|
+
ready(): Promise<void>;
|
|
290
|
+
getEmbeddedCss(): Promise<string>;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Inert, honor-system licensing and usage seam; it never performs a network request. */
|
|
294
|
+
declare class LicenseManager {
|
|
295
|
+
private config;
|
|
296
|
+
private status;
|
|
297
|
+
private readyPromise;
|
|
298
|
+
constructor(config?: LicenseConfig);
|
|
299
|
+
getStatus(): LicenseStatus;
|
|
300
|
+
ready(): Promise<LicenseStatus>;
|
|
301
|
+
hasFeature(feature: string): boolean;
|
|
302
|
+
track(name: string): void;
|
|
303
|
+
private validate;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Multi-page document state bound to one live editor canvas. */
|
|
307
|
+
declare class ProjectManager {
|
|
308
|
+
private editor;
|
|
309
|
+
private pages;
|
|
310
|
+
private activePageId;
|
|
311
|
+
constructor(editor: CanvasEditor);
|
|
312
|
+
getAll(): Array<{
|
|
313
|
+
id: string;
|
|
314
|
+
name: string;
|
|
315
|
+
}>;
|
|
316
|
+
getActivePageId(): string;
|
|
317
|
+
add(name?: string, cloneCurrent?: boolean): string;
|
|
318
|
+
switchTo(id: string): Promise<boolean>;
|
|
319
|
+
duplicate(id: string): Promise<string | null>;
|
|
320
|
+
remove(id: string): Promise<boolean>;
|
|
321
|
+
rename(id: string, name: string): boolean;
|
|
322
|
+
reorder(id: string, newIndex: number): boolean;
|
|
323
|
+
toJSON(): ProjectState;
|
|
324
|
+
fromJSON(project: ProjectState): Promise<void>;
|
|
325
|
+
private saveCurrent;
|
|
326
|
+
private blankState;
|
|
327
|
+
private emitChanged;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
type MaskRefinementErrorCode = 'not-found' | 'cancelled' | 'provider' | 'invalid-result';
|
|
331
|
+
declare class MaskRefinementError extends Error {
|
|
332
|
+
readonly code: MaskRefinementErrorCode;
|
|
333
|
+
readonly cause?: unknown | undefined;
|
|
334
|
+
constructor(code: MaskRefinementErrorCode, message: string, cause?: unknown | undefined);
|
|
335
|
+
}
|
|
336
|
+
interface MaskPerformanceSample {
|
|
337
|
+
width: number;
|
|
338
|
+
height: number;
|
|
339
|
+
backingBytes: number;
|
|
340
|
+
strokeBackupBytes: number;
|
|
341
|
+
estimatedPeakBytes: number;
|
|
342
|
+
historyBytes: number;
|
|
343
|
+
interactionLatencyMs: number;
|
|
344
|
+
usedJsHeapBytes?: number;
|
|
345
|
+
elapsedMs: number;
|
|
346
|
+
}
|
|
347
|
+
/** Raster-mask editing without exposing Fabric brush classes in the public contract. */
|
|
348
|
+
declare class MaskController {
|
|
349
|
+
private readonly editor;
|
|
350
|
+
private backing;
|
|
351
|
+
private context;
|
|
352
|
+
private layerId;
|
|
353
|
+
private brush;
|
|
354
|
+
private previousPoint;
|
|
355
|
+
private strokeBackup;
|
|
356
|
+
private strokeStartedAt;
|
|
357
|
+
private lastInteractionLatencyMs;
|
|
358
|
+
private refinement;
|
|
359
|
+
private disposed;
|
|
360
|
+
constructor(editor: CanvasEditor);
|
|
361
|
+
create(width?: number, height?: number): Promise<Layer>;
|
|
362
|
+
attach(layerId: string): void;
|
|
363
|
+
beginStroke(options: MaskBrushOptions): void;
|
|
364
|
+
addPoint(point: MaskPoint): void;
|
|
365
|
+
endStroke(): Promise<void>;
|
|
366
|
+
cancelStroke(): void;
|
|
367
|
+
isStrokeActive(): boolean;
|
|
368
|
+
activeLayerId(): string | null;
|
|
369
|
+
detach(layerId?: string): void;
|
|
370
|
+
refine(layerId: string, provider: MaskRefinementProvider, prompts: MaskRefinementPrompt[], options?: {
|
|
371
|
+
signal?: AbortSignal;
|
|
372
|
+
onProgress?: (progress: number) => void;
|
|
373
|
+
}): Promise<MaskRefinementResult>;
|
|
374
|
+
cancelRefinement(): void;
|
|
375
|
+
measure(): MaskPerformanceSample | null;
|
|
376
|
+
dispose(): void;
|
|
377
|
+
private drawDot;
|
|
378
|
+
private makeCanvas;
|
|
379
|
+
private attachBacking;
|
|
380
|
+
private requireMask;
|
|
381
|
+
private assertActive;
|
|
382
|
+
}
|
|
383
|
+
|
|
449
384
|
declare class CanvasEditor {
|
|
450
385
|
readonly canvas: Canvas;
|
|
451
386
|
readonly layers: LayerManager;
|
|
@@ -455,16 +390,24 @@ declare class CanvasEditor {
|
|
|
455
390
|
readonly snapping: SnapManager;
|
|
456
391
|
readonly crop: CropController;
|
|
457
392
|
readonly patterns: PatternManager;
|
|
393
|
+
readonly fonts: FontRegistry;
|
|
394
|
+
readonly licensing: LicenseManager;
|
|
395
|
+
readonly pages: ProjectManager;
|
|
396
|
+
readonly masks: MaskController;
|
|
458
397
|
private fileAdapter?;
|
|
459
398
|
private imageProvider?;
|
|
460
399
|
private zoomLevel;
|
|
461
400
|
private mockup;
|
|
462
401
|
private designBackground;
|
|
402
|
+
private designBackgroundImage;
|
|
403
|
+
private backgroundImageOptions;
|
|
463
404
|
constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
|
|
464
405
|
addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
406
|
+
/** Replace an image source without changing its layer identity or visual transform. */
|
|
407
|
+
replaceImageSource(layerId: string, url: string): Promise<Layer>;
|
|
465
408
|
addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
|
|
466
409
|
addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer;
|
|
467
|
-
addTemplate(template: TemplateDefinition,
|
|
410
|
+
addTemplate(template: TemplateDefinition, params: Record<string, string | number>): Promise<Layer>;
|
|
468
411
|
removeLayer(id: string): void;
|
|
469
412
|
selectLayer(id: string | null): void;
|
|
470
413
|
getSelectedLayer(): Layer | null;
|
|
@@ -472,11 +415,26 @@ declare class CanvasEditor {
|
|
|
472
415
|
flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
|
|
473
416
|
/** Clone a layer (offset slightly) and select the copy. */
|
|
474
417
|
duplicateLayer(id: string): Promise<Layer | null>;
|
|
418
|
+
applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
|
|
419
|
+
/** Combine two or more layers into a single editable group layer. */
|
|
420
|
+
groupLayers(ids: string[], name?: string): Promise<Layer | null>;
|
|
421
|
+
/** Restore a group created by groupLayers back to its original layer records. */
|
|
422
|
+
ungroupLayer(id: string): Promise<Layer[]>;
|
|
475
423
|
toJSON(): EditorState;
|
|
476
424
|
fromJSON(state: EditorState): Promise<void>;
|
|
477
425
|
toPNG(options?: PngExportOptions): Promise<Blob>;
|
|
426
|
+
toJPEG(options?: Omit<PngExportOptions, 'format'>): Promise<Blob>;
|
|
427
|
+
toWebP(options?: Omit<PngExportOptions, 'format'>): Promise<Blob>;
|
|
428
|
+
/** Export one layer in document coordinates or at its native image resolution. */
|
|
429
|
+
exportLayer(id: string, options?: SemanticExportOptions): Promise<Blob>;
|
|
430
|
+
/** Export only the configured document background, excluding design layers. */
|
|
431
|
+
exportBackground(options?: SemanticExportOptions): Promise<Blob>;
|
|
432
|
+
private toRaster;
|
|
478
433
|
toSVG(): string;
|
|
434
|
+
toSVGAsync(options?: SvgExportOptions): Promise<string>;
|
|
479
435
|
toDataURL(format?: ImageFormat, multiplier?: number): string;
|
|
436
|
+
/** Export the current product-preview composite. Advanced warping is host-defined. */
|
|
437
|
+
toMockupImage(options?: PngExportOptions): Promise<Blob>;
|
|
480
438
|
/**
|
|
481
439
|
* Run an export with the configured design background applied, even when a
|
|
482
440
|
* mockup preview has forced the live canvas transparent — so exports reflect
|
|
@@ -484,14 +442,35 @@ declare class CanvasEditor {
|
|
|
484
442
|
*/
|
|
485
443
|
private withDesignBackground;
|
|
486
444
|
toPrintifyPositioning(): Record<string, PrintifyPositioning>;
|
|
487
|
-
|
|
445
|
+
/** Provider-neutral, ID-stable placement data in 0..1 canvas coordinates. */
|
|
446
|
+
toNormalizedPositioning(): NormalizedLayerPosition[];
|
|
447
|
+
toProviderPositioning<T>(adapter: PositioningAdapter<T>): T;
|
|
448
|
+
save(filename: string, format: 'png' | 'jpeg' | 'webp' | 'svg' | 'json'): Promise<string | undefined>;
|
|
488
449
|
uploadImage(file: File): Promise<ImageProviderResult | undefined>;
|
|
489
450
|
browseImages(): Promise<ImageProviderResult | null>;
|
|
451
|
+
searchImages(query: string, options?: ImageSearchOptions): Promise<ImageSearchResult | null>;
|
|
452
|
+
/** Track provider usage, then insert its hotlinked image as a normal layer. */
|
|
453
|
+
addProviderImage(image: ImageProviderResult, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
490
454
|
setFileAdapter(adapter: FileAdapter): void;
|
|
491
455
|
setImageProvider(provider: ImageProvider): void;
|
|
492
456
|
setBackground(color: string): void;
|
|
493
457
|
getDesignBackground(): string;
|
|
494
|
-
|
|
458
|
+
getDesignBackgroundImage(): FabricObject | null;
|
|
459
|
+
getBackgroundImageOptions(): SerializedBackgroundImageOptions | null;
|
|
460
|
+
setBackgroundImage(url: string | null, options?: BackgroundImageOptions): Promise<void>;
|
|
461
|
+
/** Used by state restoration and advanced integrations with an existing Fabric object. */
|
|
462
|
+
setBackgroundImageObject(image: FabricObject | null, save?: boolean, options?: SerializedBackgroundImageOptions | null): void;
|
|
463
|
+
setTransparentBackground(): void;
|
|
464
|
+
resize(width: number, height: number, options?: ResizeOptions): void;
|
|
465
|
+
/** Effective source resolution for an image at its current physical size. */
|
|
466
|
+
getImageDpi(layerId: string): number | null;
|
|
467
|
+
validateImageDpi(minimumDpi?: number): DpiIssue[];
|
|
468
|
+
/** Render a small data-URL preview without changing document dimensions. */
|
|
469
|
+
toThumbnail(maxWidth?: number, maxHeight?: number, format?: ImageFormat): string;
|
|
470
|
+
bringToFront(id: string): boolean;
|
|
471
|
+
sendToBack(id: string): boolean;
|
|
472
|
+
bringForward(id: string): boolean;
|
|
473
|
+
sendBackward(id: string): boolean;
|
|
495
474
|
setZoom(level: number): void;
|
|
496
475
|
/** @deprecated use setZoom — kept for backward compatibility. */
|
|
497
476
|
zoom(level: number): void;
|
|
@@ -501,6 +480,8 @@ declare class CanvasEditor {
|
|
|
501
480
|
resetZoom(): void;
|
|
502
481
|
/** Fit the canvas inside a viewport (in px), accounting for padding. */
|
|
503
482
|
zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
|
|
483
|
+
/** Zoom until the current selection fills the artboard viewport. */
|
|
484
|
+
zoomToSelection(padding?: number): void;
|
|
504
485
|
applyPattern(layerId: string, config: PatternConfig): Promise<void>;
|
|
505
486
|
clearPattern(layerId: string): Promise<void>;
|
|
506
487
|
setMockup(mockup: MockupConfig | null): void;
|
|
@@ -515,7 +496,98 @@ declare const generateId: () => string;
|
|
|
515
496
|
declare function clamp(v: number, min: number, max: number): number;
|
|
516
497
|
declare function round2(v: number): number;
|
|
517
498
|
|
|
499
|
+
/** XML text/attribute escaping for values interpolated into an SVG document. */
|
|
500
|
+
declare function escapeXml(value: string | number): string;
|
|
501
|
+
/**
|
|
502
|
+
* Strip active and externally-loaded content from an SVG before it is parsed
|
|
503
|
+
* into canvas objects.
|
|
504
|
+
*
|
|
505
|
+
* This is the single implementation of the control — every path that turns
|
|
506
|
+
* untrusted SVG into layers must call it, so it is exported rather than
|
|
507
|
+
* re-declared per package.
|
|
508
|
+
*/
|
|
509
|
+
declare function sanitizeSvg(svg: string): string;
|
|
510
|
+
|
|
511
|
+
/** True for values safe to use as a canvas/SVG colour. Empty means transparent. */
|
|
512
|
+
declare function isCssColor(value: unknown, allowEmpty?: boolean): value is string;
|
|
513
|
+
|
|
518
514
|
declare function serializeEditor(editor: CanvasEditor): EditorState;
|
|
519
515
|
declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
|
|
520
516
|
|
|
521
|
-
|
|
517
|
+
/** Common print and digital canvas sizes. */
|
|
518
|
+
declare const CANVAS_SIZE_PRESETS: readonly CanvasSizePreset[];
|
|
519
|
+
|
|
520
|
+
type AnnotationPrimitive = {
|
|
521
|
+
id: string;
|
|
522
|
+
type: 'point';
|
|
523
|
+
x: number;
|
|
524
|
+
y: number;
|
|
525
|
+
label?: string;
|
|
526
|
+
} | {
|
|
527
|
+
id: string;
|
|
528
|
+
type: 'rectangle';
|
|
529
|
+
left: number;
|
|
530
|
+
top: number;
|
|
531
|
+
width: number;
|
|
532
|
+
height: number;
|
|
533
|
+
label?: string;
|
|
534
|
+
} | {
|
|
535
|
+
id: string;
|
|
536
|
+
type: 'label';
|
|
537
|
+
x: number;
|
|
538
|
+
y: number;
|
|
539
|
+
text: string;
|
|
540
|
+
} | {
|
|
541
|
+
id: string;
|
|
542
|
+
type: 'path';
|
|
543
|
+
points: Array<{
|
|
544
|
+
x: number;
|
|
545
|
+
y: number;
|
|
546
|
+
}>;
|
|
547
|
+
label?: string;
|
|
548
|
+
};
|
|
549
|
+
interface ViewportTransform {
|
|
550
|
+
zoom: number;
|
|
551
|
+
panX: number;
|
|
552
|
+
panY: number;
|
|
553
|
+
devicePixelRatio?: number;
|
|
554
|
+
}
|
|
555
|
+
/** Host-owned annotations that never enter editor layers, history, serialization, or exports. */
|
|
556
|
+
declare class AnnotationOverlay {
|
|
557
|
+
private items;
|
|
558
|
+
private transform;
|
|
559
|
+
set(annotation: AnnotationPrimitive): void;
|
|
560
|
+
remove(id: string): boolean;
|
|
561
|
+
clear(): void;
|
|
562
|
+
getAll(): AnnotationPrimitive[];
|
|
563
|
+
setTransform(transform: ViewportTransform): void;
|
|
564
|
+
documentToViewport(point: {
|
|
565
|
+
x: number;
|
|
566
|
+
y: number;
|
|
567
|
+
}): {
|
|
568
|
+
x: number;
|
|
569
|
+
y: number;
|
|
570
|
+
};
|
|
571
|
+
viewportToDocument(point: {
|
|
572
|
+
x: number;
|
|
573
|
+
y: number;
|
|
574
|
+
}): {
|
|
575
|
+
x: number;
|
|
576
|
+
y: number;
|
|
577
|
+
};
|
|
578
|
+
documentToDevice(point: {
|
|
579
|
+
x: number;
|
|
580
|
+
y: number;
|
|
581
|
+
}): {
|
|
582
|
+
x: number;
|
|
583
|
+
y: number;
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/**
|
|
588
|
+
* Warp RGBA pixels with an equally sized channel map. A channel value of 128
|
|
589
|
+
* is neutral; 0 and 255 move by the configured negative/positive maximum.
|
|
590
|
+
*/
|
|
591
|
+
declare function displaceRgba(source: Uint8ClampedArray, map: Uint8ClampedArray, width: number, height: number, options: Omit<MockupDisplacement, 'image'>): Uint8ClampedArray;
|
|
592
|
+
|
|
593
|
+
export { AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, CANVAS_SIZE_PRESETS, CanvasEditor, CanvasSizePreset, type CoverPlacement, CropController, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMeta, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MaskBrushOptions, MaskController, type MaskPerformanceSample, MaskPoint, MaskRefinementError, type MaskRefinementErrorCode, MaskRefinementPrompt, MaskRefinementProvider, MaskRefinementResult, MockupConfig, MockupDisplacement, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, PatternSourceResolver, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SemanticExportOptions, SerializedBackgroundImageOptions, SerializedLayer, ShapePlugin, SnapManager, SvgExportOptions, TemplateDefinition, type TilePlacement, Unit, UnitConverter, type ViewportTransform, applyPatternLocks, buildPatternDataURL, captureLocks, clamp, clearPatternImageCache, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, exportDataURL, exportMockup, exportPNG, exportSVG, generateId, isCssColor, loadPatternImage, restoreLocks, round2, sanitizeSvg, serializeEditor };
|