@snowcone-app/canvas 0.23.0 → 0.27.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.
Files changed (73) hide show
  1. package/ERROR_CONTRACT.md +638 -0
  2. package/README.md +2 -1
  3. package/STYLING_CONTRACT.md +59 -8
  4. package/dist/{CanvasRenderer-6_HhR4-q.js → CanvasRenderer-yszzrDfo.js} +4 -4
  5. package/dist/{CanvasRenderer-6_HhR4-q.js.map → CanvasRenderer-yszzrDfo.js.map} +1 -1
  6. package/dist/{CanvasStateV1-DmZ1Qvvn.js → CanvasStateV1-BTbCD_xC.js} +3 -3
  7. package/dist/{CanvasStateV1-DmZ1Qvvn.js.map → CanvasStateV1-BTbCD_xC.js.map} +1 -1
  8. package/dist/{ContextualToolbars-BDEt9ND0.js → ContextualToolbars-BHjYsril.js} +6 -6
  9. package/dist/{ContextualToolbars-BDEt9ND0.js.map → ContextualToolbars-BHjYsril.js.map} +1 -1
  10. package/dist/{EditorCanvasImpl-Ckg7WO2j.js → EditorCanvasImpl-Ui8Ceb-h.js} +8 -8
  11. package/dist/{EditorCanvasImpl-Ckg7WO2j.js.map → EditorCanvasImpl-Ui8Ceb-h.js.map} +1 -1
  12. package/dist/{ExportManager-DoU4VK6h.js → ExportManager-BTcyj4cf.js} +2 -2
  13. package/dist/{ExportManager-DoU4VK6h.js.map → ExportManager-BTcyj4cf.js.map} +1 -1
  14. package/dist/{FontAnalyzer-CwIpgTGd.js → FontAnalyzer-EF3gLPr8.js} +30 -20
  15. package/dist/{FontAnalyzer-CwIpgTGd.js.map → FontAnalyzer-EF3gLPr8.js.map} +1 -1
  16. package/dist/{ImagePanel-BwqFDKvW.js → ImagePanel-CIk6z41z.js} +6 -6
  17. package/dist/{ImagePanel-BwqFDKvW.js.map → ImagePanel-CIk6z41z.js.map} +1 -1
  18. package/dist/{SnowconeCanvas-D1sLcIja.js → SnowconeCanvas-DuWALOAt.js} +10 -10
  19. package/dist/{SnowconeCanvas-D1sLcIja.js.map → SnowconeCanvas-DuWALOAt.js.map} +1 -1
  20. package/dist/{UnifiedFontService-CC3CSmH5.js → UnifiedFontService-CHVYDBDW.js} +869 -836
  21. package/dist/{UnifiedFontService-CC3CSmH5.js.map → UnifiedFontService-CHVYDBDW.js.map} +1 -1
  22. package/dist/advanced.mjs +14 -14
  23. package/dist/api/embed.d.ts +6 -2
  24. package/dist/components/editor/EditorLoadingOverlay.d.ts +12 -0
  25. package/dist/components/editor/EditorPlacements.d.ts +14 -0
  26. package/dist/components/editor/EditorPreview.d.ts +32 -8
  27. package/dist/components/editor/EditorRoot.d.ts +12 -0
  28. package/dist/components/editor/PreviewPrismOverlay.d.ts +23 -0
  29. package/dist/components/editor/RootInternals.d.ts +31 -0
  30. package/dist/components/editor/editorAudit.d.ts +66 -0
  31. package/dist/components/editor/index.d.ts +14 -0
  32. package/dist/components/editor/usePlacements.d.ts +14 -0
  33. package/dist/components/embed-realtime/context.d.ts +11 -2
  34. package/dist/components/embed-realtime/validateEmbed.d.ts +20 -1
  35. package/dist/contexts/EditorContext.d.ts +34 -0
  36. package/dist/core/HybridHistoryManager.d.ts +7 -0
  37. package/dist/core/elementGuards.d.ts +19 -0
  38. package/dist/{custom-icons-BW6hqmkL.js → custom-icons-CcLMyybv.js} +7 -7
  39. package/dist/{custom-icons-BW6hqmkL.js.map → custom-icons-CcLMyybv.js.map} +1 -1
  40. package/dist/design/design-builder.d.ts +41 -3
  41. package/dist/design/product-config.d.ts +10 -0
  42. package/dist/{design-builder-2VUjfmdt.js → design-builder-cZY958Rw.js} +109 -61
  43. package/dist/design-builder-cZY958Rw.js.map +1 -0
  44. package/dist/editorErrors-BhrZ_nwj.js +1219 -0
  45. package/dist/editorErrors-BhrZ_nwj.js.map +1 -0
  46. package/dist/embed-CJswRZte.js +1586 -0
  47. package/dist/embed-CJswRZte.js.map +1 -0
  48. package/dist/embed.mjs +42 -34
  49. package/dist/errors/editorError.d.ts +29 -1
  50. package/dist/{guards-8rkFAMBs.js → guards-DIX8aXWM.js} +2 -2
  51. package/dist/{guards-8rkFAMBs.js.map → guards-DIX8aXWM.js.map} +1 -1
  52. package/dist/hooks/elementPatch.d.ts +96 -0
  53. package/dist/hooks/useCommands.d.ts +20 -0
  54. package/dist/index.mjs +8 -8
  55. package/dist/internals.mjs +9 -9
  56. package/dist/style.css +1 -1
  57. package/dist/template-fields-BXl29sgh.js +716 -0
  58. package/dist/template-fields-BXl29sgh.js.map +1 -0
  59. package/dist/testing.mjs +4 -4
  60. package/dist/{usePieceGuideBundle-CbJJg66S.js → usePieceGuideBundle-DE21DQGZ.js} +2 -2
  61. package/dist/{usePieceGuideBundle-CbJJg66S.js.map → usePieceGuideBundle-DE21DQGZ.js.map} +1 -1
  62. package/dist/{validation-C9Fe9ahK.js → validation-DGXAQmUC.js} +11 -11
  63. package/dist/{validation-C9Fe9ahK.js.map → validation-DGXAQmUC.js.map} +1 -1
  64. package/example/package.json +1 -1
  65. package/llms.txt +3 -0
  66. package/package.json +7 -4
  67. package/dist/design-builder-2VUjfmdt.js.map +0 -1
  68. package/dist/editorErrors-B2mb1sVN.js +0 -1208
  69. package/dist/editorErrors-B2mb1sVN.js.map +0 -1
  70. package/dist/embed-DxsaqZJF.js +0 -1226
  71. package/dist/embed-DxsaqZJF.js.map +0 -1
  72. package/dist/template-fields-CQ6n2P4V.js +0 -548
  73. package/dist/template-fields-CQ6n2P4V.js.map +0 -1
