@overtone-art/canvas-editor-core 0.5.0 → 0.6.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
1
  import { Canvas, FabricObject, Point, ImageFormat, Group } from 'fabric';
2
- import { b as EditorEvents, o as LayerType, m as LayerMeta, L as LayerData, X as SerializedLayer, P as PatternConfig, K as PatternLocks, a1 as TextCurveConfig, t as MaskPresetId, Y as ShapeMaskPresetId, a2 as TextureMaskPresetId, a4 as Unit, J as MockupPrintArea, z as MockupConfig, e as FontDefinition, p as LicenseConfig, r as LicenseStatus, T as ProjectState, M as MaskBrushOptions, s as MaskPoint, v as MaskRefinementProvider, u as MaskRefinementPrompt, x as MaskRefinementResult, k as LayerMaskEntry, l as LayerMaskMode, E as EditorConfig, Z as ShapePlugin, $ as TemplateDefinition, I as ImageAdjustments, c as EditorState, V as SemanticExportOptions, _ as SvgExportOptions, R as PrintifyPositioning, N as NormalizedLayerPosition, Q as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, W as SerializedBackgroundImageOptions, B as BackgroundImageOptions, U as ResizeOptions, a as DpiIssue, n as LayerShadowConfig, C as CanvasSizePreset, A as MockupDisplacement } from './types-JP8MZsIs.mjs';
3
- export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, q as LicensePayload, w as MaskRefinementRequest, y as MockupBlendMode, G as MockupDisplacementChannel, H as MockupOverlay, O as PatternState, S as ProjectPage, a0 as TemplateParameter, a3 as TileMode } from './types-JP8MZsIs.mjs';
2
+ import { b as EditorEvents, o as LayerType, m as LayerMeta, L as LayerData, X as SerializedLayer, P as PatternConfig, K as PatternLocks, a1 as TextCurveConfig, a2 as TextCurveInput, t as MaskPresetId, Y as ShapeMaskPresetId, a4 as TextureMaskPresetId, a6 as Unit, J as MockupPrintArea, z as MockupConfig, e as FontDefinition, p as LicenseConfig, r as LicenseStatus, T as ProjectState, M as MaskBrushOptions, s as MaskPoint, v as MaskRefinementProvider, u as MaskRefinementPrompt, x as MaskRefinementResult, k as LayerMaskEntry, l as LayerMaskMode, E as EditorConfig, Z as ShapePlugin, $ as TemplateDefinition, I as ImageAdjustments, c as EditorState, V as SemanticExportOptions, _ as SvgExportOptions, R as PrintifyPositioning, N as NormalizedLayerPosition, Q as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, W as SerializedBackgroundImageOptions, B as BackgroundImageOptions, U as ResizeOptions, a as DpiIssue, n as LayerShadowConfig, C as CanvasSizePreset, A as MockupDisplacement } from './types-LM7pOkkj.mjs';
3
+ export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, q as LicensePayload, w as MaskRefinementRequest, y as MockupBlendMode, G as MockupDisplacementChannel, H as MockupOverlay, O as PatternState, S as ProjectPage, a0 as TemplateParameter, a3 as TextCurveShape, a5 as TileMode } from './types-LM7pOkkj.mjs';
4
4
 
5
5
  type EventHandler<T> = (data: T) => void;
6
6
  declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
