@snowcone-app/canvas 0.37.0 → 0.38.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 (69) hide show
  1. package/ERROR_CONTRACT.md +39 -8
  2. package/STYLING_CONTRACT.md +24 -2
  3. package/dist/{CanvasRenderer-CTN4j-uO.js → CanvasRenderer-D-E5WWLm.js} +4 -4
  4. package/dist/{CanvasRenderer-CTN4j-uO.js.map → CanvasRenderer-D-E5WWLm.js.map} +1 -1
  5. package/dist/{CanvasStateV1-DLE5d1-d.js → CanvasStateV1-C9LQt2J0.js} +7 -7
  6. package/dist/{CanvasStateV1-DLE5d1-d.js.map → CanvasStateV1-C9LQt2J0.js.map} +1 -1
  7. package/dist/{ContextualToolbars-CG5Gmv_i.js → ContextualToolbars-C62As-xY.js} +202 -202
  8. package/dist/{ContextualToolbars-CG5Gmv_i.js.map → ContextualToolbars-C62As-xY.js.map} +1 -1
  9. package/dist/EditorCanvasImpl-BnxEbr2p.js +144 -0
  10. package/dist/EditorCanvasImpl-BnxEbr2p.js.map +1 -0
  11. package/dist/{ExportManager-CDX5_up8.js → ExportManager-BbBfO22S.js} +45 -45
  12. package/dist/{ExportManager-CDX5_up8.js.map → ExportManager-BbBfO22S.js.map} +1 -1
  13. package/dist/{FontAnalyzer-CEYA_6fY.js → FontAnalyzer-DWHS41ba.js} +128 -128
  14. package/dist/FontAnalyzer-DWHS41ba.js.map +1 -0
  15. package/dist/{ImagePanel-DLxIDKV-.js → ImagePanel-BaX0UE-L.js} +57 -57
  16. package/dist/{ImagePanel-DLxIDKV-.js.map → ImagePanel-BaX0UE-L.js.map} +1 -1
  17. package/dist/SnowconeCanvas-CWSPyqqj.js +1112 -0
  18. package/dist/SnowconeCanvas-CWSPyqqj.js.map +1 -0
  19. package/dist/advanced.mjs +138 -138
  20. package/dist/api/placement.d.ts +3 -0
  21. package/dist/components/editor/EditorPlacements.d.ts +19 -6
  22. package/dist/components/editor/RootInternals.d.ts +7 -0
  23. package/dist/components/editor/designStateStore.d.ts +18 -0
  24. package/dist/components/editor/index.d.ts +3 -1
  25. package/dist/components/editor/placementLinks.d.ts +52 -0
  26. package/dist/components/editor/usePlacements.d.ts +28 -4
  27. package/dist/components/embed-realtime/context.d.ts +20 -4
  28. package/dist/components/embed-realtime/usePieceGuideBundle.d.ts +1 -0
  29. package/dist/components/embed-realtime/validateEmbed.d.ts +6 -3
  30. package/dist/{custom-icons-D51KIAfz.js → custom-icons-o1U13Vcg.js} +14 -14
  31. package/dist/{custom-icons-D51KIAfz.js.map → custom-icons-o1U13Vcg.js.map} +1 -1
  32. package/dist/{design-builder-CqgTpp9B.js → design-builder-CoCtjIwj.js} +86 -86
  33. package/dist/{design-builder-CqgTpp9B.js.map → design-builder-CoCtjIwj.js.map} +1 -1
  34. package/dist/{embed-CLz3CTcX.js → embed-SOFUZlGB.js} +843 -729
  35. package/dist/embed-SOFUZlGB.js.map +1 -0
  36. package/dist/embed.mjs +28 -28
  37. package/dist/errors/editorError.d.ts +7 -2
  38. package/dist/{guards-DldCuuJq.js → guards-DMmhw_Ow.js} +4 -4
  39. package/dist/{guards-DldCuuJq.js.map → guards-DMmhw_Ow.js.map} +1 -1
  40. package/dist/index.mjs +21 -21
  41. package/dist/internals.mjs +108 -108
  42. package/dist/internals.mjs.map +1 -1
  43. package/dist/placement-Br5jI_-u.js +90 -0
  44. package/dist/placement-Br5jI_-u.js.map +1 -0
  45. package/dist/placement.d.ts +2 -0
  46. package/dist/placement.mjs +5 -0
  47. package/dist/placement.mjs.map +1 -0
  48. package/dist/template-fields-CBLHgW7G.js +556 -0
  49. package/dist/template-fields-CBLHgW7G.js.map +1 -0
  50. package/dist/testing.mjs +24 -24
  51. package/dist/{useCommands-CQi4Pyd2.js → useCommands-x8J7_Mzy.js} +262 -262
  52. package/dist/{useCommands-CQi4Pyd2.js.map → useCommands-x8J7_Mzy.js.map} +1 -1
  53. package/dist/usePieceGuideBundle-C7r06a_x.js +65 -0
  54. package/dist/usePieceGuideBundle-C7r06a_x.js.map +1 -0
  55. package/dist/{validation-THw5W6N_.js → validation-BG-V98h0.js} +846 -846
  56. package/dist/validation-BG-V98h0.js.map +1 -0
  57. package/example/package.json +1 -1
  58. package/package.json +9 -4
  59. package/dist/EditorCanvasImpl-BRdFWZA5.js +0 -81
  60. package/dist/EditorCanvasImpl-BRdFWZA5.js.map +0 -1
  61. package/dist/FontAnalyzer-CEYA_6fY.js.map +0 -1
  62. package/dist/SnowconeCanvas-BaFR8QXs.js +0 -1196
  63. package/dist/SnowconeCanvas-BaFR8QXs.js.map +0 -1
  64. package/dist/embed-CLz3CTcX.js.map +0 -1
  65. package/dist/template-fields-D8uOutD4.js +0 -505
  66. package/dist/template-fields-D8uOutD4.js.map +0 -1
  67. package/dist/usePieceGuideBundle-BUQKb0Ja.js +0 -61
  68. package/dist/usePieceGuideBundle-BUQKb0Ja.js.map +0 -1
  69. package/dist/validation-THw5W6N_.js.map +0 -1