package/dist/embed.mjs CHANGED
@@ -1,46 +1,54 @@
1
- import { C as a, a as r, b as o, u as t, d as i, f as d, g as n } from "./UnifiedFontService-CC3CSmH5.js";
2
- import { E as m, R as l, a as E, b as c, S as p, c as g, f, p as S, d as x, e as T, v } from "./embed-DxsaqZJF.js";
3
- import { g as b, i as B, u as y } from "./editorErrors-B2mb1sVN.js";
4
- import { D as R, d as D, a as k, i as F } from "./design-builder-2VUjfmdt.js";
5
- import { D as L, T as w, r as M, u as h, a as A, b as _, c as z, d as G, e as K, f as N, w as Y } from "./template-fields-CQ6n2P4V.js";
6
- import { s as q } from "./CanvasStateV1-DmZ1Qvvn.js";
1
+ import { C as a, a as r, b as t, u as i, d as o, f as n, g as d } from "./UnifiedFontService-CHVYDBDW.js";
2
+ import { E as l, R as u, a as E, b as c, S as p, c as g, d as S, f, p as x, e as T, g as v, h as C, v as P } from "./embed-CJswRZte.js";
3
+ import { g as B, i as h, u as y } from "./editorErrors-BhrZ_nwj.js";
4
+ import { D as k, d as D, a as I, i as F } from "./design-builder-cZY958Rw.js";
5
+ import { D as w, T as M, h as A, i as G, j as K, k as _, l as j, m as z, r as N, u as Y, a as q, b as H, c as J, d as O, e as Q, f as U, w as V } from "./template-fields-BXl29sgh.js";
6
+ import { s as X } from "./CanvasStateV1-BTbCD_xC.js";
7
7
  export {
8
8
  a as CanvasServicesProvider,
9
- R as DesignBuilder,
10
- L as DesignStateStore,
11
- m as Editor,
12
- b as EditorError,
13
- l as RealtimeCanvas,
9
+ k as DesignBuilder,
10
+ w as DesignStateStore,
11
+ l as Editor,
12
+ B as EditorError,
13
+ u as RealtimeCanvas,
14
14
  E as RealtimeEmbed,
15
15
  c as RealtimeMockup,
16
16
  p as SnowconeEditor,
17
- w as TEMPLATE_FIELDS_KEY,
18
- g as collectEmbedIssues,
17
+ M as TEMPLATE_FIELDS_KEY,
18
+ g as auditEditor,
19
+ S as collectEmbedIssues,
19
20
  r as createProxyGenerate,
20
- o as createProxyImageSearch,
21
+ t as createProxyImageSearch,
21
22
  D as design,
23
+ A as editorElementKind,
22
24
  f as formatBuyPrice,
23
- k as isColorToken,
24
- B as isEditorError,
25
+ I as isColorToken,
26
+ h as isEditorError,
27
+ G as isGroupElement,
28
+ K as isImageElement,
25
29
  F as isLayerToken,
26
- S as productToRenderConfig,
27
- M as readTemplateFields,
28
- q as serializeState,
29
- t as useArtboards,
30
- i as useCanvasServices,
31
- h as useColorBinding,
32
- A as useCommands,
30
+ _ as isPathElement,
31
+ j as isShapeElement,
32
+ z as isTextElement,
33
+ x as productToRenderConfig,
34
+ N as readTemplateFields,
35
+ X as serializeState,
36
+ i as useArtboards,
37
+ o as useCanvasServices,
38
+ Y as useColorBinding,
39
+ q as useCommands,
33
40
  y as useEditor,
34
- _ as useElementByName,
35
- d as useExport,
36
- z as useFontBinding,
37
- G as useImageBinding,
38
- n as useLayers,
39
- x as useProductSelection,
40
- T as useRealtimeMockups,
41
- K as useSelectedElement,
42
- N as useTextBinding,
43
- v as validateEmbed,
44
- Y as withTemplateFields
41
+ H as useElementByName,
42
+ n as useExport,
43
+ J as useFontBinding,
44
+ O as useImageBinding,
45
+ d as useLayers,
46
+ T as usePlacements,
47
+ v as useProductSelection,
48
+ C as useRealtimeMockups,
49
+ Q as useSelectedElement,
50
+ U as useTextBinding,
51
+ P as validateEmbed,
52
+ V as withTemplateFields
45
53
  };