@@ -28,6 +28,14 @@ declare class Layer {
28
28
  * the layer's real object stays the one every editor API talks to.
29
29
  */
30
30
  renderProxy: FabricObject | null;
31
+ /**
32
+ * Layers nested inside this one, in draw order. Only a `group` layer has any:
33
+ * their fabric objects live inside this layer's fabric `Group`, not on the
34
+ * canvas, which is why the manager keeps them off the canvas stack.
35
+ */
36
+ children: Layer[];
37
+ /** Group this layer sits inside, or null when it is on the canvas stack. */
38
+ parentId: string | null;
31
39
  constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
32
40
  private hasMeta;
33
41
  toData(): LayerData;
@@ -42,6 +50,26 @@ declare class LayerManager {
42
50
  setHistoryCallback(callback: () => void): void;
43
51
  add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer;
44
52
  remove(id: string): boolean;
53
+ /**
54
+ * Take a top-level layer off the canvas stack **without** disposing it — it is
55
+ * about to become a group's child, so its object has to stay alive.
56
+ */
57
+ detach(id: string): Layer | undefined;
58
+ /** Put a group's children back on the canvas stack and drop the group. */
59
+ explode(group: Layer): Layer[];
60
+ /**
61
+ * Empty a group onto the canvas stack, in the group's own place, and drop the
62
+ * group record. `removeAll` restores each child's absolute transform, so the
63
+ * group's matrix must NOT be re-applied on top of it.
64
+ */
65
+ private dissolve;
66
+ /**
67
+ * Re-attach child records to an enlivened group. `data[i]` describes
68
+ * `group._objects[i]` — the order fabric serializes and restores them in. A
69
+ * missing record still becomes a child, so a hand-edited state cannot drop
70
+ * artwork off the canvas.
71
+ */
72
+ adoptGroupChildren(group: Layer, data: LayerData[]): void;
45
73
  /** Replace a layer's render object while preserving its immutable ID and panel state. */
46
74
  replaceObject(id: string, fabricObject: FabricObject): boolean;
47
75
  /**
@@ -57,10 +85,26 @@ declare class LayerManager {
57
85
  * front-to-back instead of computed.
58
86
  */
59
87
  private syncZOrder;
88
+ /** The list a layer lives in: its group's children, or the canvas stack. */
89
+ private siblingsOf;
60
90
  reorder(id: string, newIndex: number): boolean;
61
91
  select(id: string | null): void;
92
+ /** Drill into a group so its children can be selected and clicked. */
93
+ private enterGroup;
94
+ /** Leave every entered group — selecting anything else is done drilling in. */
95
+ exitGroups(): void;
96
+ /**
97
+ * Select several layers at once, as one fabric `ActiveSelection`. Children are
98
+ * skipped: a selection spanning in and out of a group has no single transform.
99
+ */
100
+ selectMany(ids: string[]): void;
101
+ /** Depth-first over the whole tree, each layer before its children. */
102
+ private walk;
62
103
  get(id: string): Layer | undefined;
104
+ /** Top-level layers only — the canvas stack. Children hang off their group. */
63
105
  getAll(): Layer[];
106
+ /** Top-level layers, each carrying its children: what the layer panel renders. */
107
+ getTree(): LayerData[];
64
108
  findByObject(obj: FabricObject): Layer | undefined;
65
109
  setVisibility(id: string, visible: boolean): void;
66
110
  setLocked(id: string, locked: boolean): void;
@@ -323,8 +367,32 @@ declare class TiledPatternObject extends FabricObject {
323
367
  * tiling. The copy shares the source (it only ever reads from it).
324
368
  */
325
369
  clone(): Promise<this>;
370
+ /**
371
+ * The source's tile footprint: its bounding box, minus a stroke it reserves
372
+ * room for but never paints.
373
+ *
374
+ * fabric keeps `strokeWidth` inside an object's box whether or not a `stroke`
375
+ * colour paints it, and the built-in shapes arrive with `strokeWidth: 1` and no
376
+ * stroke. Stepping the grid by that box puts a transparent seam between every
377
+ * pair of neighbours at zero spacing: the artwork is a pixel narrower than the
378
+ * box it is stepped by.
379
+ */
380
+ private sourceBox;
326
381
  /** The source's on-canvas width, before the tile scale. */
327
382
  private baseW;
383
+ /** The source's on-canvas height, before the tile scale. */
384
+ private baseH;
385
+ /**
386
+ * Size to paint the snapshot at, for a tile of `tileW × tileH`.
387
+ *
388
+ * The snapshot is NOT exactly the source's box: `toCanvasElement` rounds the
389
+ * raster up to whole pixels and pads it further for a shadow. Painting it into
390
+ * the tile step would squeeze the artwork inside that padding — every tile
391
+ * shrinks by up to a pixel and the grid shows transparent seams at zero
392
+ * spacing. So the bitmap is painted at its own footprint, scaled by the same
393
+ * factor the tile is, and the step stays the source's box.
394
+ */
395
+ private drawSize;
328
396
  /** Tile size from the config alone, ignoring any in-flight gesture. */
329
397
  private baseTile;
330
398
  /** Tile size as drawn right now, including a live scale gesture. */
@@ -356,6 +424,18 @@ interface PatternOrigin {
356
424
  x: number;
357
425
  y: number;
358
426
  }
427
+ /**
428
+ * Size the tile bitmap is painted at, when that differs from the grid step.
429
+ *
430
+ * A snapshot of the source is not always exactly the source's box: the raster is
431
+ * allocated in whole pixels, and a shadow pads it further. Painting such a bitmap
432
+ * into the step would shrink the artwork inside its own transparent margin and
433
+ * open a hairline gap between neighbours at zero spacing.
434
+ */
435
+ interface TileDrawSize {
436
+ width: number;
437
+ height: number;
438
+ }
359
439
  /**
360
440
  * Pure tile geometry: where each tile centre lands and how much it is rotated,
361
441
  * for a config + target/base size. Covers every corner of the target from the
@@ -369,8 +449,12 @@ declare function computeTilePositions(config: PatternConfig, targetW: number, ta
369
449
  * Draw the tiled pattern onto a 2D context, in target coordinates (0,0 = the
370
450
  * target's top-left corner). The geometry lives in {@link computeTilePositions};
371
451
  * this just plays it out as canvas calls.
452
+ *
453
+ * `baseW`/`baseH` are the grid STEP. `draw` is the size the bitmap is painted at
454
+ * and defaults to the step — pass it when the bitmap carries padding the step
455
+ * does not (see {@link TileDrawSize}), so the artwork still lands step-sized.
372
456
  */
373
- declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, origin?: PatternOrigin): void;
457
+ declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, origin?: PatternOrigin, draw?: TileDrawSize): void;
374
458
  /** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
375
459
  interface CanvasRenderingProtocol {
376
460
  save(): void;
@@ -383,13 +467,31 @@ interface CanvasRenderingProtocol {
383
467
  /** Straight text — the state every text layer starts in. */
384
468
  declare const DEFAULT_TEXT_CURVE: TextCurveConfig;
385
469
  interface CurvePath {
386
- /** SVG path data the text is laid out along. */
470
+ /** SVG path data the line is laid out along. */
387
471
  data: string;
388
- /** Length of that path, used to centre the run on it. */
472
+ /** Length of that path. */
389
473
  length: number;
390
474
  }
391
- /** Path the given curve traces for a text run of `width` px, or null when straight. */
392
- declare function buildCurvePathData(config: TextCurveConfig, width: number, fontSize: number): CurvePath | null;
475
+ /**
476
+ * Fills in a partial curve.
477
+ *
478
+ * States saved before the shape switch existed carry only `arc` and `wave`, and
479
+ * held exactly one of them — so the non-zero one names the shape.
480
+ */
481
+ declare function normalizeTextCurve(config: TextCurveInput): TextCurveConfig;
482
+ /**
483
+ * One path per line of text, in a single shared coordinate frame.
484
+ *
485
+ * Fabric lays every line of a text object along the *same* path, so a
486
+ * multi-line run collapses into one overlapping pile. Each line gets its own
487
+ * path here, and `TextCurveManager` measures each line against its own — arcs
488
+ * concentric around one centre, waves stacked a line-height apart. The block is
489
+ * centred on the single-line baseline so adding a line doesn't shift the design.
490
+ */
491
+ declare function buildCurveLinePaths(config: TextCurveInput, width: number, fontSize: number, lineCount?: number, lineHeight?: number): CurvePath[] | null;
492
+ /** Path the given curve traces for a single-line run, or null when straight. */
493
+ declare function buildCurvePathData(config: TextCurveInput, width: number, fontSize: number): CurvePath | null;
494
+
393
495
  /**
394
496
  * Bends a text layer's baseline along a generated path.
395
497
  *
@@ -407,18 +509,44 @@ declare class TextCurveManager {
407
509
  /** Curve parameters for a layer, or null when it is not curved text. */
408
510
  get(layerId: string): TextCurveConfig | null;
409
511
  isCurved(layerId: string): boolean;
410
- /** Apply (or update) the curve on a text layer. Zeroed config clears it. */
411
- apply(layerId: string, config: Partial<TextCurveConfig>, save?: boolean): boolean;
512
+ /** Apply (or update) the curve on a text layer. A straight config clears it. */
513
+ apply(layerId: string, config: TextCurveInput, save?: boolean): boolean;
412
514
  /** Remove the curve, restoring the authored text box width. */
413
515
  clear(layerId: string, save?: boolean): boolean;
414
516
  /**
415
- * Rebuild the path from the stored parameters. Text content, font family and
416
- * font size all change the run's width, and the path is sized to that width
417
- * without this the curve keeps the geometry of the text it was created from.
517
+ * Rebuild the paths from the stored parameters. Text content, line count,
518
+ * font family and font size all change the geometry the paths are sized to —
519
+ * without this the curve keeps that of the text it was created from.
418
520
  */
419
521
  refresh(layerId: string, save?: boolean): boolean;
420
522
  /** Rebuild every curved layer — used after a state restore. */
421
523
  refreshAll(): void;
524
+ /**
525
+ * Puts every line's path on the object as one shape, and hooks per-line
526
+ * measuring so each line is laid out on its own.
527
+ *
528
+ * The object's own path is the union of the lines: fabric sizes a curved text
529
+ * object from it, and a single line's path would leave the rest of the block
530
+ * outside the layer's box — where object caching clips it away.
531
+ */
532
+ private attach;
533
+ /**
534
+ * Fabric lays every line of a text object along `this.path`, from one
535
+ * `pathStartOffset` — so a multi-line run piles all its lines on top of each
536
+ * other. Each line is measured against its own path instead, by swapping the
537
+ * path in around fabric's own per-line measure pass.
538
+ *
539
+ * The paths all share the first one's `pathOffset`, which is the origin
540
+ * fabric subtracts to place a glyph in the object — without that each line
541
+ * would be re-centred on its own bounding box and land back in the same spot.
542
+ *
543
+ * `textAlign` is switched to centre for the pass, which is how fabric centres
544
+ * a line on its path; the authored value is restored before anything else
545
+ * reads it.
546
+ */
547
+ private patchLineMeasure;
548
+ /** Restore fabric's own per-line measuring, if this manager replaced it. */
549
+ private unpatchLineMeasure;
422
550
  private detach;
423
551
  }