@@ -0,0 +1,556 @@
1
+ import { t as v, p as V, T, I as M, x as st } from "./FontAnalyzer-DWHS41ba.js";
2
+ import { l as G, b as ot, i as it, u as O, a as B, h as rt } from "./design-builder-CoCtjIwj.js";
3
+ import { toOptionAttributes as at, toCombinations as ct, getMissingSelections as lt, validateProductSelection as mt, findBestCombination as F, computeDisabledChoices as ft } from "@snowcone-app/sdk";
4
+ import { useEffect as ut, useContext as Z, useId as dt, useLayoutEffect as ht, useRef as C, useMemo as A, useCallback as _, useState as q } from "react";
5
+ import { E as tt, U as gt } from "./useCommands-x8J7_Mzy.js";
6
+ import { b as pt, o as $, c as f, n as bt, l as p, u as J, e as yt } from "./CanvasStateV1-C9LQt2J0.js";
7
+ function R(s) {
8
+ return s.text;
9
+ }
10
+ function x(s) {
11
+ return s.name;
12
+ }
13
+ class Pt {
14
+ constructor(t) {
15
+ this.listeners = /* @__PURE__ */ new Set(), this.getState = () => this.state, this.subscribe = (o) => (this.listeners.add(o), () => this.listeners.delete(o)), this.state = t;
16
+ const e = /* @__PURE__ */ new Map();
17
+ for (const o of t.elements) {
18
+ const n = x(o), i = R(o);
19
+ n && typeof i == "string" && e.set(n, i);
20
+ }
21
+ this.seedTextByName = e;
22
+ }
23
+ /** Replace the whole state (the canvas `onChange` path). */
24
+ setState(t) {
25
+ this.state = t, this.emit();
26
+ }
27
+ /** The seed value of a named text layer (for completeness rule C3). */
28
+ seedTextOf(t) {
29
+ return this.seedTextByName.get(t);
30
+ }
31
+ /** Current text of a named text layer, or undefined when absent. */
32
+ textOf(t) {
33
+ const e = this.state.elements.find((o) => x(o) === t);
34
+ return e ? R(e) : void 0;
35
+ }
36
+ /** Kind of the named layer in the CURRENT state ('text' | 'image' | null
37
+ * for unbindable), or undefined when no layer has the name. */
38
+ layerKindOf(t) {
39
+ const e = this.state.elements.find((o) => x(o) === t);
40
+ return e ? G(e) : void 0;
41
+ }
42
+ /** Names of bindable layers in the current state, for error messages. */
43
+ bindableLayerNames() {
44
+ return this.state.elements.filter((t) => G(t) !== null).map(x).filter((t) => !!t);
45
+ }
46
+ /**
47
+ * Direct write path for `Editor.TextField` when NO canvas is mounted (with
48
+ * one, writes route through the editor command path and arrive back here
49
+ * via `setState`). Immutable update; last-write-wins.
50
+ */
51
+ updateTextLayer(t, e) {
52
+ let o = !1;
53
+ const n = this.state.elements.map((i) => x(i) !== t ? i : (o = !0, { ...i, text: e }));
54
+ if (!o)
55
+ throw new v(
56
+ "E_LAYER_NOT_FOUND",
57
+ `no layer "${t}" in the current design state. Bindable layers: ${JSON.stringify(this.bindableLayerNames())}.`,
58
+ { layerName: t, validNames: this.bindableLayerNames(), docSlug: "embed-mode" }
59
+ );
60
+ this.setState({ ...this.state, elements: n });
61
+ }
62
+ /** Artboard names in author order — the first is the base (ADR-0101). */
63
+ artboardNames() {
64
+ return this.state.artboards.map((t) => t.name);
65
+ }
66
+ /**
67
+ * Split a placement out of the base (ADR-0101): clone the FIRST artboard
68
+ * and every element on it into a new artboard named `label`. Elements get
69
+ * fresh ids and the new artboard's membership tag. No-op when `label`
70
+ * already has an artboard. Used when NO canvas is mounted — with one, the
71
+ * editor document does the same through the CanvasBridge and the result
72
+ * lands here via `setState`.
73
+ */
74
+ splitArtboard(t) {
75
+ const { artboards: e, elements: o } = this.state, n = e[0];
76
+ if (!n || e.some((c) => c.name === t)) return;
77
+ const i = n.name, a = (c) => {
78
+ const l = c.artboard;
79
+ return l === void 0 || l === i;
80
+ }, r = o.filter(a).map((c, l) => ({
81
+ ...c,
82
+ id: `${String(c.id ?? "el")}__${t}__${l}`,
83
+ artboard: t
84
+ }));
85
+ this.setState({
86
+ ...this.state,
87
+ artboards: [...e, { ...n, name: t }],
88
+ elements: [...o, ...r]
89
+ });
90
+ }
91
+ /**
92
+ * Re-link a placement (ADR-0101): drop the artboard named `label` and every
93
+ * element tagged to it, so the placement inherits the base again. No-op for
94
+ * an unknown label. Refuses the base itself — that is what the others
95
+ * inherit (`E_LINK_BASE`).
96
+ */
97
+ removeArtboard(t) {
98
+ var n;
99
+ const { artboards: e, elements: o } = this.state;
100
+ if (((n = e[0]) == null ? void 0 : n.name) === t)
101
+ throw new v(
102
+ "E_LINK_BASE",
103
+ `"${t}" is the base artboard — every linked placement inherits it, so it cannot be re-linked. Link a split placement instead, or call linkAll(). Artboards: ${JSON.stringify(this.artboardNames())}.`,
104
+ { artboardName: t, validNames: this.artboardNames().slice(1), docSlug: "embed-mode" }
105
+ );
106
+ e.some((i) => i.name === t) && this.setState({
107
+ ...this.state,
108
+ artboards: e.filter((i) => i.name !== t),
109
+ elements: o.filter((i) => i.artboard !== t),
110
+ activeArtboard: this.state.activeArtboard === t ? e[0].name : this.state.activeArtboard
111
+ });
112
+ }
113
+ /** ≥1 element with visible content (completeness rule C4): non-empty text,
114
+ * an image with a URL, or a shape. Hidden elements don't count. */
115
+ hasRenderableElement() {
116
+ return this.state.elements.some((t) => {
117
+ if (t.visible === !1) return !1;
118
+ const e = t.transformType;
119
+ if (e === "image") return !!t.imageUrl;
120
+ if (e === "shape" || e === "group" || e === "path") return !0;
121
+ const o = R(t);
122
+ return typeof o == "string" && o.trim().length > 0;
123
+ });
124
+ }
125
+ emit() {
126
+ for (const t of [...this.listeners]) t();
127
+ }
128
+ }
129
+ function X(s) {
130
+ return (s.choices ?? []).map((t) => typeof t == "string" ? t : t.label ?? "").filter((t) => t !== "");
131
+ }
132
+ function vt(s, t) {
133
+ if (!s.variantId) return {};
134
+ const e = t.find((n) => n.variantId === s.variantId);
135
+ if (!e) return {};
136
+ const o = {};
137
+ for (const [n, i] of Object.entries(e))
138
+ n === "variantId" || n === "price" || (typeof i == "string" ? o[n] = i : typeof i == "number" && (o[n] = String(i)));
139
+ return o;
140
+ }
141
+ class Wt {
142
+ constructor(t) {
143
+ this.quantity = 1, this.version = 0, this.listeners = /* @__PURE__ */ new Set(), this.getVersion = () => this.version, this.subscribe = (e) => (this.listeners.add(e), () => this.listeners.delete(e)), this.product = t, this.attrs = at({ options: t.options }), this.combos = ct({ options: t.options }), this.selection = vt(t, this.combos);
144
+ }
145
+ getAttributes() {
146
+ return this.attrs;
147
+ }
148
+ getSelection() {
149
+ return this.selection;
150
+ }
151
+ getQuantity() {
152
+ return this.quantity;
153
+ }
154
+ /**
155
+ * Select a choice for a variant attribute. Strict + loud (D4/E3): an
156
+ * attribute key or choice that doesn't exist on the product is a wiring
157
+ * mistake, not user state — throws `E_UNKNOWN_OPTION` listing what IS valid.
158
+ */
159
+ select(t, e) {
160
+ const o = this.attrs[t];
161
+ if (!o)
162
+ throw new v(
163
+ "E_UNKNOWN_OPTION",
164
+ `product ${this.product.productId} has no option "${t}". Valid option keys: ${JSON.stringify(Object.keys(this.attrs))}.`,
165
+ { key: t, validKeys: Object.keys(this.attrs), docSlug: "embed-mode" }
166
+ );
167
+ const n = X(o);
168
+ if (n.length > 0 && !n.includes(e))
169
+ throw new v(
170
+ "E_UNKNOWN_OPTION",
171
+ `"${e}" is not a choice of option "${t}" on product ${this.product.productId}. Valid choices: ${JSON.stringify(n)}.`,
172
+ { key: t, choice: e, validChoices: n, docSlug: "embed-mode" }
173
+ );
174
+ this.selection[t] !== e && (this.selection = { ...this.selection, [t]: e }, this.bump());
175
+ }
176
+ /** Quantity is USER state (completeness rule C5 gates on it) — never throws. */
177
+ setQuantity(t) {
178
+ this.quantity !== t && (this.quantity = t, this.bump());
179
+ }
180
+ /** Attribute keys still required (non-optional) but unselected — Buy's
181
+ * `option:<key>` reason codes. */
182
+ missingOptionKeys() {
183
+ return Object.keys(this.attrs).length === 0 ? [] : lt(this.attrs, this.selection);
184
+ }
185
+ /** Full selection resolution (the C1 amendment): true when every required
186
+ * attribute is selected AND the selection matches a valid combination. */
187
+ selectionValid() {
188
+ return Object.keys(this.attrs).length === 0 ? !0 : mt(this.attrs, this.selection, this.combos);
189
+ }
190
+ /** The variant (gvid) the current selection resolves to. Falls back to the
191
+ * product's initial `variantId` while nothing has been selected. */
192
+ resolvedVariantId() {
193
+ if (Object.keys(this.attrs).length === 0 || this.combos.length === 0)
194
+ return this.product.variantId;
195
+ if (!this.selectionValid()) return;
196
+ const t = F(this.selection, this.combos, this.attrs);
197
+ return (typeof (t == null ? void 0 : t.variantId) == "string" && t.variantId !== "" ? t.variantId : void 0) ?? this.product.variantId;
198
+ }
199
+ /**
200
+ * The variant (gvid) to RENDER with — deliberately looser than
201
+ * {@link resolvedVariantId}. That one is Buy's currency: it returns
202
+ * `undefined` while the selection is incomplete so completeness can gate.
203
+ * But the PRODUCT PHOTO must follow the shopper's picks immediately —
204
+ * "choose the Oak frame" should render Oak even while an unrelated axis
205
+ * (size, pocket) is still unselected. This resolves the best combination
206
+ * matching the CURRENT (possibly partial) selection, falling back to the
207
+ * product's initial variant. (Before this split, switching a color swatch
208
+ * with any axis unselected rendered nothing — the mockup silently stayed
209
+ * on the old color.)
210
+ */
211
+ renderVariantId() {
212
+ if (Object.keys(this.attrs).length === 0 || this.combos.length === 0)
213
+ return this.product.variantId;
214
+ const t = F(this.selection, this.combos, this.attrs);
215
+ return (typeof (t == null ? void 0 : t.variantId) == "string" && t.variantId !== "" ? t.variantId : void 0) ?? this.product.variantId;
216
+ }
217
+ /** Price of the resolved combination, when the catalog carries one. */
218
+ resolvedPrice() {
219
+ if (!this.selectionValid()) return;
220
+ const t = F(this.selection, this.combos, this.attrs);
221
+ return typeof (t == null ? void 0 : t.price) == "number" ? t.price : void 0;
222
+ }
223
+ /** Choices invalid given the rest of the current selection — for hosts to
224
+ * disable/grey out in their variant UI. */
225
+ disabledChoices() {
226
+ const t = {};
227
+ for (const [e, o] of Object.entries(this.attrs))
228
+ t[e] = { ...o, choices: X(o) };
229
+ return ft(this.selection, t, this.combos);
230
+ }
231
+ /** The combinations (for payload assembly via `createCartDetail`). */
232
+ getCombinations() {
233
+ return this.combos;
234
+ }
235
+ bump() {
236
+ this.version++;
237
+ for (const t of [...this.listeners]) t();
238
+ }
239
+ }
240
+ function jt() {
241
+ const { selectedElement: s } = ot();
242
+ return s ?? null;
243
+ }
244
+ const Nt = 3e3, z = {
245
+ text: "useTextBinding",
246
+ image: "useImageBinding",
247
+ font: "useFontBinding"
248
+ }, $t = {
249
+ text: "setText",
250
+ image: "setImageUrl",
251
+ font: "setFontFamily"
252
+ }, xt = {
253
+ text: "text",
254
+ image: "image",
255
+ font: "text"
256
+ }, U = /* @__PURE__ */ new Set();
257
+ function Q(s) {
258
+ return s instanceof T ? "text" : s instanceof M ? "image" : "other";
259
+ }
260
+ function Ct(s, t, e) {
261
+ const o = `[${z[s]}]`, n = `the binding is dead (isConnected: false, ${$t[s]} is a no-op)`, i = xt[s], a = e.getAllByName(t);
262
+ if (a.length > 0) {
263
+ const l = [...new Set(a.map(Q))], m = i === "text" ? "image" : "text", N = l.length === 1 && l[0] === m ? ` Bind it with ${z[m]}("${t}") instead.` : "";
264
+ return `${o} the layer named "${t}" is ${l.join("/")}, not ${i} — ${n}.${N}`;
265
+ }
266
+ const r = e.getAll().filter((l) => l.name).map((l) => `"${l.name}" (${Q(l)})`), c = r.length ? `Named layers on this canvas: ${r.join(", ")}. Check the name for a typo.` : `No element on this canvas has a name — name one via design().${i}(…, { name: '${t}' }) or the element's \`name\` property.`;
267
+ return `${o} no ${i} layer named "${t}" exists — ${n}. ${c}`;
268
+ }
269
+ function Y(s, t, e, o) {
270
+ ut(() => {
271
+ var a;
272
+ if (o || typeof V > "u" || ((a = V.env) == null ? void 0 : a.NODE_ENV) === "production") return;
273
+ const n = `${s}:${t}`;
274
+ if (U.has(n)) return;
275
+ const i = setTimeout(() => {
276
+ U.has(n) || (U.add(n), console.warn(Ct(s, t, e)));
277
+ }, Nt);
278
+ return () => clearTimeout(i);
279
+ }, [s, t, e, o]);
280
+ }
281
+ function k(s) {
282
+ const t = Z(tt), e = dt();
283
+ ht(() => {
284
+ if (t)
285
+ return t.registry.requireCanvas(e, s);
286
+ }, [t, e, s]);
287
+ }
288
+ function L(s) {
289
+ return s instanceof T ? "text" : s instanceof M ? "image" : null;
290
+ }
291
+ const Ot = {
292
+ text: "useTextBinding / useFontBinding",
293
+ image: "useImageBinding"
294
+ };
295
+ function P(s, t, e) {
296
+ const o = it(s), n = o ? s.name : s, i = Z(tt), a = C(null);
297
+ if (o && s.kind !== t)
298
+ throw new v(
299
+ "E_LAYER_WRONG_KIND",
300
+ `layer "${n}" is a ${s.kind} token — this hook binds ${t} layers only (use ${Ot[s.kind]}).`,
301
+ { layerName: n, actualKind: s.kind, expectedKind: t, docSlug: "embed-mode" }
302
+ );
303
+ if (o && i && a.current !== n) {
304
+ const r = e.getAll();
305
+ if (r.length > 0) {
306
+ const c = e.getAllByName(n);
307
+ if (c.length === 0) {
308
+ const l = r.map((m) => ({ name: m.name, kind: L(m) })).filter((m) => !!m.name && m.kind !== null);
309
+ throw new v(
310
+ "E_LAYER_NOT_FOUND",
311
+ `no layer "${n}" in this Root's document — the token was minted from a different design than the one passed to <Editor.Root design={…}>, or the layer was deleted. Bindable layers here: ${JSON.stringify(l.map((m) => m.name))}.`,
312
+ { layerName: n, validNames: l.map((m) => m.name), docSlug: "embed-mode" }
313
+ );
314
+ }
315
+ if (!c.some((l) => L(l) === t)) {
316
+ const l = L(c[0]) ?? "unbindable";
317
+ throw new v(
318
+ "E_LAYER_WRONG_KIND",
319
+ `layer "${n}" is ${l === "unbindable" ? "not a bindable kind" : `an ${l} layer`} — this hook binds ${t} layers only.`,
320
+ { layerName: n, actualKind: l, expectedKind: t, docSlug: "embed-mode" }
321
+ );
322
+ }
323
+ a.current = n;
324
+ }
325
+ }
326
+ return n;
327
+ }
328
+ const St = () => {
329
+ }, Dt = [];
330
+ function Kt(s) {
331
+ const { elementStore: t } = O();
332
+ k("useTextBinding()");
333
+ const e = P(s, "text", t), { executeElementUpdate: o } = B(), n = A(() => t.getAllByName(e).filter((r) => r instanceof T), [t, e]), i = _(
334
+ (a) => {
335
+ for (const r of n) {
336
+ const c = r.clone();
337
+ c.setText(a), o(r, c);
338
+ }
339
+ },
340
+ [n, o]
341
+ );
342
+ return Y("text", e, t, n.length > 0), n.length === 0 ? { text: "", setText: St, element: null, elements: Dt, isConnected: !1 } : {
343
+ text: n[0].getText(),
344
+ setText: i,
345
+ element: n[0],
346
+ elements: n,
347
+ isConnected: !0
348
+ };
349
+ }
350
+ const Et = () => {
351
+ }, It = [];
352
+ function Tt(s, t, e) {
353
+ const o = s / t;
354
+ if (e >= o) {
355
+ const n = t, i = n * e, a = s / i;
356
+ return {
357
+ width: i,
358
+ height: n,
359
+ cropX: (1 - a) / 2,
360
+ cropY: 0,
361
+ cropWidth: a,
362
+ cropHeight: 1
363
+ };
364
+ } else {
365
+ const n = s, i = n / e, a = t / i;
366
+ return {
367
+ width: n,
368
+ height: i,
369
+ cropX: 0,
370
+ cropY: (1 - a) / 2,
371
+ cropWidth: 1,
372
+ cropHeight: a
373
+ };
374
+ }
375
+ }
376
+ function Ht(s, t) {
377
+ k("useImageBinding()");
378
+ const e = (t == null ? void 0 : t.fit) ?? "cover", { elementStore: o, setElements: n } = O(), i = P(s, "image", o), { executeElementUpdate: a } = B(), r = A(() => o.getAllByName(i).filter((b) => b instanceof M), [o, i]), c = C(/* @__PURE__ */ new Map());
379
+ for (const d of r)
380
+ if (!c.current.has(d.id)) {
381
+ const b = d.transformData;
382
+ c.current.set(d.id, {
383
+ width: b.width * b.cropWidth,
384
+ height: b.height * b.cropHeight
385
+ });
386
+ }
387
+ const l = C(r);
388
+ l.current = r;
389
+ const m = C(a);
390
+ m.current = a;
391
+ const N = C(n);
392
+ N.current = n;
393
+ const S = _(
394
+ (d) => {
395
+ const b = l.current, W = m.current;
396
+ for (const D of b) {
397
+ const j = c.current.get(D.id);
398
+ if (!j) continue;
399
+ const { width: K, height: H } = j, h = D.clone();
400
+ h.imageLoaded = !1, h.imageElement = null, h.isCropping = !1, h.imageUrl = d, e === "cover" ? (h.preserveDimensions = !0, h.onLoadCallback = (u) => {
401
+ const E = u.imageAspectRatio || 1, g = Tt(K, H, E);
402
+ u.transformData.width = g.width, u.transformData.height = g.height, u.transformData.cropX = g.cropX, u.transformData.cropY = g.cropY, u.transformData.cropWidth = g.cropWidth, u.transformData.cropHeight = g.cropHeight, W(D, u);
403
+ }) : (h.preserveDimensions = !1, h.onLoadCallback = (u) => {
404
+ const E = u.transformData.width, g = u.transformData.height, w = Math.min(K / E, H / g, 1);
405
+ w < 1 && (u.transformData.width = E * w, u.transformData.height = g * w), u.transformData.cropX = 0, u.transformData.cropY = 0, u.transformData.cropWidth = 1, u.transformData.cropHeight = 1, W(D, u);
406
+ }), h.loadImage(d);
407
+ }
408
+ },
409
+ [e]
410
+ // Stable deps only — imageElements/executeElementUpdate/setElements accessed via refs
411
+ );
412
+ return Y("image", i, o, r.length > 0), r.length === 0 ? { imageUrl: "", setImageUrl: Et, element: null, elements: It, isConnected: !1 } : {
413
+ imageUrl: r[0].imageUrl,
414
+ setImageUrl: S,
415
+ element: r[0],
416
+ elements: r,
417
+ isConnected: !0
418
+ };
419
+ }
420
+ const Bt = [];
421
+ function I(s) {
422
+ let t = s.trim().toUpperCase();
423
+ return t.length === 4 && t.startsWith("#") && (t = "#" + t[1] + t[1] + t[2] + t[2] + t[3] + t[3]), t;
424
+ }
425
+ function y(s, t) {
426
+ return typeof s == "string" && I(s) === t;
427
+ }
428
+ function et(s, t) {
429
+ var o, n, i;
430
+ const e = s;
431
+ return y(e.color, t) || y((o = e.transformData) == null ? void 0 : o.fillColor, t) || y((n = e.transformData) == null ? void 0 : n.strokeColor, t) || ((i = e.stroke) == null ? void 0 : i.enabled) === !0 && y(e.stroke.color, t);
432
+ }
433
+ function At(s, t, e) {
434
+ var a, r, c;
435
+ if (!et(s, t)) return null;
436
+ const o = s.clone(), n = s, i = o;
437
+ return y(n.color, t) && (typeof i.setColor == "function" ? i.setColor(e) : i.color = e), y((a = n.transformData) == null ? void 0 : a.fillColor, t) && (i.transformData = { ...i.transformData, fillColor: e }), y((r = n.transformData) == null ? void 0 : r.strokeColor, t) && (i.transformData = { ...i.transformData, strokeColor: e }), ((c = n.stroke) == null ? void 0 : c.enabled) === !0 && y(n.stroke.color, t) && (i.stroke = { ...i.stroke, color: e }), o;
438
+ }
439
+ function Vt(s) {
440
+ const t = rt(s) ? s.value : s, { elementStore: e } = O(), { executeElementUpdate: o } = B();
441
+ k("useColorBinding()");
442
+ const [n, i] = q(() => I(t)), [a, r] = q(t);
443
+ t !== a && (r(t), i(I(t)));
444
+ const c = A(
445
+ () => e.getAll().filter((m) => et(m, n)),
446
+ [e, n]
447
+ ), l = _(
448
+ (m) => {
449
+ const N = I(m);
450
+ if (N !== n) {
451
+ for (const S of e.getAll()) {
452
+ const d = At(S, n, m);
453
+ d && o(S, d);
454
+ }
455
+ i(N);
456
+ }
457
+ },
458
+ [e, n, o]
459
+ );
460
+ return c.length === 0 ? { color: n, setColor: l, elements: Bt, isConnected: !1 } : { color: n, setColor: l, elements: c, isConnected: !0 };
461
+ }
462
+ const _t = () => {
463
+ }, kt = [];
464
+ function Gt(s) {
465
+ const { elementStore: t } = O();
466
+ k("useFontBinding()");
467
+ const e = P(s, "text", t), { executeElementUpdate: o } = B(), n = A(() => t.getAllByName(e).filter((r) => r instanceof T), [t, e]), i = _(
468
+ (a) => {
469
+ gt.loadGoogleFontByName(a);
470
+ for (const r of n) {
471
+ if (r.fontFamily === a) continue;
472
+ st.clearCache(r.fontFamily);
473
+ const c = r.clone();
474
+ c.fontFamily = a, o(r, c);
475
+ }
476
+ },
477
+ [n, o]
478
+ );
479
+ return Y("font", e, t, n.length > 0), n.length === 0 ? { fontFamily: "", setFontFamily: _t, element: null, elements: kt, isConnected: !1 } : {
480
+ fontFamily: n[0].fontFamily,
481
+ setFontFamily: i,
482
+ element: n[0],
483
+ elements: n,
484
+ isConnected: !0
485
+ };
486
+ }
487
+ function qt(s) {
488
+ const { elementStore: t } = O();
489
+ return s ? t.getByName(s) ?? null : null;
490
+ }
491
+ const nt = "personalization", wt = pt("type", [
492
+ $({
493
+ type: p("text"),
494
+ name: f().min(1),
495
+ label: f(),
496
+ placeholder: f().optional(),
497
+ maxLength: bt().int().positive().optional(),
498
+ artboard: f().min(1).optional(),
499
+ group: f().optional()
500
+ }),
501
+ $({
502
+ type: p("image"),
503
+ name: f().min(1),
504
+ label: f(),
505
+ placeholder: f().optional(),
506
+ fit: J([p("cover"), p("contain")]).optional(),
507
+ artboard: f().min(1).optional(),
508
+ group: f().optional()
509
+ }),
510
+ $({
511
+ type: p("color"),
512
+ color: f().min(1),
513
+ label: f(),
514
+ artboard: f().min(1).optional(),
515
+ group: f().optional()
516
+ }),
517
+ $({
518
+ type: p("select"),
519
+ name: f().min(1),
520
+ label: f(),
521
+ property: J([p("text"), p("imageUrl"), p("fontFamily")]),
522
+ options: yt($({ label: f(), value: f() })).min(1),
523
+ artboard: f().min(1).optional(),
524
+ group: f().optional()
525
+ })
526
+ ]);
527
+ function Jt(s) {
528
+ if (!s || typeof s != "object") return [];
529
+ const t = s[nt];
530
+ if (!Array.isArray(t)) return [];
531
+ const e = [];
532
+ for (const o of t) {
533
+ if (!o || typeof o != "object") continue;
534
+ const n = "type" in o ? o : { ...o, type: "text" }, i = wt.safeParse(n);
535
+ i.success && e.push(i.data);
536
+ }
537
+ return e;
538
+ }
539
+ function Xt(s, t) {
540
+ return { ...s, [nt]: t };
541
+ }
542
+ export {
543
+ Wt as C,
544
+ Pt as D,
545
+ nt as T,
546
+ qt as a,
547
+ Gt as b,
548
+ Ht as c,
549
+ jt as d,
550
+ Kt as e,
551
+ X as f,
552
+ Jt as r,
553
+ Vt as u,
554
+ Xt as w
555
+ };
556
+ //# sourceMappingURL=template-fields-CBLHgW7G.js.map