@overtone-art/canvas-editor-core 0.8.6 → 0.9.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
@@ -1,6 +1,6 @@
1
- import { Canvas, FabricObject, Point, ImageFormat, Group } from 'fabric';
2
- import { f as EditorEvents, v as LayerType, t as LayerMeta, L as LayerData, a3 as SerializedLayer, V as PatternConfig, W as PatternLocks, a9 as TextCurveConfig, aa as TextCurveInput, ad as TextWrapMode, ac as TextOverflow, A as MaskPresetId, a4 as ShapeMaskPresetId, ae as TextureMaskPresetId, ag as Unit, T as MockupPrintArea, P as MockupConfig, i as FontDefinition, w as LicenseConfig, y as LicenseStatus, $ as ProjectState, M as MaskBrushOptions, z as MaskPoint, J as MaskRefinementProvider, H as MaskRefinementPrompt, N as MaskRefinementResult, r as LayerMaskEntry, j as GradientConfig, s as LayerMaskMode, E as EditorConfig, a5 as ShapePlugin, c as BlendMode, a7 as TemplateDefinition, I as ImageAdjustments, g as EditorState, a1 as SemanticExportOptions, a6 as SvgExportOptions, Z as PrintifyPositioning, U as NormalizedLayerPosition, Y as PositioningAdapter, o as ImageProviderResult, p as ImageSearchOptions, q as ImageSearchResult, F as FileAdapter, n as ImageProvider, a2 as SerializedBackgroundImageOptions, b as BackgroundImageOptions, a0 as ResizeOptions, e as DpiIssue, u as LayerShadowConfig, C as CanvasSizePreset, Q as MockupDisplacement } from './types-F2GH3dcU.mjs';
3
- export { B as BLEND_GROUPS, a as BLEND_MODES, D as DEFAULT_GRADIENT_CONFIG, d as DEFAULT_PATTERN_CONFIG, h as ExportFormat, G as GradientBox, k as GradientKind, l as GradientStop, m as ImageAttribution, x as LicensePayload, K as MaskRefinementRequest, O as MockupBlendMode, R as MockupDisplacementChannel, S as MockupOverlay, X as PatternState, _ as ProjectPage, a8 as TemplateParameter, ab as TextCurveShape, af as TileMode, ah as angleFromCoords, ai as blendModeLabel, aj as blendModeOf, ak as blendOperation, al as linearCoords, am as readGradientConfig, an as toFabricGradient } from './types-F2GH3dcU.mjs';
1
+ import { Canvas, FabricObject, Point, filters, ImageFormat, Group } from 'fabric';
2
+ import { g as EditorEvents, O as LayerType, M as LayerMeta, L as LayerData, af as SerializedLayer, a5 as PatternConfig, a6 as PatternLocks, ai as ShapePlugin, aj as ShapeState, s as ImageEffectsState, H as LayerEffectState, z as LayerEffectKind, an as TextCurveConfig, ao as TextCurveInput, ar as TextWrapMode, aq as TextOverflow, U as MaskPresetId, ag as ShapeMaskPresetId, as as TextureMaskPresetId, au as Unit, a2 as MockupPrintArea, _ as MockupConfig, k as FontDefinition, P as LicenseConfig, R as LicenseStatus, ab as ProjectState, S as MaskBrushOptions, T as MaskPoint, W as MaskRefinementProvider, V as MaskRefinementPrompt, Y as MaskRefinementResult, J as LayerMaskEntry, l as GradientConfig, K as LayerMaskMode, E as EditorConfig, d as BlendMode, al as TemplateDefinition, h as EditorState, ad as SemanticExportOptions, ak as SvgExportOptions, a9 as PrintifyPositioning, a4 as NormalizedLayerPosition, a8 as PositioningAdapter, w as ImageProviderResult, x as ImageSearchOptions, y as ImageSearchResult, F as FileAdapter, v as ImageProvider, ae as SerializedBackgroundImageOptions, c as BackgroundImageOptions, ac as ResizeOptions, f as DpiIssue, N as LayerShadowConfig, C as CanvasSizePreset, $ as MockupDisplacement } from './specs-B_jOmY6u.mjs';
3
+ export { A as ADJUST_KEYS, a as ADJUST_RANGES, B as BLEND_GROUPS, b as BLEND_MODES, D as DEFAULT_GRADIENT_CONFIG, e as DEFAULT_PATTERN_CONFIG, i as ExportFormat, j as FilterSpec, G as GradientBox, m as GradientKind, n as GradientStop, I as IMAGE_FILTER_PRESETS, o as IMAGE_PROXY_MAX_EDGE, p as ImageAdjust, q as ImageAlphaClip, r as ImageAttribution, t as ImageFilterPreset, u as ImageFilterPresetId, Q as LicensePayload, X as MaskRefinementRequest, Z as MockupBlendMode, a0 as MockupDisplacementChannel, a1 as MockupOverlay, a3 as NEUTRAL_ADJUST, a7 as PatternState, aa as ProjectPage, ah as ShapeParamDef, am as TemplateParameter, ap as TextCurveShape, at as TileMode, av as alphaClipMatrix, aw as angleFromCoords, ax as blendModeLabel, ay as blendModeOf, az as blendOperation, aA as clampAdjust, aB as clampAlphaClip, aC as imageEffectsFilterSpecs, aD as imageFilterPreset, aE as linearCoords, aF as normalizeImageEffects, aG as readGradientConfig, aH as toFabricGradient } from './specs-B_jOmY6u.mjs';
4
4
 