424
552
 
@@ -930,15 +1058,21 @@ declare class CanvasEditor {
930
1058
  addTemplate(template: TemplateDefinition, params: Record<string, string | number>): Promise<Layer>;
931
1059
  removeLayer(id: string): void;
932
1060
  selectLayer(id: string | null): void;
1061
+ /** Select several layers at once — what a panel's shift/⌘ click drives. */
1062
+ selectLayers(ids: string[]): void;
933
1063
  getSelectedLayer(): Layer | null;
934
1064
  /** Mirror a layer along the given axis. */
935
1065
  flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
936
1066
  /** Clone a layer (offset slightly) and select the copy. */
937
1067
  duplicateLayer(id: string): Promise<Layer | null>;
938
1068
  applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
939
- /** Combine two or more layers into a single editable group layer. */
1069
+ /**
1070
+ * Combine two or more layers into one group layer. Picking a group among them
1071
+ * **absorbs** it — its children join the new group and the old group record is
1072
+ * dropped — because groups are exactly one level deep.
1073
+ */
940
1074
  groupLayers(ids: string[], name?: string): Promise<Layer | null>;
941
- /** Restore a group created by groupLayers back to its original layer records. */
1075
+ /** Split a group back into the layers it holds, in place. */
942
1076
  ungroupLayer(id: string): Promise<Layer[]>;
943
1077
  toJSON(): EditorState;
944
1078
  fromJSON(state: EditorState): Promise<void>;
@@ -1050,6 +1184,37 @@ declare class CanvasEditor {
1050
1184
  private setupCanvasEvents;
1051
1185
  }
1052
1186
 
1187
+ /**
1188
+ * A template is a bootstrap, not a frozen picture: it is taken apart into the
1189
+ * layers it is drawn from, so every run of copy stays editable afterwards.
1190
+ */
1191
+ interface TemplateLayerSpec {
1192
+ type: 'text' | 'shape';
1193
+ name: string;
1194
+ object: FabricObject;
1195
+ /**
1196
+ * Baseline curve to apply once the layer exists (`<textPath>` templates).
1197
+ * Partial on purpose: a template states only the parameters it cares about
1198
+ * and `TextCurveManager.apply` normalizes the rest.
1199
+ */
1200
+ curve?: Partial<TextCurveConfig>;
1201
+ }
1202
+ /**
1203
+ * Curve a `<textPath>` template asks for.
1204
+ *
1205
+ * Fabric's SVG parser cannot read `<textPath>` at all, so these templates are
1206
+ * rebuilt from their parameters instead of parsed — the curve is the engine's
1207
+ * own, which keeps the text editable rather than rasterized.
1208
+ */
1209
+ declare function textPathCurve(template: TemplateDefinition, values: Record<string, string | number>, runWidth: number): Partial<TextCurveConfig>;
1210
+ /** The single text layer a `<textPath>` template stands for. */
1211
+ declare function textPathSpec(template: TemplateDefinition, values: Record<string, string | number>): TemplateLayerSpec;
1212
+ /**
1213
+ * The layers a resolved template SVG is made of, in draw order: every `<text>`
1214
+ * an editable text layer, every other top-level element a vector layer.
1215
+ */
1216
+ declare function explodeTemplateSvg(template: TemplateDefinition, resolvedSvg: string, values: Record<string, string | number>): Promise<TemplateLayerSpec[]>;
1217
+
1053
1218
  declare const DEFAULT_LAYER_SHADOW: LayerShadowConfig;
1054
1219
  /**
1055
1220
  * Read a layer's drop shadow back off its fabric object.
@@ -1175,4 +1340,4 @@ declare class AnnotationOverlay {
1175
1340
  */
1176
1341
  declare function displaceRgba(source: Uint8ClampedArray, map: Uint8ClampedArray, width: number, height: number, options: Omit<MockupDisplacement, 'image'>): Uint8ClampedArray;
1177
1342
 
1178
- export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, 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, TextCurveConfig, TextCurveManager, TextureMaskPresetId, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, readLayerShadow, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, toCanvasSpace, toHostSpace, unwrapGroup };
1343
+ export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, 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, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, 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, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, readLayerShadow, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unwrapGroup };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Canvas, FabricObject, Point, ImageFormat, Group } from 'fabric';
2
- import { b as EditorEvents, o as LayerType, m as LayerMeta, L as LayerData, X as SerializedLayer, P as PatternConfig, K as PatternLocks, a1 as TextCurveConfig, t as MaskPresetId, Y as ShapeMaskPresetId, a2 as TextureMaskPresetId, a4 as Unit, J as MockupPrintArea, z as MockupConfig, e as FontDefinition, p as LicenseConfig, r as LicenseStatus, T as ProjectState, M as MaskBrushOptions, s as MaskPoint, v as MaskRefinementProvider, u as MaskRefinementPrompt, x as MaskRefinementResult, k as LayerMaskEntry, l as LayerMaskMode, E as EditorConfig, Z as ShapePlugin, $ as TemplateDefinition, I as ImageAdjustments, c as EditorState, V as SemanticExportOptions, _ as SvgExportOptions, R as PrintifyPositioning, N as NormalizedLayerPosition, Q as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, W as SerializedBackgroundImageOptions, B as BackgroundImageOptions, U as ResizeOptions, a as DpiIssue, n as LayerShadowConfig, C as CanvasSizePreset, A as MockupDisplacement } from './types-JP8MZsIs.js';
3
- export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, q as LicensePayload, w as MaskRefinementRequest, y as MockupBlendMode, G as MockupDisplacementChannel, H as MockupOverlay, O as PatternState, S as ProjectPage, a0 as TemplateParameter, a3 as TileMode } from './types-JP8MZsIs.js';
2
+ import { b as EditorEvents, o as LayerType, m as LayerMeta, L as LayerData, X as SerializedLayer, P as PatternConfig, K as PatternLocks, a1 as TextCurveConfig, a2 as TextCurveInput, t as MaskPresetId, Y as ShapeMaskPresetId, a4 as TextureMaskPresetId, a6 as Unit, J as MockupPrintArea, z as MockupConfig, e as FontDefinition, p as LicenseConfig, r as LicenseStatus, T as ProjectState, M as MaskBrushOptions, s as MaskPoint, v as MaskRefinementProvider, u as MaskRefinementPrompt, x as MaskRefinementResult, k as LayerMaskEntry, l as LayerMaskMode, E as EditorConfig, Z as ShapePlugin, $ as TemplateDefinition, I as ImageAdjustments, c as EditorState, V as SemanticExportOptions, _ as SvgExportOptions, R as PrintifyPositioning, N as NormalizedLayerPosition, Q as PositioningAdapter, h as ImageProviderResult, i as ImageSearchOptions, j as ImageSearchResult, F as FileAdapter, g as ImageProvider, W as SerializedBackgroundImageOptions, B as BackgroundImageOptions, U as ResizeOptions, a as DpiIssue, n as LayerShadowConfig, C as CanvasSizePreset, A as MockupDisplacement } from './types-LM7pOkkj.js';
3
+ export { D as DEFAULT_PATTERN_CONFIG, d as ExportFormat, f as ImageAttribution, q as LicensePayload, w as MaskRefinementRequest, y as MockupBlendMode, G as MockupDisplacementChannel, H as MockupOverlay, O as PatternState, S as ProjectPage, a0 as TemplateParameter, a3 as TextCurveShape, a5 as TileMode } from './types-LM7pOkkj.js';
4
4
 
