@snowcone-app/canvas 0.16.0 → 0.17.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 (70) hide show
  1. package/dist/{CanvasStateV1-BQD8fCBU.js → CanvasStateV1-C6i6vU6p.js} +63 -63
  2. package/dist/{CanvasStateV1-BQD8fCBU.js.map → CanvasStateV1-C6i6vU6p.js.map} +1 -1
  3. package/dist/EditorCanvasImpl-DkgE5-C2.js +68 -0
  4. package/dist/EditorCanvasImpl-DkgE5-C2.js.map +1 -0
  5. package/dist/EditorContext-CyanYzo2.js +1131 -0
  6. package/dist/EditorContext-CyanYzo2.js.map +1 -0
  7. package/dist/{ImportManager-eotl7r5d.js → ElementFactory-C05JJkRp.js} +1510 -5121
  8. package/dist/ElementFactory-C05JJkRp.js.map +1 -0
  9. package/dist/{HybridHistoryManager-NL3zyEl4.js → HybridHistoryManager-Bht98XRv.js} +98 -98
  10. package/dist/{HybridHistoryManager-NL3zyEl4.js.map → HybridHistoryManager-Bht98XRv.js.map} +1 -1
  11. package/dist/ImportManager-kRYfIX-D.js +3617 -0
  12. package/dist/ImportManager-kRYfIX-D.js.map +1 -0
  13. package/dist/SnowconeCanvas-C3eZ9PP8.js +1047 -0
  14. package/dist/SnowconeCanvas-C3eZ9PP8.js.map +1 -0
  15. package/dist/ThemeContext-Rjz25x9X.js +75 -0
  16. package/dist/ThemeContext-Rjz25x9X.js.map +1 -0
  17. package/dist/UnifiedFontService-BAtqqkU4.js +1478 -0
  18. package/dist/UnifiedFontService-BAtqqkU4.js.map +1 -0
  19. package/dist/advanced.mjs +210 -207
  20. package/dist/advanced.mjs.map +1 -1
  21. package/dist/api/embed.d.ts +8 -4
  22. package/dist/api/testing.d.ts +1 -0
  23. package/dist/components/editor/EditorBuy.d.ts +49 -0
  24. package/dist/components/editor/EditorCanvas.d.ts +30 -0
  25. package/dist/components/editor/EditorCanvasImpl.d.ts +33 -0
  26. package/dist/components/editor/EditorPreview.d.ts +39 -0
  27. package/dist/components/editor/EditorRoot.d.ts +86 -0
  28. package/dist/components/editor/EditorTextField.d.ts +22 -0
  29. package/dist/components/editor/RootInternals.d.ts +77 -0
  30. package/dist/components/editor/designStateStore.d.ts +45 -0
  31. package/dist/components/editor/index.d.ts +23 -0
  32. package/dist/components/embed-realtime/RealtimeCanvas.d.ts +1 -1
  33. package/dist/components/embed-realtime/RealtimeEmbed.d.ts +5 -78
  34. package/dist/components/embed-realtime/RealtimeMockup.d.ts +5 -34
  35. package/dist/components/embed-realtime/context.d.ts +12 -2
  36. package/dist/components/embed-realtime/validateEmbed.d.ts +17 -3
  37. package/dist/design/design-builder.d.ts +81 -6
  38. package/dist/editorError-DMENTZ-3.js +19 -0
  39. package/dist/editorError-DMENTZ-3.js.map +1 -0
  40. package/dist/editorErrors-DbIEtCTt.js +29 -0
  41. package/dist/editorErrors-DbIEtCTt.js.map +1 -0
  42. package/dist/embed-Bdj4PKUA.js +737 -0
  43. package/dist/embed-Bdj4PKUA.js.map +1 -0
  44. package/dist/embed.mjs +38 -230
  45. package/dist/embed.mjs.map +1 -1
  46. package/dist/errors/editorError.d.ts +57 -0
  47. package/dist/iconify-D6eVIEy4.js +1089 -0
  48. package/dist/iconify-D6eVIEy4.js.map +1 -0
  49. package/dist/index.mjs +48 -46
  50. package/dist/index.mjs.map +1 -1
  51. package/dist/internals.mjs +105 -104
  52. package/dist/internals.mjs.map +1 -1
  53. package/dist/template-fields-GOM4MNfq.js +643 -0
  54. package/dist/template-fields-GOM4MNfq.js.map +1 -0
  55. package/dist/testing/editorErrors.d.ts +30 -0
  56. package/dist/testing.mjs +28 -23
  57. package/dist/testing.mjs.map +1 -1
  58. package/dist/{usePieceGuideBundle-Cyl695jv.js → usePieceGuideBundle-CGERAQJl.js} +2 -2
  59. package/dist/{usePieceGuideBundle-Cyl695jv.js.map → usePieceGuideBundle-CGERAQJl.js.map} +1 -1
  60. package/dist/validation-DEd6EOCP.js +19947 -0
  61. package/dist/validation-DEd6EOCP.js.map +1 -0
  62. package/dist/workers/export-worker.bundle.string.d.ts +1 -1
  63. package/package.json +9 -4
  64. package/dist/ImportManager-eotl7r5d.js.map +0 -1
  65. package/dist/ThemeContext-D9AaUw9v.js +0 -1200
  66. package/dist/ThemeContext-D9AaUw9v.js.map +0 -1
  67. package/dist/template-fields-PcSPApl5.js +0 -1632
  68. package/dist/template-fields-PcSPApl5.js.map +0 -1
  69. package/dist/validation-BpEod0Rn.js +0 -22953
  70. package/dist/validation-BpEod0Rn.js.map +0 -1