46
54
  //# sourceMappingURL=embed.mjs.map
@@ -36,6 +36,12 @@ export type EditorErrorCode =
36
36
  /** `productToRenderConfig`: the catalog product has no renderable image
37
37
  * placement / no mockup scenes, or the requested placement doesn't exist. */
38
38
  | 'E_PRODUCT_NOT_RENDERABLE'
39
+ /** `design().artboard()`: an artboard with this label already exists in the
40
+ * design (artboard names are placement labels — unique by contract). */
41
+ | 'E_DUPLICATE_ARTBOARD'
42
+ /** `usePlacements().select()`: the label names no artboard in the design
43
+ * (ADR-0088). Lists the valid placement labels. */
44
+ | 'E_UNKNOWN_PLACEMENT'
39
45
  /** `select()` named an option key/choice that doesn't exist on the product
40
46
  * (Buy-owned selection, ADR-0085 §2 / P2). */
41
47
  | 'E_UNKNOWN_OPTION'
@@ -49,6 +55,25 @@ export type EditorErrorCode =
49
55
  /** `design.color(name)`: no color role with this name — lists the design's
50
56
  * declared roles. */
51
57
  | 'E_COLOR_ROLE_NOT_FOUND'
58
+ /** `Editor.Preview loadingOverlay` got `false`/an unknown value. A mockup
59
+ * preview ALWAYS has a render-in-flight treatment (a server render takes
60
+ * real time, and the loader paints OVER the still-visible previous
61
+ * mockup) — keep the default, pass a variant/custom element, or declare
62
+ * `"host-owned"` with your own indicator. Silence-then-pop-in is a
63
+ * composition mistake, not a preference. */
64
+ | 'E_PREVIEW_NO_LOADER'
65
+ /** `updateElement(target, patch)`: a patch key doesn't apply to the target
66
+ * element's kind (e.g. `fontSize` on a shape), or a value is out of range
67
+ * (opacity outside 0..1, fontSize/width/height <= 0, non-finite number,
68
+ * wrong primitive type). The message names the element kind and lists the
69
+ * valid keys for it. Dev AND prod. */
70
+ | 'E_INVALID_PATCH'
71
+ /** `addElement(spec)`: there is no active artboard to add the element to.
72
+ * Create or select an artboard first (`<Editor.Root>` seeds one
73
+ * automatically; with a raw `EditorProvider` use `executeCreateArtboard`).
74
+ * Replaces the old `handleAddElement` window.alert — agents read throws,
75
+ * not dialogs. */
76
+ | 'E_NO_ACTIVE_ARTBOARD'
52
77
  /** `assertRenders`: the shop's asset-origin allowlist denied a design asset
53
78
  * (translated from the server's 403 — F4). */