5
5
  type EventHandler<T> = (data: T) => void;
6
6
  declare class EventEmitter<TEvents extends {} = Record<string, unknown>> {
@@ -28,6 +28,14 @@ declare class Layer {
28
28
  * the layer's real object stays the one every editor API talks to.
29
29
  */
30
30
  renderProxy: FabricObject | null;
31
+ /**
32
+ * Layers nested inside this one, in draw order. Only a `group` layer has any:
33
+ * their fabric objects live inside this layer's fabric `Group`, not on the
34
+ * canvas, which is why the manager keeps them off the canvas stack.
35
+ */
36
+ children: Layer[];
37
+ /** Group this layer sits inside, or null when it is on the canvas stack. */
38
+ parentId: string | null;
31
39
  constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
32
40
  private hasMeta;
33
41
  toData(): LayerData;
@@ -42,6 +50,26 @@ declare class LayerManager {
42
50
  setHistoryCallback(callback: () => void): void;
43
51
  add(type: LayerType, fabricObject: FabricObject, name?: string, id?: string): Layer;
44
52
  remove(id: string): boolean;
53
+ /**
54
+ * Take a top-level layer off the canvas stack **without** disposing it — it is
55
+ * about to become a group's child, so its object has to stay alive.
56
+ */
57
+ detach(id: string): Layer | undefined;
58
+ /** Put a group's children back on the canvas stack and drop the group. */
59
+ explode(group: Layer): Layer[];
60
+ /**
61
+ * Empty a group onto the canvas stack, in the group's own place, and drop the
62
+ * group record. `removeAll` restores each child's absolute transform, so the
63
+ * group's matrix must NOT be re-applied on top of it.
64
+ */
65
+ private dissolve;
66
+ /**
67
+ * Re-attach child records to an enlivened group. `data[i]` describes
68
+ * `group._objects[i]` — the order fabric serializes and restores them in. A
69
+ * missing record still becomes a child, so a hand-edited state cannot drop
70
+ * artwork off the canvas.
71
+ */
72
+ adoptGroupChildren(group: Layer, data: LayerData[]): void;
45
73
  /** Replace a layer's render object while preserving its immutable ID and panel state. */
46
74
  replaceObject(id: string, fabricObject: FabricObject): boolean;
47
75
  /**
@@ -57,10 +85,26 @@ declare class LayerManager {
57
85
  * front-to-back instead of computed.
58
86
  */
59
87
  private syncZOrder;
88
+ /** The list a layer lives in: its group's children, or the canvas stack. */
89
+ private siblingsOf;
60
90
  reorder(id: string, newIndex: number): boolean;
61
91
  select(id: string | null): void;
92
+ /** Drill into a group so its children can be selected and clicked. */
93
+ private enterGroup;
94
+ /** Leave every entered group — selecting anything else is done drilling in. */
95
+ exitGroups(): void;
96
+ /**
97
+ * Select several layers at once, as one fabric `ActiveSelection`. Children are
98
+ * skipped: a selection spanning in and out of a group has no single transform.
99
+ */
100
+ selectMany(ids: string[]): void;
101
+ /** Depth-first over the whole tree, each layer before its children. */
102
+ private walk;
62
103
  get(id: string): Layer | undefined;
104
+ /** Top-level layers only — the canvas stack. Children hang off their group. */
63
105
  getAll(): Layer[];
106
+ /** Top-level layers, each carrying its children: what the layer panel renders. */
107
+ getTree(): LayerData[];
64
108
  findByObject(obj: FabricObject): Layer | undefined;
65
109
  setVisibility(id: string, visible: boolean): void;
66
110
  setLocked(id: string, locked: boolean): void;
@@ -323,8 +367,32 @@ declare class TiledPatternObject extends FabricObject {
323
367
  * tiling. The copy shares the source (it only ever reads from it).
324
368
  */
325
369
  clone(): Promise<this>;
370
+ /**
371
+ * The source's tile footprint: its bounding box, minus a stroke it reserves
372
+ * room for but never paints.
373
+ *
374
+ * fabric keeps `strokeWidth` inside an object's box whether or not a `stroke`
375
+ * colour paints it, and the built-in shapes arrive with `strokeWidth: 1` and no
376
+ * stroke. Stepping the grid by that box puts a transparent seam between every
377
+ * pair of neighbours at zero spacing: the artwork is a pixel narrower than the
378
+ * box it is stepped by.
379
+ */
380
+ private sourceBox;
326
381
  /** The source's on-canvas width, before the tile scale. */
327
382
  private baseW;
383
+ /** The source's on-canvas height, before the tile scale. */
384
+ private baseH;
385
+ /**
386
+ * Size to paint the snapshot at, for a tile of `tileW × tileH`.
387
+ *
388
+ * The snapshot is NOT exactly the source's box: `toCanvasElement` rounds the
389
+ * raster up to whole pixels and pads it further for a shadow. Painting it into
390
+ * the tile step would squeeze the artwork inside that padding — every tile
391
+ * shrinks by up to a pixel and the grid shows transparent seams at zero
392
+ * spacing. So the bitmap is painted at its own footprint, scaled by the same
393
+ * factor the tile is, and the step stays the source's box.
394
+ */
395
+ private drawSize;
328
396
  /** Tile size from the config alone, ignoring any in-flight gesture. */
329
397
  private baseTile;
330
398
  /** Tile size as drawn right now, including a live scale gesture. */
@@ -356,6 +424,18 @@ interface PatternOrigin {
356
424
  x: number;
357
425
  y: number;
358
426
  }
427
+ /**
428
+ * Size the tile bitmap is painted at, when that differs from the grid step.
429
+ *
430
+ * A snapshot of the source is not always exactly the source's box: the raster is
431
+ * allocated in whole pixels, and a shadow pads it further. Painting such a bitmap
432
+ * into the step would shrink the artwork inside its own transparent margin and
433
+ * open a hairline gap between neighbours at zero spacing.
434
+ */
435
+ interface TileDrawSize {
436
+ width: number;
437
+ height: number;
438
+ }
359
439
  /**
360
440
  * Pure tile geometry: where each tile centre lands and how much it is rotated,
361
441
  * for a config + target/base size. Covers every corner of the target from the
@@ -369,8 +449,12 @@ declare function computeTilePositions(config: PatternConfig, targetW: number, ta
369
449
  * Draw the tiled pattern onto a 2D context, in target coordinates (0,0 = the
370
450
  * target's top-left corner). The geometry lives in {@link computeTilePositions};
371
451
  * this just plays it out as canvas calls.
452
+ *
453
+ * `baseW`/`baseH` are the grid STEP. `draw` is the size the bitmap is painted at
454
+ * and defaults to the step — pass it when the bitmap carries padding the step
455
+ * does not (see {@link TileDrawSize}), so the artwork still lands step-sized.
372
456
  */
373
- declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, origin?: PatternOrigin): void;
457
+ declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number, origin?: PatternOrigin, draw?: TileDrawSize): void;
374
458
  /** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
375
459
  interface CanvasRenderingProtocol {
376
460
  save(): void;
@@ -383,13 +467,31 @@ interface CanvasRenderingProtocol {
383
467
  /** Straight text — the state every text layer starts in. */
384
468
  declare const DEFAULT_TEXT_CURVE: TextCurveConfig;
385
469
  interface CurvePath {
386
- /** SVG path data the text is laid out along. */
470
+ /** SVG path data the line is laid out along. */
387
471
  data: string;
388
- /** Length of that path, used to centre the run on it. */
472
+ /** Length of that path. */
389
473
  length: number;
390
474
  }
391
- /** Path the given curve traces for a text run of `width` px, or null when straight. */
392
- declare function buildCurvePathData(config: TextCurveConfig, width: number, fontSize: number): CurvePath | null;
475
+ /**
476
+ * Fills in a partial curve.
477
+ *
478
+ * States saved before the shape switch existed carry only `arc` and `wave`, and
479
+ * held exactly one of them — so the non-zero one names the shape.
480
+ */
481
+ declare function normalizeTextCurve(config: TextCurveInput): TextCurveConfig;
482
+ /**
483
+ * One path per line of text, in a single shared coordinate frame.
484
+ *
485
+ * Fabric lays every line of a text object along the *same* path, so a
486
+ * multi-line run collapses into one overlapping pile. Each line gets its own
487
+ * path here, and `TextCurveManager` measures each line against its own — arcs
488
+ * concentric around one centre, waves stacked a line-height apart. The block is
489
+ * centred on the single-line baseline so adding a line doesn't shift the design.
490
+ */
491
+ declare function buildCurveLinePaths(config: TextCurveInput, width: number, fontSize: number, lineCount?: number, lineHeight?: number): CurvePath[] | null;
492
+ /** Path the given curve traces for a single-line run, or null when straight. */
493
+ declare function buildCurvePathData(config: TextCurveInput, width: number, fontSize: number): CurvePath | null;
494
+
393
495
  /**
394
496
  * Bends a text layer's baseline along a generated path.
395
497
  *
@@ -407,18 +509,44 @@ declare class TextCurveManager {
407
509
  /** Curve parameters for a layer, or null when it is not curved text. */
408
510
  get(layerId: string): TextCurveConfig | null;
409
511
  isCurved(layerId: string): boolean;
410
- /** Apply (or update) the curve on a text layer. Zeroed config clears it. */
411
- apply(layerId: string, config: Partial<TextCurveConfig>, save?: boolean): boolean;
512
+ /** Apply (or update) the curve on a text layer. A straight config clears it. */
513
+ apply(layerId: string, config: TextCurveInput, save?: boolean): boolean;
412
514
  /** Remove the curve, restoring the authored text box width. */
413
515
  clear(layerId: string, save?: boolean): boolean;
414
516
  /**
415
- * Rebuild the path from the stored parameters. Text content, font family and
416
- * font size all change the run's width, and the path is sized to that width
417
- * without this the curve keeps the geometry of the text it was created from.
517
+ * Rebuild the paths from the stored parameters. Text content, line count,
518
+ * font family and font size all change the geometry the paths are sized to —
519
+ * without this the curve keeps that of the text it was created from.
418
520
  */
419
521
  refresh(layerId: string, save?: boolean): boolean;
420
522
  /** Rebuild every curved layer — used after a state restore. */
421
523
  refreshAll(): void;
524
+ /**
525
+ * Puts every line's path on the object as one shape, and hooks per-line
526
+ * measuring so each line is laid out on its own.
527
+ *
528
+ * The object's own path is the union of the lines: fabric sizes a curved text
529
+ * object from it, and a single line's path would leave the rest of the block
530
+ * outside the layer's box — where object caching clips it away.
531
+ */
532
+ private attach;
533
+ /**
534
+ * Fabric lays every line of a text object along `this.path`, from one
535
+ * `pathStartOffset` — so a multi-line run piles all its lines on top of each
536
+ * other. Each line is measured against its own path instead, by swapping the
537
+ * path in around fabric's own per-line measure pass.
538
+ *
539
+ * The paths all share the first one's `pathOffset`, which is the origin
540
+ * fabric subtracts to place a glyph in the object — without that each line
541
+ * would be re-centred on its own bounding box and land back in the same spot.
542
+ *
543
+ * `textAlign` is switched to centre for the pass, which is how fabric centres
544
+ * a line on its path; the authored value is restored before anything else
545
+ * reads it.
546
+ */
547
+ private patchLineMeasure;
548
+ /** Restore fabric's own per-line measuring, if this manager replaced it. */
549
+ private unpatchLineMeasure;
422
550
  private detach;
423
551
  }
424
552
 
@@ -930,15 +1058,21 @@ declare class CanvasEditor {
930
1058
  addTemplate(template: TemplateDefinition, params: Record<string, string | number>): Promise<Layer>;
931
1059
  removeLayer(id: string): void;
932
1060
  selectLayer(id: string | null): void;
1061
+ /** Select several layers at once — what a panel's shift/⌘ click drives. */
1062
+ selectLayers(ids: string[]): void;
933
1063
  getSelectedLayer(): Layer | null;
934
1064
  /** Mirror a layer along the given axis. */
935
1065
  flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
936
1066
  /** Clone a layer (offset slightly) and select the copy. */
937
1067
  duplicateLayer(id: string): Promise<Layer | null>;
938
1068
  applyImageAdjustments(layerId: string, adjustments: ImageAdjustments): boolean;
939
- /** Combine two or more layers into a single editable group layer. */
1069
+ /**
1070
+ * Combine two or more layers into one group layer. Picking a group among them
1071
+ * **absorbs** it — its children join the new group and the old group record is
1072
+ * dropped — because groups are exactly one level deep.
1073
+ */
940
1074
  groupLayers(ids: string[], name?: string): Promise<Layer | null>;
941
- /** Restore a group created by groupLayers back to its original layer records. */
1075
+ /** Split a group back into the layers it holds, in place. */
942
1076
  ungroupLayer(id: string): Promise<Layer[]>;
943
1077
  toJSON(): EditorState;
944
1078
  fromJSON(state: EditorState): Promise<void>;
@@ -1050,6 +1184,37 @@ declare class CanvasEditor {
1050
1184
  private setupCanvasEvents;
1051
1185
  }
1052
1186
 
1187
+ /**
1188
+ * A template is a bootstrap, not a frozen picture: it is taken apart into the
1189
+ * layers it is drawn from, so every run of copy stays editable afterwards.
1190
+ */
1191
+ interface TemplateLayerSpec {
1192
+ type: 'text' | 'shape';
1193
+ name: string;
1194
+ object: FabricObject;
1195
+ /**
1196
+ * Baseline curve to apply once the layer exists (`<textPath>` templates).
1197
+ * Partial on purpose: a template states only the parameters it cares about
1198
+ * and `TextCurveManager.apply` normalizes the rest.
1199
+ */
1200
+ curve?: Partial<TextCurveConfig>;
1201
+ }
1202
+ /**
1203
+ * Curve a `<textPath>` template asks for.
1204
+ *
1205
+ * Fabric's SVG parser cannot read `<textPath>` at all, so these templates are
1206
+ * rebuilt from their parameters instead of parsed — the curve is the engine's
1207
+ * own, which keeps the text editable rather than rasterized.
1208
+ */
1209
+ declare function textPathCurve(template: TemplateDefinition, values: Record<string, string | number>, runWidth: number): Partial<TextCurveConfig>;
1210
+ /** The single text layer a `<textPath>` template stands for. */
1211
+ declare function textPathSpec(template: TemplateDefinition, values: Record<string, string | number>): TemplateLayerSpec;
1212
+ /**
1213
+ * The layers a resolved template SVG is made of, in draw order: every `<text>`
1214
+ * an editable text layer, every other top-level element a vector layer.
1215
+ */
1216
+ declare function explodeTemplateSvg(template: TemplateDefinition, resolvedSvg: string, values: Record<string, string | number>): Promise<TemplateLayerSpec[]>;
1217
+
1053
1218
  declare const DEFAULT_LAYER_SHADOW: LayerShadowConfig;
1054
1219
  /**
1055
1220
  * Read a layer's drop shadow back off its fabric object.
@@ -1175,4 +1340,4 @@ declare class AnnotationOverlay {
1175
1340
  */
1176
1341
  declare function displaceRgba(source: Uint8ClampedArray, map: Uint8ClampedArray, width: number, height: number, options: Omit<MockupDisplacement, 'image'>): Uint8ClampedArray;
1177
1342
 
1178
- export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, CANVAS_MASK_TARGET, CANVAS_SIZE_PRESETS, CanvasEditor, type CanvasRenderingProtocol, CanvasSizePreset, type CoverPlacement, CropController, DEFAULT_LAYER_SHADOW, DEFAULT_SELECTION_STYLE, DEFAULT_TEXT_CURVE, DpiIssue, EditorConfig, EditorEvents, EditorState, EventEmitter, FileAdapter, FontDefinition, FontRegistry, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, 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, TextCurveConfig, TextCurveManager, TextureMaskPresetId, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, readLayerShadow, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, toCanvasSpace, toHostSpace, unwrapGroup };
1343
+ export { type AddMaskOptions, AnnotationOverlay, type AnnotationPrimitive, BackgroundImageOptions, 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, HistoryManager, ImageAdjustments, ImageProvider, ImageProviderResult, ImageSearchOptions, ImageSearchResult, Layer, LayerData, LayerManager, LayerMaskEntry, LayerMaskManager, LayerMaskMode, LayerMeta, LayerShadowConfig, LayerType, LicenseConfig, LicenseManager, LicenseStatus, 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, TextureMaskPresetId, type TileDrawSize, type TilePlacement, TiledPatternObject, Unit, UnitConverter, type ViewportTransform, applyAspectLock, applyLayerShadow, applyObjectSelectionStyle, applySelectionStyle, buildCurveLinePaths, buildCurvePathData, clamp, clearTextureMaskCache, composeMaskGroup, computeCoverPlacement, computePrintAreaClip, computeTilePositions, deserializeEditor, displaceRgba, drawTiles, escapeXml, explodeTemplateSvg, exportDataURL, exportMockup, exportPNG, exportPrintArea, exportSVG, fitToBox, generateId, isCssColor, isMaskPresetId, isShapeMaskId, isTextureMaskId, needsAbsoluteSpace, normalizeTextCurve, readLayerShadow, renderTextureMask, resetTransform, restoreLocks, round2, sanitizeSvg, serializeEditor, shapeMaskPathData, textPathCurve, textPathSpec, toCanvasSpace, toHostSpace, unwrapGroup };