5
5
  type EventHandler<T> = (data: T) => void;
6
6
  declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
@@ -40,6 +40,14 @@ declare class Layer {
40
40
  private hasMeta;
41
41
  toData(): LayerData;
42
42
  serialize(): SerializedLayer;
43
+ /**
44
+ * A member of an ActiveSelection holds selection-relative coordinates and
45
+ * `toObject()` writes them verbatim. A snapshot taken mid-selection — which
46
+ * `HistoryManager.undo()` takes — then held positions no restore could use,
47
+ * and the redo scattered the layers. Realise the selection's transform for
48
+ * the write and put the object's own transform back.
49
+ */
50
+ private serializeObject;
43
51
  }
44
52
  declare class LayerManager {
45
53
  private canvas;
@@ -239,13 +247,47 @@ declare class CropController {
239
247
  constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
240
248
  isActive(): boolean;
241
249
  activeLayerId(): string | null;
242
- start(layer: Layer): void;
250
+ start(layer: Layer, options?: {
251
+ aspect?: number | null;
252
+ }): void;
253
+ /**
254
+ * The frame's own geometry, without its stroke.
255
+ *
256
+ * The rect draws a 1px dashed outline, and `getBoundingRect` /
257
+ * `getScaledWidth` both count it — so reading the frame through them made the
258
+ * aspect box, the zoom centre and the applied crop each about a pixel larger
259
+ * than the box the user drew. The rect is axis-aligned (rotation is locked),
260
+ * so its own left/top and scaled dimensions are exact.
261
+ */
262
+ private frameBox;
263
+ /**
264
+ * Lock the frame to a ratio: it becomes the largest box of that ratio inside
265
+ * the current frame, centred, and only the corner handles stay — fabric's
266
+ * default `uniformScaling` then keeps the ratio through a drag. `null` frees it.
267
+ */
268
+ setAspect(ratio: number | null): void;
269
+ /** Zoom the image under a fixed frame, about the frame's centre. */
270
+ setScale(factor: number): void;
271
+ /** Back to the frame and image transform the session started with; aspect freed. */
272
+ reset(): void;
243
273
  apply(): void;
244
274
  cancel(): void;
245
275
  dispose(): void;
246
276
  private finish;
247
277
  }
248
278
 
279
+ type AlignTarget = 'left' | 'center-h' | 'right' | 'top' | 'middle' | 'bottom';
280
+ interface Box {
281
+ left: number;
282
+ top: number;
283
+ width: number;
284
+ height: number;
285
+ }
286
+ declare function unionBox(boxes: Box[]): Box;
287
+ declare function alignObjects(objects: FabricObject[], target: AlignTarget, frame: Box): void;
288
+ /** Equal gaps between neighbours along one axis; the outer two stay put. */
289
+ declare function distributeObjects(objects: FabricObject[], axis: 'h' | 'v'): boolean;
290
+
249
291
  /**
250
292
  * Repeats a layer's own object across the print area.
251
293
  *
@@ -287,6 +329,8 @@ declare class PatternManager {
287
329
  /** Release every proxy and the offscreen snapshot it holds. */
288
330
  private clearProxies;
289
331
  private attach;
332
+ /** Fold a programmatic move of the proxy into the config and the source, as a drop does. */
333
+ commitProxy(layerId: string): void;
290
334
  /**
291
335
  * Fold a finished drag / scale / rotate on the proxy back into the pattern:
292
336
  * position becomes the grid origin (carried by the source), scale becomes the
@@ -482,6 +526,96 @@ interface CanvasRenderingProtocol {
482
526
  drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
483
527
  }
484
528
 
529
+ /** Defaults filled in and every value clamped to its definition. */
530
+ declare function resolveShapeParams(plugin: ShapePlugin, overrides?: Record<string, number>): Record<string, number>;
531
+ /**
532
+ * Parametric shapes: the geometry lives on a stock fabric object (so the print
533
+ * path needs nothing), the parameters that produced it live in `meta.shape`,
534
+ * and this manager is the only writer of both.
535
+ */
536
+ declare class ShapeManager {
537
+ private canvas;
538
+ private layers;
539
+ private history;
540
+ private events;
541
+ private plugins;
542
+ /**
543
+ * An arrow scaled 2×1 must not stretch its head: the new box is baked into
544
+ * the points and the scale returns to 1. Runs before the editor's own
545
+ * `object:modified` handler (constructed earlier), so history records the
546
+ * baked state.
547
+ */
548
+ private readonly onObjectModified;
549
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
550
+ dispose(): void;
551
+ /** A restored layer names its plugin by id; only a registered one can regenerate. */
552
+ register(plugin: ShapePlugin): void;
553
+ read(layerId: string): ShapeState | null;
554
+ /**
555
+ * `commit: false` is a slider drag: geometry and `meta.shape` are written and
556
+ * `layer:modified` is emitted so the Shape panel re-reads, but nothing reaches
557
+ * history. The default commits one entry.
558
+ */
559
+ setParams(layerId: string, patch: Record<string, number>, commit?: boolean): void;
560
+ }
561
+
562
+ type Filter = filters.BaseFilter<string>;
563
+ declare class ImageEffectsManager {
564
+ private canvas;
565
+ private layers;
566
+ private history;
567
+ private events;
568
+ private proxies;
569
+ private lastSpecs;
570
+ private readonly onRemoved;
571
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
572
+ read(layerId: string): ImageEffectsState;
573
+ /** The filter instances a state derives to, in the D5 order, with no layer involved. */
574
+ filtersFor(state: ImageEffectsState): Filter[];
575
+ preview(layerId: string, patch: Partial<ImageEffectsState>): void;
576
+ commit(layerId: string, patch: Partial<ImageEffectsState>): void;
577
+ reset(layerId: string): void;
578
+ /** Re-derive after a source swap or a load. */
579
+ refresh(layerId: string): void;
580
+ refreshAll(): void;
581
+ hasProxy(layerId: string): boolean;
582
+ /** Run `fn` with every proxied image filtered at source resolution (export), then restore the proxies. */
583
+ withSourceResolution<T>(fn: () => T): T;
584
+ dispose(): void;
585
+ private imageLayer;
586
+ private write;
587
+ private apply;
588
+ private render;
589
+ private proxyFor;
590
+ private drop;
591
+ }
592
+
593
+ type Params = Record<string, number | string>;
594
+ declare const LAYER_EFFECT_DEFAULTS: Record<Exclude<LayerEffectKind, 'none'>, Params>;
595
+ /**
596
+ * One effect per layer, applied as one history entry. Outline, hollow and drop
597
+ * are native fabric props; splice, echo and background are the `effect` prop
598
+ * the effects-package subclasses render — so every kind survives
599
+ * `toObject()` → `enlivenObjects()` in both runtimes (engine D1, D3, D6).
600
+ */
601
+ declare class LayerEffectsManager {
602
+ private canvas;
603
+ private layers;
604
+ private history;
605
+ private events;
606
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
607
+ read(layerId: string): LayerEffectState | null;
608
+ /**
609
+ * `commit: false` is a slider drag: props are written and `layer:modified`
610
+ * is emitted so the panels re-read, but nothing reaches history. The default
611
+ * commits ONE entry, setMeta's own save folded into the same transaction.
612
+ */
613
+ apply(layerId: string, kind: LayerEffectKind, params?: Params, commit?: boolean): void;
614
+ /** Undo what the previous kind wrote, so kinds never stack. */
615
+ private clear;
616
+ private install;
617
+ }
618
+
485
619
  /** Straight text — the state every text layer starts in. */
486
620
  declare const DEFAULT_TEXT_CURVE: TextCurveConfig;
487
621
  interface CurvePath {
@@ -1183,11 +1317,17 @@ declare class CanvasEditor {
1183
1317
  readonly snapping: SnapManager;
1184
1318
  readonly crop: CropController;
1185
1319
  readonly patterns: PatternManager;
1320
+ /** Parametric shape layers: `meta.shape` and in-place regeneration. */
1321
+ readonly shapes: ShapeManager;
1186
1322
  readonly curves: TextCurveManager;
1187
1323
  readonly wrap: TextWrapManager;
1188
1324
  readonly maskPresets: MaskPresetManager;
1325
+ /** Owner of every image layer's filter array (D5). */
1326
+ readonly imageEffects: ImageEffectsManager;
1189
1327
  /** Stacked boolean masks, per layer and for the design as a whole. */
1190
1328
  readonly layerMasks: LayerMaskManager;
1329
+ /** One effect per text or shape layer (D6). */
1330
+ readonly effects: LayerEffectsManager;
1191
1331
  readonly fonts: FontRegistry;
1192
1332
  readonly licensing: LicenseManager;
1193
1333
  readonly pages: ProjectManager;
@@ -1197,13 +1337,27 @@ declare class CanvasEditor {
1197
1337
  private zoomLevel;
1198
1338
  private selectionStyle;
1199
1339
  private mockup;
1340
+ /** Alt was held when a drag began on this layer; the drop leaves a copy behind. */
1341
+ private altDrag;
1200
1342
  private designBackground;
1201
1343
  private designBackgroundImage;
1202
1344
  private backgroundImageOptions;
1203
1345
  constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
1204
1346
  addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
1205
1347
  /** Replace an image source without changing its layer identity or visual transform. */
1206
- replaceImageSource(layerId: string, url: string): Promise<Layer>;
1348
+ replaceImageSource(layerId: string, url: string, options?: {
1349
+ crossOrigin?: 'anonymous';
1350
+ }): Promise<Layer>;
1351
+ /**
1352
+ * The class the registry holds for a stock name.
1353
+ *
1354
+ * `registerEffects` (run in the constructor) overrides the stock names, but
1355
+ * registration only decides what an ENLIVEN produces — a `new Textbox(...)`
1356
+ * here would still be the stock class, which carries no `effect` in its
1357
+ * `customProperties` and so could never serialize one. Authoring and
1358
+ * restoring have to yield the same class.
1359
+ */
1360
+ private registered;
1207
1361
  addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
1208
1362
  addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer;
1209
1363
  /**
@@ -1231,9 +1385,17 @@ declare class CanvasEditor {
1231
1385
  getSelectedLayer(): Layer | null;
1232
1386
  /** Mirror a layer along the given axis. */
1233
1387
  flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
1388
+ /** What the user is acting on: the proxy where a layer has one. */
1389
+ private selectedTargets;
1390
+ private afterMove;
1391
+ /** One layer aligns to the canvas; several align to their common box. One history entry. */
1392
+ alignLayers(target: AlignTarget): boolean;
1393
+ /** Equal gaps along an axis. Needs three selected; returns false otherwise. */
1394
+ distributeLayers(axis: 'h' | 'v'): boolean;
1234
1395
  /** Clone a layer (offset slightly) and select the copy. */
1235
1396
  duplicateLayer(id: string): Promise<Layer | null>;
1236
- applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
1397
+ /** The drag moved the original; a copy takes the start position, just beneath it. */
1398
+ private leaveCopyBehind;
1237
1399
  /**
1238
1400
  * Combine two or more layers into one group layer. Picking a group among them
1239
1401
  * **absorbs** it — its children join the new group and the old group record is
@@ -1535,4 +1697,4 @@ declare class AnnotationOverlay {
1535
1697
  */
1536
1698
  declare function displaceRgba(source: Uint8ClampedArray, map: Uint8ClampedArray, width: number, height: number, options: Omit<MockupDisplacement, 'image'>): Uint8ClampedArray;
1537
1699
 
1538
- export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, BlendMode, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, type CurvePath, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, GradientConfig, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MAX_MASK_LAYERS, MaskBrushOptions, MaskController, type MaskPerformanceSample, MaskPoint, MaskPresetId, MaskPresetManager, MaskRefinementError, type MaskRefinementErrorCode, MaskRefinementPrompt, MaskRefinementProvider, MaskRefinementResult, MockupConfig, MockupDisplacement, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, type PatternOrigin, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SHAPE_MASK_BOX, SHAPE_MASK_IDS, type SelectionStyle, SemanticExportOptions, SerializedBackgroundImageOptions, SerializedLayer, ShapeMaskPresetId, ShapePlugin, SnapManager, SvgExportOptions, TEXTURE_MASK_IDS, TEXTURE_MASK_SIZE, TemplateDefinition, type TemplateLayerSpec, TextCurveConfig, TextCurveInput, TextCurveManager, TextOverflow, TextWrapManager, TextWrapMode, type TextWrapState, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, applyTextWrapToObject, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitTextWidth, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, preWrapWordSplit, readLayerShadow, readTextWrap, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unwrapGroup };
1700
+ export { type AddMaskOptions, type AlignTarget, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, BlendMode, type Box, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, type CurvePath, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, GradientConfig, HistoryManager, ImageEffectsManager, ImageEffectsState, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, LAYER_EFFECT_DEFAULTS, Layer, LayerData, LayerEffectKind, LayerEffectState, LayerEffectsManager, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MAX_MASK_LAYERS, MaskBrushOptions, MaskController, type MaskPerformanceSample, MaskPoint, MaskPresetId, MaskPresetManager, MaskRefinementError, type MaskRefinementErrorCode, MaskRefinementPrompt, MaskRefinementProvider, MaskRefinementResult, MockupConfig, MockupDisplacement, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, type PatternOrigin, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SHAPE_MASK_BOX, SHAPE_MASK_IDS, type SelectionStyle, SemanticExportOptions, SerializedBackgroundImageOptions, SerializedLayer, ShapeManager, ShapeMaskPresetId, ShapePlugin, ShapeState, SnapManager, SvgExportOptions, TEXTURE_MASK_IDS, TEXTURE_MASK_SIZE, TemplateDefinition, type TemplateLayerSpec, TextCurveConfig, TextCurveInput, TextCurveManager, TextOverflow, TextWrapManager, TextWrapMode, type TextWrapState, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, alignObjects, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, applyTextWrapToObject, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, distributeObjects, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitTextWidth, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, preWrapWordSplit, readLayerShadow, readTextWrap, renderTextureMask, resetTransform, resolveShapeParams, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unionBox, unwrapGroup };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Canvas, FabricObject, Point, ImageFormat, Group } from 'fabric';
2
- import { f as EditorEvents, v as LayerType, t as LayerMeta, L as LayerData, a3 as SerializedLayer, V as PatternConfig, W as PatternLocks, a9 as TextCurveConfig, aa as TextCurveInput, ad as TextWrapMode, ac as TextOverflow, A as MaskPresetId, a4 as ShapeMaskPresetId, ae as TextureMaskPresetId, ag as Unit, T as MockupPrintArea, P as MockupConfig, i as FontDefinition, w as LicenseConfig, y as LicenseStatus, $ as ProjectState, M as MaskBrushOptions, z as MaskPoint, J as MaskRefinementProvider, H as MaskRefinementPrompt, N as MaskRefinementResult, r as LayerMaskEntry, j as GradientConfig, s as LayerMaskMode, E as EditorConfig, a5 as ShapePlugin, c as BlendMode, a7 as TemplateDefinition, I as ImageAdjustments, g as EditorState, a1 as SemanticExportOptions, a6 as SvgExportOptions, Z as PrintifyPositioning, U as NormalizedLayerPosition, Y as PositioningAdapter, o as ImageProviderResult, p as ImageSearchOptions, q as ImageSearchResult, F as FileAdapter, n as ImageProvider, a2 as SerializedBackgroundImageOptions, b as BackgroundImageOptions, a0 as ResizeOptions, e as DpiIssue, u as LayerShadowConfig, C as CanvasSizePreset, Q as MockupDisplacement } from './types-F2GH3dcU.js';
3
- export { B as BLEND_GROUPS, a as BLEND_MODES, D as DEFAULT_GRADIENT_CONFIG, d as DEFAULT_PATTERN_CONFIG, h as ExportFormat, G as GradientBox, k as GradientKind, l as GradientStop, m as ImageAttribution, x as LicensePayload, K as MaskRefinementRequest, O as MockupBlendMode, R as MockupDisplacementChannel, S as MockupOverlay, X as PatternState, _ as ProjectPage, a8 as TemplateParameter, ab as TextCurveShape, af as TileMode, ah as angleFromCoords, ai as blendModeLabel, aj as blendModeOf, ak as blendOperation, al as linearCoords, am as readGradientConfig, an as toFabricGradient } from './types-F2GH3dcU.js';
1
+ import { Canvas, FabricObject, Point, filters, ImageFormat, Group } from 'fabric';
2
+ import { g as EditorEvents, O as LayerType, M as LayerMeta, L as LayerData, af as SerializedLayer, a5 as PatternConfig, a6 as PatternLocks, ai as ShapePlugin, aj as ShapeState, s as ImageEffectsState, H as LayerEffectState, z as LayerEffectKind, an as TextCurveConfig, ao as TextCurveInput, ar as TextWrapMode, aq as TextOverflow, U as MaskPresetId, ag as ShapeMaskPresetId, as as TextureMaskPresetId, au as Unit, a2 as MockupPrintArea, _ as MockupConfig, k as FontDefinition, P as LicenseConfig, R as LicenseStatus, ab as ProjectState, S as MaskBrushOptions, T as MaskPoint, W as MaskRefinementProvider, V as MaskRefinementPrompt, Y as MaskRefinementResult, J as LayerMaskEntry, l as GradientConfig, K as LayerMaskMode, E as EditorConfig, d as BlendMode, al as TemplateDefinition, h as EditorState, ad as SemanticExportOptions, ak as SvgExportOptions, a9 as PrintifyPositioning, a4 as NormalizedLayerPosition, a8 as PositioningAdapter, w as ImageProviderResult, x as ImageSearchOptions, y as ImageSearchResult, F as FileAdapter, v as ImageProvider, ae as SerializedBackgroundImageOptions, c as BackgroundImageOptions, ac as ResizeOptions, f as DpiIssue, N as LayerShadowConfig, C as CanvasSizePreset, $ as MockupDisplacement } from './specs-B_jOmY6u.js';
3
+ export { A as ADJUST_KEYS, a as ADJUST_RANGES, B as BLEND_GROUPS, b as BLEND_MODES, D as DEFAULT_GRADIENT_CONFIG, e as DEFAULT_PATTERN_CONFIG, i as ExportFormat, j as FilterSpec, G as GradientBox, m as GradientKind, n as GradientStop, I as IMAGE_FILTER_PRESETS, o as IMAGE_PROXY_MAX_EDGE, p as ImageAdjust, q as ImageAlphaClip, r as ImageAttribution, t as ImageFilterPreset, u as ImageFilterPresetId, Q as LicensePayload, X as MaskRefinementRequest, Z as MockupBlendMode, a0 as MockupDisplacementChannel, a1 as MockupOverlay, a3 as NEUTRAL_ADJUST, a7 as PatternState, aa as ProjectPage, ah as ShapeParamDef, am as TemplateParameter, ap as TextCurveShape, at as TileMode, av as alphaClipMatrix, aw as angleFromCoords, ax as blendModeLabel, ay as blendModeOf, az as blendOperation, aA as clampAdjust, aB as clampAlphaClip, aC as imageEffectsFilterSpecs, aD as imageFilterPreset, aE as linearCoords, aF as normalizeImageEffects, aG as readGradientConfig, aH as toFabricGradient } from './specs-B_jOmY6u.js';
4
4
 
5
5
  type EventHandler<T> = (data: T) => void;
6
6
  declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
@@ -40,6 +40,14 @@ declare class Layer {
40
40
  private hasMeta;
41
41
  toData(): LayerData;
42
42
  serialize(): SerializedLayer;
43
+ /**
44
+ * A member of an ActiveSelection holds selection-relative coordinates and
45
+ * `toObject()` writes them verbatim. A snapshot taken mid-selection — which
46
+ * `HistoryManager.undo()` takes — then held positions no restore could use,
47
+ * and the redo scattered the layers. Realise the selection's transform for
48
+ * the write and put the object's own transform back.
49
+ */
50
+ private serializeObject;
43
51
  }
44
52
  declare class LayerManager {
45
53
  private canvas;
@@ -239,13 +247,47 @@ declare class CropController {
239
247
  constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
240
248
  isActive(): boolean;
241
249
  activeLayerId(): string | null;
242
- start(layer: Layer): void;
250
+ start(layer: Layer, options?: {
251
+ aspect?: number | null;
252
+ }): void;
253
+ /**
254
+ * The frame's own geometry, without its stroke.
255
+ *
256
+ * The rect draws a 1px dashed outline, and `getBoundingRect` /
257
+ * `getScaledWidth` both count it — so reading the frame through them made the
258
+ * aspect box, the zoom centre and the applied crop each about a pixel larger
259
+ * than the box the user drew. The rect is axis-aligned (rotation is locked),
260
+ * so its own left/top and scaled dimensions are exact.
261
+ */
262
+ private frameBox;
263
+ /**
264
+ * Lock the frame to a ratio: it becomes the largest box of that ratio inside
265
+ * the current frame, centred, and only the corner handles stay — fabric's
266
+ * default `uniformScaling` then keeps the ratio through a drag. `null` frees it.
267
+ */
268
+ setAspect(ratio: number | null): void;
269
+ /** Zoom the image under a fixed frame, about the frame's centre. */
270
+ setScale(factor: number): void;
271
+ /** Back to the frame and image transform the session started with; aspect freed. */
272
+ reset(): void;
243
273
  apply(): void;
244
274
  cancel(): void;
245
275
  dispose(): void;
246
276
  private finish;
247
277
  }
248
278
 
279
+ type AlignTarget = 'left' | 'center-h' | 'right' | 'top' | 'middle' | 'bottom';
280
+ interface Box {
281
+ left: number;
282
+ top: number;
283
+ width: number;
284
+ height: number;
285
+ }
286
+ declare function unionBox(boxes: Box[]): Box;
287
+ declare function alignObjects(objects: FabricObject[], target: AlignTarget, frame: Box): void;
288
+ /** Equal gaps between neighbours along one axis; the outer two stay put. */
289
+ declare function distributeObjects(objects: FabricObject[], axis: 'h' | 'v'): boolean;
290
+
249
291
  /**
250
292
  * Repeats a layer's own object across the print area.
251
293
  *
@@ -287,6 +329,8 @@ declare class PatternManager {
287
329
  /** Release every proxy and the offscreen snapshot it holds. */
288
330
  private clearProxies;
289
331
  private attach;
332
+ /** Fold a programmatic move of the proxy into the config and the source, as a drop does. */
333
+ commitProxy(layerId: string): void;
290
334
  /**
291
335
  * Fold a finished drag / scale / rotate on the proxy back into the pattern:
292
336
  * position becomes the grid origin (carried by the source), scale becomes the
@@ -482,6 +526,96 @@ interface CanvasRenderingProtocol {
482
526
  drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
483
527
  }
484
528
 
529
+ /** Defaults filled in and every value clamped to its definition. */
530
+ declare function resolveShapeParams(plugin: ShapePlugin, overrides?: Record<string, number>): Record<string, number>;
531
+ /**
532
+ * Parametric shapes: the geometry lives on a stock fabric object (so the print
533
+ * path needs nothing), the parameters that produced it live in `meta.shape`,
534
+ * and this manager is the only writer of both.
535
+ */
536
+ declare class ShapeManager {
537
+ private canvas;
538
+ private layers;
539
+ private history;
540
+ private events;
541
+ private plugins;
542
+ /**
543
+ * An arrow scaled 2×1 must not stretch its head: the new box is baked into
544
+ * the points and the scale returns to 1. Runs before the editor's own
545
+ * `object:modified` handler (constructed earlier), so history records the
546
+ * baked state.
547
+ */
548
+ private readonly onObjectModified;
549
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
550
+ dispose(): void;
551
+ /** A restored layer names its plugin by id; only a registered one can regenerate. */
552
+ register(plugin: ShapePlugin): void;
553
+ read(layerId: string): ShapeState | null;
554
+ /**
555
+ * `commit: false` is a slider drag: geometry and `meta.shape` are written and
556
+ * `layer:modified` is emitted so the Shape panel re-reads, but nothing reaches
557
+ * history. The default commits one entry.
558
+ */
559
+ setParams(layerId: string, patch: Record<string, number>, commit?: boolean): void;
560
+ }
561
+
562
+ type Filter = filters.BaseFilter<string>;
563
+ declare class ImageEffectsManager {
564
+ private canvas;
565
+ private layers;
566
+ private history;
567
+ private events;
568
+ private proxies;
569
+ private lastSpecs;
570
+ private readonly onRemoved;
571
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
572
+ read(layerId: string): ImageEffectsState;
573
+ /** The filter instances a state derives to, in the D5 order, with no layer involved. */
574
+ filtersFor(state: ImageEffectsState): Filter[];
575
+ preview(layerId: string, patch: Partial<ImageEffectsState>): void;
576
+ commit(layerId: string, patch: Partial<ImageEffectsState>): void;
577
+ reset(layerId: string): void;
578
+ /** Re-derive after a source swap or a load. */
579
+ refresh(layerId: string): void;
580
+ refreshAll(): void;
581
+ hasProxy(layerId: string): boolean;
582
+ /** Run `fn` with every proxied image filtered at source resolution (export), then restore the proxies. */
583
+ withSourceResolution<T>(fn: () => T): T;
584
+ dispose(): void;
585
+ private imageLayer;
586
+ private write;
587
+ private apply;
588
+ private render;
589
+ private proxyFor;
590
+ private drop;
591
+ }
592
+
593
+ type Params = Record<string, number | string>;
594
+ declare const LAYER_EFFECT_DEFAULTS: Record<Exclude<LayerEffectKind, 'none'>, Params>;
595
+ /**
596
+ * One effect per layer, applied as one history entry. Outline, hollow and drop
597
+ * are native fabric props; splice, echo and background are the `effect` prop
598
+ * the effects-package subclasses render — so every kind survives
599
+ * `toObject()` → `enlivenObjects()` in both runtimes (engine D1, D3, D6).
600
+ */
601
+ declare class LayerEffectsManager {
602
+ private canvas;
603
+ private layers;
604
+ private history;
605
+ private events;
606
+ constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager, events: EventEmitter<EditorEvents>);
607
+ read(layerId: string): LayerEffectState | null;
608
+ /**
609
+ * `commit: false` is a slider drag: props are written and `layer:modified`
610
+ * is emitted so the panels re-read, but nothing reaches history. The default
611
+ * commits ONE entry, setMeta's own save folded into the same transaction.
612
+ */
613
+ apply(layerId: string, kind: LayerEffectKind, params?: Params, commit?: boolean): void;
614
+ /** Undo what the previous kind wrote, so kinds never stack. */
615
+ private clear;
616
+ private install;
617
+ }
618
+
485
619
  /** Straight text — the state every text layer starts in. */
486
620
  declare const DEFAULT_TEXT_CURVE: TextCurveConfig;
487
621
  interface CurvePath {
@@ -1183,11 +1317,17 @@ declare class CanvasEditor {
1183
1317
  readonly snapping: SnapManager;
1184
1318
  readonly crop: CropController;
1185
1319
  readonly patterns: PatternManager;
1320
+ /** Parametric shape layers: `meta.shape` and in-place regeneration. */
1321
+ readonly shapes: ShapeManager;
1186
1322
  readonly curves: TextCurveManager;
1187
1323
  readonly wrap: TextWrapManager;
1188
1324
  readonly maskPresets: MaskPresetManager;
1325
+ /** Owner of every image layer's filter array (D5). */
1326
+ readonly imageEffects: ImageEffectsManager;
1189
1327
  /** Stacked boolean masks, per layer and for the design as a whole. */
1190
1328
  readonly layerMasks: LayerMaskManager;
1329
+ /** One effect per text or shape layer (D6). */
1330
+ readonly effects: LayerEffectsManager;
1191
1331
  readonly fonts: FontRegistry;
1192
1332
  readonly licensing: LicenseManager;
1193
1333
  readonly pages: ProjectManager;
@@ -1197,13 +1337,27 @@ declare class CanvasEditor {
1197
1337
  private zoomLevel;
1198
1338
  private selectionStyle;
1199
1339
  private mockup;
1340
+ /** Alt was held when a drag began on this layer; the drop leaves a copy behind. */
1341
+ private altDrag;
1200
1342
  private designBackground;
1201
1343
  private designBackgroundImage;
1202
1344
  private backgroundImageOptions;
1203
1345
  constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
1204
1346
  addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
1205
1347
  /** Replace an image source without changing its layer identity or visual transform. */
1206
- replaceImageSource(layerId: string, url: string): Promise<Layer>;
1348
+ replaceImageSource(layerId: string, url: string, options?: {
1349
+ crossOrigin?: 'anonymous';
1350
+ }): Promise<Layer>;
1351
+ /**
1352
+ * The class the registry holds for a stock name.
1353
+ *
1354
+ * `registerEffects` (run in the constructor) overrides the stock names, but
1355
+ * registration only decides what an ENLIVEN produces — a `new Textbox(...)`
1356
+ * here would still be the stock class, which carries no `effect` in its
1357
+ * `customProperties` and so could never serialize one. Authoring and
1358
+ * restoring have to yield the same class.
1359
+ */
1360
+ private registered;
1207
1361
  addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
1208
1362
  addShape(plugin: ShapePlugin, options?: Record<string, unknown>): Layer;
1209
1363
  /**
@@ -1231,9 +1385,17 @@ declare class CanvasEditor {
1231
1385
  getSelectedLayer(): Layer | null;
1232
1386
  /** Mirror a layer along the given axis. */
1233
1387
  flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
1388
+ /** What the user is acting on: the proxy where a layer has one. */
1389
+ private selectedTargets;
1390
+ private afterMove;
1391
+ /** One layer aligns to the canvas; several align to their common box. One history entry. */
1392
+ alignLayers(target: AlignTarget): boolean;
1393
+ /** Equal gaps along an axis. Needs three selected; returns false otherwise. */
1394
+ distributeLayers(axis: 'h' | 'v'): boolean;
1234
1395
  /** Clone a layer (offset slightly) and select the copy. */
1235
1396
  duplicateLayer(id: string): Promise<Layer | null>;
1236
- applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
1397
+ /** The drag moved the original; a copy takes the start position, just beneath it. */
1398
+ private leaveCopyBehind;
1237
1399
  /**
1238
1400
  * Combine two or more layers into one group layer. Picking a group among them
1239
1401
  * **absorbs** it — its children join the new group and the old group record is
@@ -1535,4 +1697,4 @@ declare class AnnotationOverlay {
1535
1697
  */
1536
1698
  declare function displaceRgba(source: Uint8ClampedArray, map: Uint8ClampedArray, width: number, height: number, options: Omit<MockupDisplacement, 'image'>): Uint8ClampedArray;
1537
1699
 
1538
- export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, BlendMode, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, type CurvePath, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, GradientConfig, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MAX_MASK_LAYERS, MaskBrushOptions, MaskController, type MaskPerformanceSample, MaskPoint, MaskPresetId, MaskPresetManager, MaskRefinementError, type MaskRefinementErrorCode, MaskRefinementPrompt, MaskRefinementProvider, MaskRefinementResult, MockupConfig, MockupDisplacement, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, type PatternOrigin, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SHAPE_MASK_BOX, SHAPE_MASK_IDS, type SelectionStyle, SemanticExportOptions, SerializedBackgroundImageOptions, SerializedLayer, ShapeMaskPresetId, ShapePlugin, SnapManager, SvgExportOptions, TEXTURE_MASK_IDS, TEXTURE_MASK_SIZE, TemplateDefinition, type TemplateLayerSpec, TextCurveConfig, TextCurveInput, TextCurveManager, TextOverflow, TextWrapManager, TextWrapMode, type TextWrapState, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, applyTextWrapToObject, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitTextWidth, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, preWrapWordSplit, readLayerShadow, readTextWrap, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unwrapGroup };
1700
+ export { type AddMaskOptions, type AlignTarget, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, BlendMode, type Box, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, type CurvePath, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, GradientConfig, HistoryManager, ImageEffectsManager, ImageEffectsState, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, LAYER_EFFECT_DEFAULTS, Layer, LayerData, LayerEffectKind, LayerEffectState, LayerEffectsManager, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, MAX_MASK_LAYERS, MaskBrushOptions, MaskController, type MaskPerformanceSample, MaskPoint, MaskPresetId, MaskPresetManager, MaskRefinementError, type MaskRefinementErrorCode, MaskRefinementPrompt, MaskRefinementProvider, MaskRefinementResult, MockupConfig, MockupDisplacement, MockupPrintArea, NormalizedLayerPosition, PatternConfig, PatternLocks, PatternManager, type PatternOrigin, type PngExportOptions, PositioningAdapter, PrintifyPositioning, ProjectManager, ProjectState, ResizeOptions, SHAPE_MASK_BOX, SHAPE_MASK_IDS, type SelectionStyle, SemanticExportOptions, SerializedBackgroundImageOptions, SerializedLayer, ShapeManager, ShapeMaskPresetId, ShapePlugin, ShapeState, SnapManager, SvgExportOptions, TEXTURE_MASK_IDS, TEXTURE_MASK_SIZE, TemplateDefinition, type TemplateLayerSpec, TextCurveConfig, TextCurveInput, TextCurveManager, TextOverflow, TextWrapManager, TextWrapMode, type TextWrapState, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, alignObjects, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, applyTextWrapToObject, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, distributeObjects, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitTextWidth, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, preWrapWordSplit, readLayerShadow, readTextWrap, renderTextureMask, resetTransform, resolveShapeParams, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unionBox, unwrapGroup };