54
79
  | 'E_ASSET_FORBIDDEN'
@@ -59,7 +84,10 @@ export type EditorErrorCode =
59
84
  | 'E_BINDING_INERT'
60
85
  /** `assertRenders`: the design has no named text layer to mutate and no
61
86
  * `mutate` override was given (F4). */
62
- | 'E_NO_MUTABLE_BINDING';
87
+ | 'E_NO_MUTABLE_BINDING'
88
+ /** `auditEditor()` called with no `<Editor.Root>` mounted — the imperative
89
+ * audit reads the most-recent mounted Root's registry (#10). */
90
+ | 'E_AUDIT_NO_ROOT';
63
91
  export interface EditorErrorData {
64
92
  code: EditorErrorCode;
65
93
  /** Slug under https://developers.snowcone.app/ for the violated contract. */
@@ -1,4 +1,4 @@
1
- import { G as n, I as t, P as a, S as s, T as i } from "./FontAnalyzer-CwIpgTGd.js";
1
+ import { G as n, I as t, P as a, S as s, T as i } from "./FontAnalyzer-EF3gLPr8.js";
2
2
  function r(e) {
3
3
  return e instanceof i;
4
4
  }
@@ -21,4 +21,4 @@ export {
21
21
  r as d,
22
22
  u as i
23
23
  };
24
- //# sourceMappingURL=guards-8rkFAMBs.js.map
24
+ //# sourceMappingURL=guards-DIX8aXWM.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"guards-8rkFAMBs.js","sources":["../src/types/guards.ts"],"sourcesContent":["/**\n * Type guards for EditorElement discrimination\n *\n * These guards use instanceof checks against the concrete element classes,\n * matching the pattern established in EditorContext.tsx. They accept\n * BaseElement | EditorElement | undefined | null for maximum flexibility\n * at call sites.\n */\n\nimport { BaseElement } from '../core/BaseElement.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\n\ntype Narrowable = BaseElement | TextElement | ImageElement | GroupElement | ShapeElement | PathElement | undefined | null;\n\n/**\n * Type guard: checks if an element is a TextElement (or any text-based transform subclass).\n *\n * TextElement is the base class for all text transforms (custom, circle, arch, wave, etc.),\n * so this returns true for any text-based element regardless of its specific transformType.\n */\nexport function isTextElement(element: Narrowable): element is TextElement {\n return element instanceof TextElement;\n}\n\n/**\n * Type guard: checks if an element is an ImageElement.\n */\nexport function isImageElement(element: Narrowable): element is ImageElement {\n return element instanceof ImageElement;\n}\n\n/**\n * Type guard: checks if an element is a GroupElement.\n */\nexport function isGroupElement(element: Narrowable): element is GroupElement {\n return element instanceof GroupElement;\n}\n\n/**\n * Type guard: checks if an element is a ShapeElement.\n */\nexport function isShapeElement(element: Narrowable): element is ShapeElement {\n return element instanceof ShapeElement;\n}\n\n/**\n * Type guard: checks if an element is a PathElement.\n */\nexport function isPathElement(element: Narrowable): element is PathElement {\n return element instanceof PathElement;\n}\n"],"names":["isTextElement","element","TextElement","isImageElement","ImageElement","isGroupElement","GroupElement","isShapeElement","ShapeElement","isPathElement","PathElement"],"mappings":";AAwBO,SAASA,EAAcC,GAA6C;AACzE,SAAOA,aAAmBC;AAC5B;AAKO,SAASC,EAAeF,GAA8C;AAC3E,SAAOA,aAAmBG;AAC5B;AAKO,SAASC,EAAeJ,GAA8C;AAC3E,SAAOA,aAAmBK;AAC5B;AAKO,SAASC,EAAeN,GAA8C;AAC3E,SAAOA,aAAmBO;AAC5B;AAKO,SAASC,EAAcR,GAA6C;AACzE,SAAOA,aAAmBS;AAC5B;"}
1
+ {"version":3,"file":"guards-DIX8aXWM.js","sources":["../src/types/guards.ts"],"sourcesContent":["/**\n * Type guards for EditorElement discrimination\n *\n * These guards use instanceof checks against the concrete element classes,\n * matching the pattern established in EditorContext.tsx. They accept\n * BaseElement | EditorElement | undefined | null for maximum flexibility\n * at call sites.\n */\n\nimport { BaseElement } from '../core/BaseElement.js';\nimport { TextElement } from '../core/TextElement.js';\nimport { ImageElement } from '../core/ImageElement.js';\nimport { GroupElement } from '../core/GroupElement.js';\nimport { ShapeElement } from '../core/ShapeElement.js';\nimport { PathElement } from '../core/PathElement.js';\n\ntype Narrowable = BaseElement | TextElement | ImageElement | GroupElement | ShapeElement | PathElement | undefined | null;\n\n/**\n * Type guard: checks if an element is a TextElement (or any text-based transform subclass).\n *\n * TextElement is the base class for all text transforms (custom, circle, arch, wave, etc.),\n * so this returns true for any text-based element regardless of its specific transformType.\n */\nexport function isTextElement(element: Narrowable): element is TextElement {\n return element instanceof TextElement;\n}\n\n/**\n * Type guard: checks if an element is an ImageElement.\n */\nexport function isImageElement(element: Narrowable): element is ImageElement {\n return element instanceof ImageElement;\n}\n\n/**\n * Type guard: checks if an element is a GroupElement.\n */\nexport function isGroupElement(element: Narrowable): element is GroupElement {\n return element instanceof GroupElement;\n}\n\n/**\n * Type guard: checks if an element is a ShapeElement.\n */\nexport function isShapeElement(element: Narrowable): element is ShapeElement {\n return element instanceof ShapeElement;\n}\n\n/**\n * Type guard: checks if an element is a PathElement.\n */\nexport function isPathElement(element: Narrowable): element is PathElement {\n return element instanceof PathElement;\n}\n"],"names":["isTextElement","element","TextElement","isImageElement","ImageElement","isGroupElement","GroupElement","isShapeElement","ShapeElement","isPathElement","PathElement"],"mappings":";AAwBO,SAASA,EAAcC,GAA6C;AACzE,SAAOA,aAAmBC;AAC5B;AAKO,SAASC,EAAeF,GAA8C;AAC3E,SAAOA,aAAmBG;AAC5B;AAKO,SAASC,EAAeJ,GAA8C;AAC3E,SAAOA,aAAmBK;AAC5B;AAKO,SAASC,EAAeN,GAA8C;AAC3E,SAAOA,aAAmBO;AAC5B;AAKO,SAASC,EAAcR,GAA6C;AACzE,SAAOA,aAAmBS;AAC5B;"}
@@ -0,0 +1,96 @@
1
+ import { LayerToken } from '../design/design-builder.js';
2
+ import { EditorElementKind } from '../core/elementGuards.js';
3
+ import { ElementStore } from '../core/ElementStore.js';
4
+ import { EditorElement } from '../contexts/EditorContext.js';
5
+ import { TextAlign } from '../types/index.js';
6
+ /**
7
+ * A serializable element patch for {@link UseCommandsReturn.updateElement}.
8
+ *
9
+ * Keys are validated against the TARGET element's kind at call time — a key
10
+ * that doesn't apply (e.g. `fontSize` on a shape) throws `E_INVALID_PATCH`
11
+ * naming the kind and listing its valid keys, dev AND prod.
12
+ *
13
+ * | keys | applies to |
14
+ * |---|---|
15
+ * | `x`, `y`, `rotation`, `opacity`, `name`, `visible`, `locked` | every kind |
16
+ * | `text`, `fontSize`, `color`, `fontFamily`, `bold`, `italic`, `textAlign` | text |
17
+ * | `fillColor`, `width`, `height` | shape |
18
+ * | `imageUrl`, `width`, `height` | image |
19
+ */
20
+ export interface ElementPatch {
21
+ /** Center x in artboard coordinates. Any kind. */
22
+ x?: number;
23
+ /** Center y in artboard coordinates. Any kind. */
24
+ y?: number;
25
+ /** Rotation in degrees. Any kind. */
26
+ rotation?: number;
27
+ /** 0..1. Any kind. Out of range throws `E_INVALID_PATCH`. */
28
+ opacity?: number;
29
+ /** Layer name (renaming a bound layer throws `E_BOUND_LAYER_MUTATION`). Any kind. */
30
+ name?: string;
31
+ /** Layer visibility. Any kind. */
32
+ visible?: boolean;
33
+ /** Layer lock. Any kind. */
34
+ locked?: boolean;
35
+ /** Text content. Text elements only. */
36
+ text?: string;
37
+ /** Font size (> 0; clamped to the editor's min/max). Text elements only. */
38
+ fontSize?: number;
39
+ /** Ink color (CSS color). Text elements only. */
40
+ color?: string;
41
+ /** Font family name. Text elements only. */
42
+ fontFamily?: string;
43
+ /** Bold. Text elements only. */
44
+ bold?: boolean;
45
+ /** Italic. Text elements only. */
46
+ italic?: boolean;
47
+ /** Text alignment. Text elements only. */
48
+ textAlign?: TextAlign;
49
+ /** Fill color (CSS color). Shape elements only. */
50
+ fillColor?: string;
51
+ /** Frame width (> 0). Shape and image elements only. */
52
+ width?: number;
53
+ /** Frame height (> 0). Shape and image elements only. */
54
+ height?: number;
55
+ /** Image source URL — swaps the image and reloads it. Image elements only.
56
+ * Combined with explicit `width`/`height` the frame is preserved;
57
+ * otherwise the frame height re-fits the loaded aspect ratio. */
58
+ imageUrl?: string;
59
+ }
60
+ /** Options for {@link UseCommandsReturn.updateElement}. */
61
+ export interface UpdateElementOptions {
62
+ /**
63
+ * Coalesce with the immediately-preceding coalesced `updateElement` to the
64
+ * SAME element: consecutive calls land as ONE history entry, so one
65
+ * `undo()` returns to the state before the run (finding #16 — host
66
+ * inspectors that commit per keystroke stop flooding history). Any other
67
+ * command in between, or an undo/redo, breaks the run.
68
+ */
69
+ coalesce?: boolean;
70
+ }
71
+ /** Patchable keys per element kind — the validation source of truth. */
72
+ export declare const PATCH_KEYS_BY_KIND: Record<EditorElementKind, readonly string[]>;
73
+ /**
74
+ * Resolve an `updateElement` target — an element id, a layer name, or a
75
+ * `design.layer()` token — to an element in the store. Unknown targets throw
76
+ * the existing `E_LAYER_NOT_FOUND` listing the valid ids and layer names.
77
+ * When several elements share a layer name, the first (render order) wins.
78
+ */
79
+ export declare function resolveElementTarget(elementStore: ElementStore, target: string | LayerToken): EditorElement;
80
+ /**
81
+ * Validate a patch against the element's kind. Throws `E_INVALID_PATCH`
82
+ * (dev AND prod) for: a key that doesn't apply to the kind (message names the
83
+ * kind and lists its valid keys), opacity outside 0..1, fontSize/width/height
84
+ * <= 0, non-finite numbers, or wrong primitive types.
85
+ */
86
+ export declare function validateElementPatch(el: EditorElement, patch: ElementPatch): EditorElementKind;
87
+ /**
88
+ * Apply a VALIDATED patch onto a clone (mutates `clone` in place). Uses the
89
+ * element's own normalizing setters where they exist (`setText`,
90
+ * `setFontSize` clamps, `setColor` keeps rich-text spans in sync).
91
+ * Image-source swaps need a post-command `loadImage` — signalled by the
92
+ * return value so `updateElement` can run the load path.
93
+ */
94
+ export declare function applyElementPatch(clone: EditorElement, patch: ElementPatch): {
95
+ needsImageLoad: boolean;
96
+ };
@@ -1,4 +1,6 @@
1
1
  import { useEditor } from '../contexts/EditorContext.js';
2
+ import { ElementPatch, UpdateElementOptions } from './elementPatch.js';
3
+ import { LayerToken } from '../design/design-builder.js';
2
4
  export interface UseCommandsReturn {
3
5
  undo: () => void;
4
6
  redo: () => void;
@@ -6,6 +8,24 @@ export interface UseCommandsReturn {
6
8
  canRedo: boolean;
7
9
  clearHistory: () => void;
8
10
  clearArtboardHistory: (artboardId: string) => void;
11
+ /**
12
+ * Declarative, validated, undoable element mutation — the agent write path.
13
+ * `target` is an element id, a layer name, or a `design.layer()` token
14
+ * (unknown targets throw `E_LAYER_NOT_FOUND` listing the valid names).
15
+ * The patch is validated against the element's kind and applied as ONE
16
+ * history entry; invalid keys/values throw `E_INVALID_PATCH` naming the
17
+ * kind and its valid keys — dev AND prod.
18
+ *
19
+ * `{ coalesce: true }`: consecutive coalesced calls to the SAME element
20
+ * fold into one history entry (one `undo()` returns to the pre-run state).
21
+ */
22
+ updateElement: (target: string | LayerToken, patch: ElementPatch, opts?: UpdateElementOptions) => void;
23
+ /**
24
+ * Create an element and get `{ id, name }` back; the element arrives
25
+ * selected. Throws `E_NO_ACTIVE_ARTBOARD` when there is no artboard.
26
+ * (Also available on `useEditor()`.)
27
+ */
28
+ addElement: ReturnType<typeof useEditor>['addElement'];
9
29
  executeElementUpdate: ReturnType<typeof useEditor>['executeElementUpdate'];
10
30
  executeAddElement: ReturnType<typeof useEditor>['executeAddElement'];
11
31
  executeRemoveElement: ReturnType<typeof useEditor>['executeRemoveElement'];
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import { e as u } from "./UnifiedFontService-CC3CSmH5.js";
2
- import { C as l, c as x, a as I, b as v, u as A, d as T, f as g, g as B } from "./UnifiedFontService-CC3CSmH5.js";
3
- import { E as _, S as y, S as L, u as O, a as M } from "./SnowconeCanvas-D1sLcIja.js";
4
- import { u as d, a as m } from "./editorErrors-B2mb1sVN.js";
5
- import { T as z, r as w, u as F, a as D, b as K, c as N, d as V, e as b, f as h, w as U } from "./template-fields-CQ6n2P4V.js";
6
- import { A as Z, C as G, E as H, M as j, P as k, r as q, v as J } from "./validation-C9Fe9ahK.js";
7
- import { C as W, D as X, d as $, s as ee } from "./design-builder-2VUjfmdt.js";
1
+ import { e as u } from "./UnifiedFontService-CHVYDBDW.js";
2
+ import { C as l, c as x, a as I, b as v, u as A, d as T, f as g, g as B } from "./UnifiedFontService-CHVYDBDW.js";
3
+ import { E as _, S as y, S as L, u as O, a as M } from "./SnowconeCanvas-DuWALOAt.js";
4
+ import { u as d, a as m } from "./editorErrors-BhrZ_nwj.js";
5
+ import { T as z, r as w, u as F, a as D, b as K, c as N, d as V, e as b, f as h, w as U } from "./template-fields-BXl29sgh.js";
6
+ import { A as Z, C as G, E as H, M as j, P as k, r as q, v as J } from "./validation-DGXAQmUC.js";
7
+ import { C as W, D as X, d as $, s as ee } from "./design-builder-cZY958Rw.js";
8
8
  import { c as se, e as te } from "./compose-DtQL_oit.js";
9
- import { d as oe, m as ie, s as ne, v as ue } from "./CanvasStateV1-DmZ1Qvvn.js";
9
+ import { d as oe, m as ie, s as ne, v as ue } from "./CanvasStateV1-BTbCD_xC.js";
10
10
  function C() {
11
11
  const { isCanvasReady: e } = d();
12
12
  return e;
@@ -1,8 +1,8 @@
1
- import { A as w, a as b, C as I, I as R, R as W, S as A, T as E } from "./CanvasRenderer-6_HhR4-q.js";
2
- import { r as p } from "./ExportManager-DoU4VK6h.js";
3
- import { D as O, E as F, I as L, W as X, a as z, b as K, c as Y, d as B, e as _, f as J, h as N, i as V, j as U, k as j, l as q, m as Q, n as Z, o as $, p as m, q as G, s as x, t as D, u as rr, v as or, w as sr, x as ir, y as er, z as ar, A as nr, B as tr, C as hr } from "./ExportManager-DoU4VK6h.js";
4
- import { D as cr, E as fr, H as pr, J as gr, K as lr, L as ur, M as Tr, N as kr, O as Mr, Q as yr, W as Cr, U as vr, V as Sr, X as Pr, c as wr, Y as br, Z as Ir, _ as Rr, $ as Wr, a0 as Ar } from "./FontAnalyzer-CwIpgTGd.js";
5
- import { A as Hr, e as Or, C as Fr, S as Lr } from "./CanvasStateV1-DmZ1Qvvn.js";
1
+ import { A as w, a as b, C as I, I as R, R as W, S as A, T as E } from "./CanvasRenderer-yszzrDfo.js";
2
+ import { r as p } from "./ExportManager-BTcyj4cf.js";
3
+ import { D as O, E as F, I as L, W as X, a as z, b as K, c as Y, d as B, e as _, f as J, h as N, i as V, j, k as q, l as Q, m as U, n as Z, o as $, p as m, q as G, s as x, t as D, u as rr, v as or, w as sr, x as ir, y as er, z as ar, A as nr, B as tr, C as hr } from "./ExportManager-BTcyj4cf.js";
4
+ import { D as cr, E as fr, H as pr, J as gr, K as lr, L as ur, M as Tr, N as kr, O as Mr, Q as yr, W as Cr, V as vr, X as Sr, Y as Pr, c as wr, Z as br, _ as Ir, $ as Rr, a0 as Wr, a1 as Ar } from "./FontAnalyzer-EF3gLPr8.js";
5
+ import { A as Hr, e as Or, C as Fr, S as Lr } from "./CanvasStateV1-BTbCD_xC.js";
6
6
  function y(r, o) {
7
7
  return !r.needsCropPixelConversion || r.cropWidth === void 0 ? r : {
8
8
  ...r,
@@ -198,10 +198,10 @@ export {
198
198
  N as createCirclePath,
199
199
  V as createImagePath,
200
200
  wr as createLogger,
201
- U as createRectPath,
202
- j as createTextPath,
203
- q as getFontMetrics,
204
- Q as getSharedWorkerExportManager,
201
+ j as createRectPath,
202
+ q as createTextPath,
203
+ Q as getFontMetrics,
204
+ U as getSharedWorkerExportManager,
205
205
  br as hitTestCircle,
206
206
  Ir as hitTestRect,
207
207
  Z as invalidateMaskCache,