@@ -0,0 +1,643 @@
1
+ import { useCallback as C, useEffect as et, useMemo as $, useRef as A, useState as _ } from "react";
2
+ import { u as G, c as T, b as H } from "./EditorContext-CyanYzo2.js";
3
+ import { c as nt, y as z, T as B, I as J, z as ot } from "./HybridHistoryManager-Bht98XRv.js";
4
+ import { U as rt } from "./UnifiedFontService-BAtqqkU4.js";
5
+ import { E as P } from "./editorError-DMENTZ-3.js";
6
+ import { a as it, o as E, b as h, n as at, l as b, u as L, c as st } from "./CanvasStateV1-C6i6vU6p.js";
7
+ const X = nt("useCommands");
8
+ function Mt() {
9
+ const t = G(), {
10
+ undo: e,
11
+ redo: n,
12
+ canUndo: r,
13
+ canRedo: i,
14
+ executeElementUpdate: o,
15
+ executeAddElement: a,
16
+ executeRemoveElement: s,
17
+ executeReorderElement: l,
18
+ executeCommandBatch: c,
19
+ executeCreateArtboard: m,
20
+ executeDeleteArtboard: u,
21
+ executeUpdateArtboard: d
22
+ } = t, g = C(() => {
23
+ X.warn("[useCommands] clearHistory is not yet implemented in EditorContext");
24
+ }, []), N = C((k) => {
25
+ X.warn("[useCommands] clearArtboardHistory is not yet implemented in EditorContext");
26
+ }, []);
27
+ return {
28
+ // Undo/Redo
29
+ undo: e,
30
+ redo: n,
31
+ canUndo: r,
32
+ canRedo: i,
33
+ // History management
34
+ clearHistory: g,
35
+ clearArtboardHistory: N,
36
+ // Command execution
37
+ executeElementUpdate: o,
38
+ executeAddElement: a,
39
+ executeRemoveElement: s,
40
+ executeReorderElement: l,
41
+ executeCreateArtboard: m,
42
+ executeDeleteArtboard: u,
43
+ executeUpdateArtboard: d,
44
+ // Batch execution
45
+ executeCommandBatch: c
46
+ };
47
+ }
48
+ function Ut() {
49
+ const { selectedElement: t } = G();
50
+ return t ?? null;
51
+ }
52
+ const ct = 3e3, K = {
53
+ text: "useTextBinding",
54
+ image: "useImageBinding",
55
+ font: "useFontBinding"
56
+ }, lt = {
57
+ text: "setText",
58
+ image: "setImageUrl",
59
+ font: "setFontFamily"
60
+ }, ft = {
61
+ text: "text",
62
+ image: "image",
63
+ font: "text"
64
+ }, v = /* @__PURE__ */ new Set();
65
+ function V(t) {
66
+ return t instanceof B ? "text" : t instanceof J ? "image" : "other";
67
+ }
68
+ function ht(t, e, n) {
69
+ const r = `[${K[t]}]`, i = `the binding is dead (isConnected: false, ${lt[t]} is a no-op)`, o = ft[t], a = n.getAllByName(e);
70
+ if (a.length > 0) {
71
+ const c = [...new Set(a.map(V))], m = o === "text" ? "image" : "text", u = c.length === 1 && c[0] === m ? ` Bind it with ${K[m]}("${e}") instead.` : "";
72
+ return `${r} the layer named "${e}" is ${c.join("/")}, not ${o} — ${i}.${u}`;
73
+ }
74
+ const s = n.getAll().filter((c) => c.name).map((c) => `"${c.name}" (${V(c)})`), l = s.length ? `Named layers on this canvas: ${s.join(", ")}. Check the name for a typo.` : `No element on this canvas has a name — name one via design().${o}(…, { name: '${e}' }) or the element's \`name\` property.`;
75
+ return `${r} no ${o} layer named "${e}" exists — ${i}. ${l}`;
76
+ }
77
+ function M(t, e, n, r) {
78
+ et(() => {
79
+ var a;
80
+ if (r || typeof z > "u" || ((a = z.env) == null ? void 0 : a.NODE_ENV) === "production") return;
81
+ const i = `${t}:${e}`;
82
+ if (v.has(i)) return;
83
+ const o = setTimeout(() => {
84
+ v.has(i) || (v.add(i), console.warn(ht(t, e, n)));
85
+ }, ct);
86
+ return () => clearTimeout(o);
87
+ }, [t, e, n, r]);
88
+ }
89
+ const dt = () => {
90
+ }, mt = [];
91
+ function Wt(t) {
92
+ const { elementStore: e } = T(), { executeElementUpdate: n } = H(), r = $(() => e.getAllByName(t).filter((a) => a instanceof B), [e, t]), i = C(
93
+ (o) => {
94
+ for (const a of r) {
95
+ const s = a.clone();
96
+ s.setText(o), n(a, s);
97
+ }
98
+ },
99
+ [r, n]
100
+ );
101
+ return M("text", t, e, r.length > 0), r.length === 0 ? { text: "", setText: dt, element: null, elements: mt, isConnected: !1 } : {
102
+ text: r[0].getText(),
103
+ setText: i,
104
+ element: r[0],
105
+ elements: r,
106
+ isConnected: !0
107
+ };
108
+ }
109
+ const ut = () => {
110
+ }, gt = [];
111
+ function pt(t, e, n) {
112
+ const r = t / e;
113
+ if (n >= r) {
114
+ const i = e, o = i * n, a = t / o;
115
+ return {
116
+ width: o,
117
+ height: i,
118
+ cropX: (1 - a) / 2,
119
+ cropY: 0,
120
+ cropWidth: a,
121
+ cropHeight: 1
122
+ };
123
+ } else {
124
+ const i = t, o = i / n, a = e / o;
125
+ return {
126
+ width: i,
127
+ height: o,
128
+ cropX: 0,
129
+ cropY: (1 - a) / 2,
130
+ cropWidth: 1,
131
+ cropHeight: a
132
+ };
133
+ }
134
+ }
135
+ function It(t, e) {
136
+ const n = (e == null ? void 0 : e.fit) ?? "cover", { elementStore: r, setElements: i } = T(), { executeElementUpdate: o } = H(), a = $(() => r.getAllByName(t).filter((g) => g instanceof J), [r, t]), s = A(/* @__PURE__ */ new Map());
137
+ for (const d of a)
138
+ if (!s.current.has(d.id)) {
139
+ const g = d.transformData;
140
+ s.current.set(d.id, {
141
+ width: g.width * g.cropWidth,
142
+ height: g.height * g.cropHeight
143
+ });
144
+ }
145
+ const l = A(a);
146
+ l.current = a;
147
+ const c = A(o);
148
+ c.current = o;
149
+ const m = A(i);
150
+ m.current = i;
151
+ const u = C(
152
+ (d) => {
153
+ const g = l.current, N = c.current;
154
+ for (const k of g) {
155
+ const W = s.current.get(k.id);
156
+ if (!W) continue;
157
+ const { width: I, height: Y } = W, p = k.clone();
158
+ p.imageLoaded = !1, p.imageElement = null, p.isCropping = !1, p.imageUrl = d, n === "cover" ? (p.preserveDimensions = !0, p.onLoadCallback = (f) => {
159
+ const D = f.imageAspectRatio || 1, y = pt(I, Y, D);
160
+ f.transformData.width = y.width, f.transformData.height = y.height, f.transformData.cropX = y.cropX, f.transformData.cropY = y.cropY, f.transformData.cropWidth = y.cropWidth, f.transformData.cropHeight = y.cropHeight, N(k, f);
161
+ }) : (p.preserveDimensions = !1, p.onLoadCallback = (f) => {
162
+ const D = f.transformData.width, y = f.transformData.height, S = Math.min(I / D, Y / y, 1);
163
+ S < 1 && (f.transformData.width = D * S, f.transformData.height = y * S), f.transformData.cropX = 0, f.transformData.cropY = 0, f.transformData.cropWidth = 1, f.transformData.cropHeight = 1, N(k, f);
164
+ }), p.loadImage(d);
165
+ }
166
+ },
167
+ [n]
168
+ // Stable deps only — imageElements/executeElementUpdate/setElements accessed via refs
169
+ );
170
+ return M("image", t, r, a.length > 0), a.length === 0 ? { imageUrl: "", setImageUrl: ut, element: null, elements: gt, isConnected: !1 } : {
171
+ imageUrl: a[0].imageUrl,
172
+ setImageUrl: u,
173
+ element: a[0],
174
+ elements: a,
175
+ isConnected: !0
176
+ };
177
+ }
178
+ const yt = [];
179
+ function R(t) {
180
+ let e = t.trim().toUpperCase();
181
+ return e.length === 4 && e.startsWith("#") && (e = "#" + e[1] + e[1] + e[2] + e[2] + e[3] + e[3]), e;
182
+ }
183
+ function x(t, e) {
184
+ return typeof t == "string" && R(t) === e;
185
+ }
186
+ function q(t, e) {
187
+ var r, i, o;
188
+ const n = t;
189
+ return x(n.color, e) || x((r = n.transformData) == null ? void 0 : r.fillColor, e) || x((i = n.transformData) == null ? void 0 : i.strokeColor, e) || ((o = n.stroke) == null ? void 0 : o.enabled) === !0 && x(n.stroke.color, e);
190
+ }
191
+ function bt(t, e, n) {
192
+ var a, s, l;
193
+ if (!q(t, e)) return null;
194
+ const r = t.clone(), i = t, o = r;
195
+ return x(i.color, e) && (typeof o.setColor == "function" ? o.setColor(n) : o.color = n), x((a = i.transformData) == null ? void 0 : a.fillColor, e) && (o.transformData = { ...o.transformData, fillColor: n }), x((s = i.transformData) == null ? void 0 : s.strokeColor, e) && (o.transformData = { ...o.transformData, strokeColor: n }), ((l = i.stroke) == null ? void 0 : l.enabled) === !0 && x(i.stroke.color, e) && (o.stroke = { ...o.stroke, color: n }), r;
196
+ }
197
+ function Yt(t) {
198
+ const { elementStore: e } = T(), { executeElementUpdate: n } = H(), [r, i] = _(() => R(t)), [o, a] = _(t);
199
+ t !== o && (a(t), i(R(t)));
200
+ const s = $(
201
+ () => e.getAll().filter((c) => q(c, r)),
202
+ [e, r]
203
+ ), l = C(
204
+ (c) => {
205
+ const m = R(c);
206
+ if (m !== r) {
207
+ for (const u of e.getAll()) {
208
+ const d = bt(u, r, c);
209
+ d && n(u, d);
210
+ }
211
+ i(m);
212
+ }
213
+ },
214
+ [e, r, n]
215
+ );
216
+ return s.length === 0 ? { color: r, setColor: l, elements: yt, isConnected: !1 } : { color: r, setColor: l, elements: s, isConnected: !0 };
217
+ }
218
+ const xt = () => {
219
+ }, wt = [];
220
+ function _t(t) {
221
+ const { elementStore: e } = T(), { executeElementUpdate: n } = H(), r = $(() => e.getAllByName(t).filter((a) => a instanceof B), [e, t]), i = C(
222
+ (o) => {
223
+ rt.loadGoogleFontByName(o);
224
+ for (const a of r) {
225
+ if (a.fontFamily === o) continue;
226
+ ot.clearCache(a.fontFamily);
227
+ const s = a.clone();
228
+ s.fontFamily = o, n(a, s);
229
+ }
230
+ },
231
+ [r, n]
232
+ );
233
+ return M("font", t, e, r.length > 0), r.length === 0 ? { fontFamily: "", setFontFamily: xt, element: null, elements: wt, isConnected: !1 } : {
234
+ fontFamily: r[0].fontFamily,
235
+ setFontFamily: i,
236
+ element: r[0],
237
+ elements: r,
238
+ isConnected: !0
239
+ };
240
+ }
241
+ function zt(t) {
242
+ const { elementStore: e } = T();
243
+ return t ? e.getByName(t) ?? null : null;
244
+ }
245
+ const Ct = 1;
246
+ function w(t) {
247
+ return typeof t == "number" && Number.isFinite(t) ? Math.round(t * 100) / 100 : t;
248
+ }
249
+ function Q(t) {
250
+ return {
251
+ ...t,
252
+ ...t.x !== void 0 && { x: w(t.x) },
253
+ ...t.y !== void 0 && { y: w(t.y) },
254
+ ...t.width !== void 0 && { width: w(t.width) },
255
+ ...t.height !== void 0 && { height: w(t.height) },
256
+ ...t.rotation !== void 0 && { rotation: w(t.rotation) }
257
+ };
258
+ }
259
+ function kt(t) {
260
+ var r;
261
+ const e = (r = t.artboards) != null && r.length ? t.artboards : [{ name: "Front", width: 800, height: 800 }], n = e.map(() => []);
262
+ for (const i of t.elements || []) {
263
+ const o = i == null ? void 0 : i.artboard, a = typeof o == "string" ? e.findIndex((s) => (s.name || "Front") === o) : -1;
264
+ n[a >= 0 ? a : 0].push(Et(i));
265
+ }
266
+ return {
267
+ schemaVersion: Ct,
268
+ artboards: e.map((i, o) => ({
269
+ id: `artboard-${o + 1}`,
270
+ name: i.name || "Front",
271
+ x: 0,
272
+ y: 0,
273
+ width: w(i.width || 800),
274
+ height: w(i.height || 800),
275
+ backgroundColor: i.backgroundColor || "transparent",
276
+ // Pass the artboard's flag through — the server worker only paints the
277
+ // background when this is true. Hardcoding `false` here silently dropped
278
+ // explicitly-set artboard backgrounds from every realtime mockup while
279
+ // the editor kept showing them (WYSIWYG drift).
280
+ exportBackground: i.exportBackground ?? !1,
281
+ elements: n[o],
282
+ distressTexture: i.distressTexture,
283
+ imageMask: i.imageMask
284
+ }))
285
+ };
286
+ }
287
+ function Et(t) {
288
+ const e = t.type || t.transformType;
289
+ if (e === "image")
290
+ return Tt(t);
291
+ const { artboard: n, ...r } = t;
292
+ return Q({
293
+ ...r,
294
+ type: e
295
+ });
296
+ }
297
+ function Tt(t) {
298
+ var c;
299
+ const e = t.transformData || {}, n = t.masks && t.masks.length > 0, r = e.width || 0, i = e.height || 0, o = n ? r : r * (e.cropWidth ?? 1), a = n ? i : i * (e.cropHeight ?? 1), s = {
300
+ id: t.id,
301
+ type: "image",
302
+ x: t.x || 0,
303
+ y: t.y || 0,
304
+ width: o,
305
+ height: a,
306
+ rotation: t.rotation || 0,
307
+ imageUrl: t.imageUrl,
308
+ imageAspectRatio: t.imageAspectRatio
309
+ };
310
+ return !n && (e.cropX !== 0 || e.cropY !== 0 || e.cropWidth !== 1 || e.cropHeight !== 1) && (s.cropX = e.cropX, s.cropY = e.cropY, s.cropWidth = e.cropWidth, s.cropHeight = e.cropHeight, s.needsCropPixelConversion = !0), e.flipHorizontal && (s.flipHorizontal = e.flipHorizontal), e.flipVertical && (s.flipVertical = e.flipVertical), e.borderRadius && (s.borderRadius = e.borderRadius), t.opacity !== void 0 && (s.opacity = t.opacity), t.distressEffect && (s.distressEffect = t.distressEffect), ((c = t.masks) == null ? void 0 : c.length) > 0 && (s.masks = t.masks), t.blendMode && (s.blendMode = t.blendMode), t.knockoutParts && (s.knockoutParts = t.knockoutParts), t.stroke && (s.stroke = t.stroke), Q(s);
311
+ }
312
+ const j = "center", Z = Symbol.for("snowcone.canvas.layerToken");
313
+ function Pt(t) {
314
+ return typeof t == "object" && t !== null && t[Z] === !0 && typeof t.name == "string" && (t.kind === "text" || t.kind === "image");
315
+ }
316
+ function Nt(t, e) {
317
+ return Object.freeze({ kind: t, name: e, [Z]: !0 });
318
+ }
319
+ function O(t) {
320
+ const e = t.transformType;
321
+ return e === "image" ? "image" : e === "shape" || e === "group" || e === "path" ? null : "text";
322
+ }
323
+ function Dt(t) {
324
+ return t === "top-left" || t === "left" || t === "bottom-left" ? "left" : t === "top-right" || t === "right" || t === "bottom-right" ? "right" : "center";
325
+ }
326
+ function At(t) {
327
+ return t === "top-left" || t === "top" || t === "top-right" ? "top" : t === "bottom-left" || t === "bottom" || t === "bottom-right" ? "bottom" : "middle";
328
+ }
329
+ function F(t, e, n, r, i, o) {
330
+ const a = Dt(t), s = At(t), l = a === "left" ? e / 2 + o : a === "right" ? r - e / 2 - o : r / 2, c = s === "top" ? n / 2 + o : s === "bottom" ? i - n / 2 - o : i / 2;
331
+ return { x: l, y: c };
332
+ }
333
+ function Rt(t, e, n) {
334
+ const r = e / n;
335
+ if (t >= r) {
336
+ const a = n * t, s = e / a;
337
+ return {
338
+ width: a,
339
+ height: n,
340
+ cropX: (1 - s) / 2,
341
+ cropY: 0,
342
+ cropWidth: s,
343
+ cropHeight: 1
344
+ };
345
+ }
346
+ const i = e / t, o = n / i;
347
+ return {
348
+ width: e,
349
+ height: i,
350
+ cropX: 0,
351
+ cropY: (1 - o) / 2,
352
+ cropWidth: 1,
353
+ cropHeight: o
354
+ };
355
+ }
356
+ class U {
357
+ constructor(e) {
358
+ if (this.els = [], this.idCounter = 0, !(e.width > 0) || !(e.height > 0))
359
+ throw new Error("design(): artboard width and height must be positive numbers");
360
+ this.artboard = {
361
+ name: e.name || "Front",
362
+ width: e.width,
363
+ height: e.height,
364
+ backgroundColor: e.backgroundColor
365
+ };
366
+ }
367
+ /**
368
+ * Seed a builder from a previously saved canvas state — the editor shape
369
+ * `<SnowconeCanvas onChange>` emits (and `toJSON()` produces).
370
+ *
371
+ * This is how a saved editable template re-enters the turnkey embed path:
372
+ * load the template's state JSON, lift it back into a `DesignBuilder`, and
373
+ * hand it to `<RealtimeEmbed design={…}>`. The active artboard becomes the
374
+ * builder's artboard; elements tagged for other artboards are skipped
375
+ * (untagged elements are assumed to belong to the active one).
376
+ */
377
+ static fromState(e) {
378
+ const n = e.artboards.find((i) => i.name === e.activeArtboard) ?? e.artboards[0];
379
+ if (!n)
380
+ throw new Error("DesignBuilder.fromState(): state has no artboards");
381
+ const r = new U({
382
+ name: n.name,
383
+ width: n.width,
384
+ height: n.height,
385
+ backgroundColor: n.backgroundColor
386
+ });
387
+ for (const i of e.elements)
388
+ i.artboard && i.artboard !== n.name || r.els.push({ ...i });
389
+ return r;
390
+ }
391
+ nextId(e) {
392
+ return `${e}-${++this.idCounter}`;
393
+ }
394
+ background(e, n = {}) {
395
+ const { width: r, height: i } = this.artboard;
396
+ let o;
397
+ if (n.aspectRatio && n.aspectRatio > 0) {
398
+ const s = Rt(n.aspectRatio, r, i);
399
+ o = {
400
+ type: "image",
401
+ width: s.width,
402
+ height: s.height,
403
+ cropX: s.cropX,
404
+ cropY: s.cropY,
405
+ cropWidth: s.cropWidth,
406
+ cropHeight: s.cropHeight,
407
+ flipHorizontal: !1,
408
+ flipVertical: !1,
409
+ borderRadius: 0
410
+ };
411
+ } else
412
+ o = {
413
+ type: "image",
414
+ width: r,
415
+ height: i,
416
+ cropX: 0,
417
+ cropY: 0,
418
+ cropWidth: 1,
419
+ cropHeight: 1,
420
+ flipHorizontal: !1,
421
+ flipVertical: !1,
422
+ borderRadius: 0
423
+ };
424
+ const a = {
425
+ id: this.nextId("bg"),
426
+ transformType: "image",
427
+ x: r / 2,
428
+ y: i / 2,
429
+ rotation: 0,
430
+ opacity: n.opacity ?? 1,
431
+ imageUrl: e,
432
+ imageAspectRatio: n.aspectRatio,
433
+ transformData: o,
434
+ name: n.name ?? "Background"
435
+ };
436
+ return this.els.unshift(a), this;
437
+ }
438
+ image(e, n = {}) {
439
+ const { width: r, height: i } = this.artboard, o = n.width ?? Math.round(r / 3), a = n.height ?? (n.aspectRatio ? Math.round(o / n.aspectRatio) : o), { x: s, y: l } = F(n.anchor ?? j, o, a, r, i, n.padding ?? 0), c = {
440
+ id: this.nextId("img"),
441
+ transformType: "image",
442
+ x: s,
443
+ y: l,
444
+ rotation: n.rotation ?? 0,
445
+ opacity: n.opacity ?? 1,
446
+ imageUrl: e,
447
+ imageAspectRatio: n.aspectRatio,
448
+ transformData: {
449
+ type: "image",
450
+ width: o,
451
+ height: a,
452
+ cropX: 0,
453
+ cropY: 0,
454
+ cropWidth: 1,
455
+ cropHeight: 1,
456
+ flipHorizontal: !1,
457
+ flipVertical: !1,
458
+ borderRadius: 0
459
+ },
460
+ ...n.name ? { name: n.name } : {}
461
+ };
462
+ return this.els.push(c), this;
463
+ }
464
+ text(e, n = {}) {
465
+ const { width: r, height: i } = this.artboard, o = n.fontSize ?? Math.round(this.artboard.height / 12), { x: a, y: s } = F(n.anchor ?? "top", 0, o, r, i, n.padding ?? Math.round(i / 20)), l = {
466
+ id: this.nextId("text"),
467
+ transformType: "custom",
468
+ x: a,
469
+ y: s,
470
+ rotation: n.rotation ?? 0,
471
+ text: e,
472
+ fontSize: o,
473
+ fontFamily: n.fontFamily ?? "Anton",
474
+ color: n.color ?? "#ffffff",
475
+ textAlign: n.textAlign ?? "center",
476
+ bold: n.bold ?? !1,
477
+ italic: n.italic ?? !1,
478
+ transformData: { type: "custom" },
479
+ ...n.name ? { name: n.name } : {}
480
+ };
481
+ return this.els.push(l), this;
482
+ }
483
+ /**
484
+ * Mint a {@link LayerToken} for a named layer — the only currency
485
+ * `Editor.TextField` accepts (ADR-0085 §1). Compile time: `name` is
486
+ * constrained to this design's declared layer names, kind inferred from
487
+ * which per-kind union it falls in. Runtime: validated EAGERLY against the
488
+ * built elements (nearest the mistake), so CMS/JSON-loaded designs get the
489
+ * same protection with `string` typing.
490
+ *
491
+ * @throws EditorError `E_LAYER_NOT_FOUND` — no layer with this name; lists
492
+ * the valid names per kind.
493
+ * @throws EditorError `E_LAYER_WRONG_KIND` — the name matches a layer that
494
+ * is not bindable (shape/group/path).
495
+ * @experimental ADR-0085; subject to change until the P4 gate.
496
+ */
497
+ layer(e) {
498
+ const n = this.els.find((i) => i.name === e);
499
+ if (!n) {
500
+ const i = this.layerNamesOfKind("text"), o = this.layerNamesOfKind("image");
501
+ throw new P(
502
+ "E_LAYER_NOT_FOUND",
503
+ `no layer "${e}" in this design. Text layers: ${JSON.stringify(i)}; image layers: ${JSON.stringify(o)}. Fix the name, or add the layer first — e.g. design(…).text('…', { name: '${e}' }).`,
504
+ { layerName: e, validNames: [...i, ...o], textNames: i, imageNames: o, docSlug: "embed-mode" }
505
+ );
506
+ }
507
+ const r = O(n);
508
+ if (!r)
509
+ throw new P(
510
+ "E_LAYER_WRONG_KIND",
511
+ `layer "${e}" is a ${n.transformType} element — only text and image layers are bindable. Bindable layers: ${JSON.stringify([...this.layerNamesOfKind("text"), ...this.layerNamesOfKind("image")])}.`,
512
+ { layerName: e, actualType: n.transformType, docSlug: "embed-mode" }
513
+ );
514
+ return Nt(r, e);
515
+ }
516
+ /** Names of bindable layers of one kind, in stack order. @internal */
517
+ layerNamesOfKind(e) {
518
+ return this.els.filter((n) => O(n) === e).map((n) => n.name).filter((n) => !!n);
519
+ }
520
+ /** An anchored vector shape. */
521
+ shape(e, n = {}) {
522
+ const { width: r, height: i } = this.artboard, o = n.size ?? Math.round(r / 6), a = typeof o == "number" ? o : o.width, s = typeof o == "number" ? o : o.height, { x: l, y: c } = F(n.anchor ?? j, a, s, r, i, n.padding ?? 0), m = {
523
+ type: "shape",
524
+ shapeType: e,
525
+ width: a,
526
+ height: s,
527
+ fillColor: n.fill ?? "#000000",
528
+ fillOpacity: n.opacity ?? 1,
529
+ ...n.points !== void 0 ? { points: n.points } : {},
530
+ ...n.sides !== void 0 ? { sides: n.sides } : {}
531
+ }, u = {
532
+ id: this.nextId("shape"),
533
+ transformType: "shape",
534
+ x: l,
535
+ y: c,
536
+ rotation: n.rotation ?? 0,
537
+ transformData: m,
538
+ ...n.name ? { name: n.name } : {}
539
+ };
540
+ return this.els.push(u), this;
541
+ }
542
+ /** The composed elements, in render order (background first). Editor shape. */
543
+ get elements() {
544
+ return this.els.map((e) => ({ ...e }));
545
+ }
546
+ /** Editor-shape canvas state for `<SnowconeCanvas initialElements=… />` and
547
+ * `serializeStateForServer`. `activeArtboard` is the artboard name. */
548
+ toJSON() {
549
+ return {
550
+ elements: this.elements,
551
+ artboards: [{
552
+ name: this.artboard.name,
553
+ width: this.artboard.width,
554
+ height: this.artboard.height,
555
+ // A background set on a design is part of the design: flag it
556
+ // renderable so exports and server renders paint it, matching the
557
+ // editor (the export worker skips it without `exportBackground`).
558
+ ...this.artboard.backgroundColor ? {
559
+ backgroundColor: this.artboard.backgroundColor,
560
+ exportBackground: this.artboard.backgroundColor !== "transparent"
561
+ } : {}
562
+ }],
563
+ activeArtboard: this.artboard.name
564
+ };
565
+ }
566
+ /** Server-render payload for `RenderSession.renderState(placement, …)`.
567
+ * Equivalent to `serializeStateForServer(design.toJSON())`. */
568
+ toServerRequest() {
569
+ return kt(this.toJSON());
570
+ }
571
+ }
572
+ function Lt(t) {
573
+ return new U(t);
574
+ }
575
+ function Xt(t) {
576
+ return O(t);
577
+ }
578
+ const tt = "personalization", $t = it("type", [
579
+ E({
580
+ type: b("text"),
581
+ name: h().min(1),
582
+ label: h(),
583
+ placeholder: h().optional(),
584
+ maxLength: at().int().positive().optional(),
585
+ group: h().optional()
586
+ }),
587
+ E({
588
+ type: b("image"),
589
+ name: h().min(1),
590
+ label: h(),
591
+ placeholder: h().optional(),
592
+ fit: L([b("cover"), b("contain")]).optional(),
593
+ group: h().optional()
594
+ }),
595
+ E({
596
+ type: b("color"),
597
+ color: h().min(1),
598
+ label: h(),
599
+ group: h().optional()
600
+ }),
601
+ E({
602
+ type: b("select"),
603
+ name: h().min(1),
604
+ label: h(),
605
+ property: L([b("text"), b("imageUrl"), b("fontFamily")]),
606
+ options: st(E({ label: h(), value: h() })).min(1),
607
+ group: h().optional()
608
+ })
609
+ ]);
610
+ function Kt(t) {
611
+ if (!t || typeof t != "object") return [];
612
+ const e = t[tt];
613
+ if (!Array.isArray(e)) return [];
614
+ const n = [];
615
+ for (const r of e) {
616
+ if (!r || typeof r != "object") continue;
617
+ const i = "type" in r ? r : { ...r, type: "text" }, o = $t.safeParse(i);
618
+ o.success && n.push(o.data);
619
+ }
620
+ return n;
621
+ }
622
+ function Vt(t, e) {
623
+ return { ...t, [tt]: e };
624
+ }
625
+ export {
626
+ Ct as C,
627
+ U as D,
628
+ tt as T,
629
+ Mt as a,
630
+ zt as b,
631
+ _t as c,
632
+ Lt as d,
633
+ It as e,
634
+ Ut as f,
635
+ Wt as g,
636
+ Pt as i,
637
+ Xt as l,
638
+ Kt as r,
639
+ kt as s,
640
+ Yt as u,
641
+ Vt as w
642
+ };
643
+ //# sourceMappingURL=template-fields-GOM4MNfq.js.map