@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
@@ -1,176 +1,176 @@
1
- import { E as Ke, p as Ge, q as We, C as He, r as te, t as ne, v as Je, w as Qe, x as Ye, y as Xe, z as Ze, h as et, e as tt } from "./useCommands-CQi4Pyd2.js";
2
- import { E as I, y as Ce, z as P } from "./FontAnalyzer-CEYA_6fY.js";
3
- import { jsx as c, jsxs as F, Fragment as nt } from "react/jsx-runtime";
4
- import { useContext as rt, createContext as it, useRef as O, useState as T, useMemo as L, useCallback as K, useLayoutEffect as re, useEffect as U, useSyncExternalStore as J, Component as st, forwardRef as $e, useId as ge, memo as ot, isValidElement as Oe } from "react";
5
- import { assertVariantSelected as at, RenderSession as dt, createCartDetail as lt } from "@snowcone-app/sdk";
6
- import { s as de, B as ct, E as ut, r as mt, i as pt } from "./design-builder-CqgTpp9B.js";
7
- import { u as ft, p as ht } from "./usePieceGuideBundle-BUQKb0Ja.js";
8
- import { D as gt, C as yt, f as bt, d as vt } from "./template-fields-D8uOutD4.js";
9
- import "./ExportManager-CDX5_up8.js";
10
- import "./CanvasStateV1-DLE5d1-d.js";
11
- const Ne = it(void 0);
12
- function Q() {
13
- const e = rt(Ne);
1
+ import { n as Xe, o as Ze, E as et, C as tt, y as se, z as oe, A as nt, F as rt, G as it, H as st, J as ot, l as at, e as dt } from "./useCommands-x8J7_Mzy.js";
2
+ import { t as S, V as Te, p as z } from "./FontAnalyzer-DWHS41ba.js";
3
+ import { jsx as g, jsxs as U, Fragment as lt } from "react/jsx-runtime";
4
+ import { useContext as ct, createContext as ut, useRef as C, useState as D, useMemo as A, useCallback as G, useLayoutEffect as ae, useEffect as L, useSyncExternalStore as J, Component as mt, forwardRef as Ae, useId as we, memo as pt, isValidElement as De } from "react";
5
+ import { assertVariantSelected as ft, RenderSession as ht, createCartDetail as gt } from "@snowcone-app/sdk";
6
+ import { s as ee, B as yt, E as bt, n as vt, i as wt } from "./design-builder-CoCtjIwj.js";
7
+ import { u as Et, p as kt } from "./usePieceGuideBundle-C7r06a_x.js";
8
+ import { D as xt, C as St, f as Rt, d as It } from "./template-fields-CBLHgW7G.js";
9
+ import "./ExportManager-BbBfO22S.js";
10
+ import "./CanvasStateV1-C9LQt2J0.js";
11
+ const Be = ut(void 0);
12
+ function te() {
13
+ const e = ct(Be);
14
14
  if (!e)
15
15
  throw new Error(
16
16
  "useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered inside <RealtimeEmbed>. Wrap them: <RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>"
17
17
  );
18
18
  return e;
19
19
  }
20
- function _e(e) {
20
+ function Ue(e) {
21
21
  var t;
22
22
  return Array.isArray((t = e.bundle) == null ? void 0 : t.members) && e.bundle.members.length > 0;
23
23
  }
24
- const G = "bundles";
25
- function wt(e) {
24
+ const W = "bundles";
25
+ function Ot(e) {
26
26
  return Object.keys(e).sort().map((t) => `${t}:${e[t]}`).join(",");
27
27
  }
28
- function ye(e) {
28
+ function Ee(e) {
29
29
  const t = e.indexOf(".");
30
30
  return t <= 0 || t === e.length - 1 ? null : { role: e.slice(0, t), key: e.slice(t + 1) };
31
31
  }
32
- function Et(e) {
32
+ function $t(e) {
33
33
  return e.type !== "color" && typeof e.width == "number" && e.width > 0 && typeof e.height == "number" && e.height > 0;
34
34
  }
35
- function kt(e, t) {
35
+ function Ct(e, t) {
36
36
  var i, s;
37
37
  const n = (s = (i = e.options) == null ? void 0 : i.combinations) == null ? void 0 : s.find((o) => o.variantId === t);
38
38
  if (!n) return t;
39
39
  const r = Object.entries(n).filter(([o, l]) => o !== "variantId" && o !== "price" && (typeof l == "string" || typeof l == "number")).map(([o, l]) => `${o} ${String(l)}`);
40
40
  return r.length > 0 ? r.join(" · ") : t;
41
41
  }
42
- function yn(e, t = {}) {
43
- var E, A, C, D, V;
44
- if (!_e(e))
45
- throw new I(
42
+ function On(e, t = {}) {
43
+ var v, B, N, _, F;
44
+ if (!Ue(e))
45
+ throw new S(
46
46
  "E_NOT_A_BUNDLE",
47
47
  `product ${e.id} has no bundle block — picks / variants are bundle parameters the server refuses on a single product (E_NOT_A_BUNDLE). Use productToRenderConfig() for it.`,
48
- { productId: e.id, docSlug: G }
48
+ { productId: e.id, docSlug: W }
49
49
  );
50
- const n = e.bundle.members, r = n.map((m) => m.role);
51
- for (const [m, R] of [
50
+ const n = e.bundle.members, r = n.map((h) => h.role);
51
+ for (const [h, $] of [
52
52
  ["picks", t.picks],
53
53
  ["variants", t.variants]
54
54
  ])
55
- for (const N of Object.keys(R ?? {}))
56
- if (!r.includes(N))
57
- throw new I(
55
+ for (const V of Object.keys($ ?? {}))
56
+ if (!r.includes(V))
57
+ throw new S(
58
58
  "E_BUNDLE_ROLE_NOT_FOUND",
59
- `bundle ${e.id} has no role "${N}" (in ${m}). Roles: [${r.join(", ")}].`,
60
- { productId: e.id, field: m, role: N, validNames: r, docSlug: G }
59
+ `bundle ${e.id} has no role "${V}" (in ${h}). Roles: [${r.join(", ")}].`,
60
+ { productId: e.id, field: h, role: V, validNames: r, docSlug: W }
61
61
  );
62
- const i = {}, s = {}, o = {}, l = e.placements ?? [], u = [];
63
- for (const m of n) {
64
- const R = m.products.map((w) => w.productId), N = (E = t.picks) == null ? void 0 : E[m.role], _ = N === void 0 ? m.products[0] : m.products.find((w) => w.productId === N);
65
- if (!_)
66
- throw new I(
62
+ const i = {}, s = {}, o = {}, l = e.placements ?? [], d = [];
63
+ for (const h of n) {
64
+ const $ = h.products.map((w) => w.productId), V = (v = t.picks) == null ? void 0 : v[h.role], T = V === void 0 ? h.products[0] : h.products.find((w) => w.productId === V);
65
+ if (!T)
66
+ throw new S(
67
67
  "E_BUNDLE_PICK_NOT_FOUND",
68
- `bundle ${e.id} role "${m.role}" has no alternative "${N}". Alternatives: [${R.join(", ")}] — pass picks: { ${m.role}: "${R[0]}" }.`,
69
- { productId: e.id, role: m.role, requested: N, validNames: R, docSlug: G }
68
+ `bundle ${e.id} role "${h.role}" has no alternative "${V}". Alternatives: [${$.join(", ")}] — pass picks: { ${h.role}: "${$[0]}" }.`,
69
+ { productId: e.id, role: h.role, requested: V, validNames: $, docSlug: W }
70
70
  );
71
- i[m.role] = _.productId;
72
- const Y = (_.variants ?? []).map((w) => w.gvid).filter((w) => typeof w == "string" && w !== ""), q = Y.length > 0 ? Y : _.defaultGvid ? [_.defaultGvid] : [], M = ((A = t.variants) == null ? void 0 : A[m.role]) ?? _.defaultGvid ?? Y[0];
73
- if (!M || !q.includes(M)) {
74
- const w = (C = t.variants) == null ? void 0 : C[m.role];
75
- throw new I(
71
+ i[h.role] = T.productId;
72
+ const j = (T.variants ?? []).map((w) => w.gvid).filter((w) => typeof w == "string" && w !== ""), M = j.length > 0 ? j : T.defaultGvid ? [T.defaultGvid] : [], K = ((B = t.variants) == null ? void 0 : B[h.role]) ?? T.defaultGvid ?? j[0];
73
+ if (!K || !M.includes(K)) {
74
+ const w = (N = t.variants) == null ? void 0 : N[h.role];
75
+ throw new S(
76
76
  "E_BUNDLE_VARIANT_NOT_FOUND",
77
- q.length === 0 ? `bundle ${e.id} role "${m.role}": alternative ${_.productId} publishes no variant — nothing can render this slot (catalog data is incomplete).` : `bundle ${e.id} role "${m.role}" (${_.productId}) has no variant "${w}". Variants: [${q.join(", ")}] — pass variants: { ${m.role}: "${q[0]}" }.`,
77
+ M.length === 0 ? `bundle ${e.id} role "${h.role}": alternative ${T.productId} publishes no variant — nothing can render this slot (catalog data is incomplete).` : `bundle ${e.id} role "${h.role}" (${T.productId}) has no variant "${w}". Variants: [${M.join(", ")}] — pass variants: { ${h.role}: "${M[0]}" }.`,
78
78
  {
79
79
  productId: e.id,
80
- role: m.role,
81
- memberProductId: _.productId,
80
+ role: h.role,
81
+ memberProductId: T.productId,
82
82
  requested: w,
83
- validNames: q,
84
- docSlug: G
83
+ validNames: M,
84
+ docSlug: W
85
85
  }
86
86
  );
87
87
  }
88
- s[m.role] = M, o[m.role] = ((V = (D = _.variants) == null ? void 0 : D.find((w) => w.gvid === M)) == null ? void 0 : V.gvidForMockup) || M;
89
- const ie = l.filter(
90
- (w) => w.role === m.role && w.memberProductId === _.productId && typeof w.key == "string" && w.key !== "" && Et(w)
88
+ s[h.role] = K, o[h.role] = ((F = (_ = T.variants) == null ? void 0 : _.find((w) => w.gvid === K)) == null ? void 0 : F.gvidForMockup) || K;
89
+ const X = l.filter(
90
+ (w) => w.role === h.role && w.memberProductId === T.productId && typeof w.key == "string" && w.key !== "" && $t(w)
91
91
  ).map((w) => ({
92
92
  key: w.key,
93
- role: m.role,
93
+ role: h.role,
94
94
  label: w.label,
95
- memberProductId: _.productId,
95
+ memberProductId: T.productId,
96
96
  width: w.width,
97
97
  height: w.height,
98
98
  aspectRatio: w.width / w.height
99
99
  }));
100
- u.push({
101
- role: m.role,
102
- required: m.required !== !1,
103
- alternatives: R,
104
- pick: _.productId,
105
- variantId: M,
106
- variantChoices: q.map((w) => ({ gvid: w, label: kt(_, w) })),
107
- placements: ie
100
+ d.push({
101
+ role: h.role,
102
+ required: h.required !== !1,
103
+ alternatives: $,
104
+ pick: T.productId,
105
+ variantId: K,
106
+ variantChoices: M.map((w) => ({ gvid: w, label: Ct(T, w) })),
107
+ placements: X
108
108
  });
109
109
  }
110
- const a = new Set(u.flatMap((m) => m.placements.map((R) => R.key))), h = new Map(u.flatMap((m) => m.placements.map((R) => [R.key, R]))), p = [];
111
- for (const m of l) {
112
- if (typeof m.key != "string" || !a.has(m.key)) continue;
113
- const R = h.get(m.key);
114
- R && !p.includes(R) && p.push(R);
110
+ const a = new Set(d.flatMap((h) => h.placements.map(($) => $.key))), u = new Map(d.flatMap((h) => h.placements.map(($) => [$.key, $]))), c = [];
111
+ for (const h of l) {
112
+ if (typeof h.key != "string" || !a.has(h.key)) continue;
113
+ const $ = u.get(h.key);
114
+ $ && !c.includes($) && c.push($);
115
115
  }
116
- const b = p.map((m) => m.key);
117
- let k;
116
+ const b = c.map((h) => h.key);
117
+ let x;
118
118
  if (t.placement !== void 0) {
119
- if (!ye(t.placement))
120
- throw new I(
119
+ if (!Ee(t.placement))
120
+ throw new S(
121
121
  "E_BUNDLE_ROLE_REQUIRED",
122
122
  `placement "${t.placement}" names no role — on bundle ${e.id} a placement is addressed by its role-scoped key. Keys: [${b.join(", ")}].`,
123
- { productId: e.id, requested: t.placement, validNames: b, docSlug: G }
123
+ { productId: e.id, requested: t.placement, validNames: b, docSlug: W }
124
124
  );
125
- if (k = p.find((m) => m.key === t.placement), !k)
126
- throw new I(
125
+ if (x = c.find((h) => h.key === t.placement), !x)
126
+ throw new S(
127
127
  "E_PRODUCT_NOT_RENDERABLE",
128
128
  `bundle ${e.id} has no renderable placement "${t.placement}" for picks ${JSON.stringify(i)}. Keys: [${b.join(", ")}].`,
129
- { productId: e.id, requested: t.placement, picks: i, validNames: b, docSlug: G }
129
+ { productId: e.id, requested: t.placement, picks: i, validNames: b, docSlug: W }
130
130
  );
131
131
  } else
132
- k = p[0];
133
- if (!k)
134
- throw new I(
132
+ x = c[0];
133
+ if (!x)
134
+ throw new S(
135
135
  "E_PRODUCT_NOT_RENDERABLE",
136
136
  `bundle ${e.id} has no renderable image placement for picks ${JSON.stringify(i)} (a role-scoped, non-color placement with width/height). The catalog payload may be incomplete — fetch it via getProduct(), not a search hit.`,
137
- { productId: e.id, picks: i, docSlug: G }
137
+ { productId: e.id, picks: i, docSlug: W }
138
138
  );
139
- const d = e.mockups ?? [], v = d.filter(
140
- (m) => !m.picks || Object.entries(m.picks).every(([R, N]) => i[R] === N)
141
- ), g = (v.length > 0 ? v : d).map((m) => m.id);
142
- if (g.length === 0)
143
- throw new I(
139
+ const m = e.mockups ?? [], E = m.filter(
140
+ (h) => !h.picks || Object.entries(h.picks).every(([$, V]) => i[$] === V)
141
+ ), y = (E.length > 0 ? E : m).map((h) => h.id);
142
+ if (y.length === 0)
143
+ throw new S(
144
144
  "E_PRODUCT_NOT_RENDERABLE",
145
145
  `bundle ${e.id} has no mockup scenes — nothing to render a preview into.`,
146
- { productId: e.id, docSlug: G }
146
+ { productId: e.id, docSlug: W }
147
147
  );
148
- const f = (e.requiredPlacements ?? []).filter((m) => typeof m.key == "string" && m.key !== "" && a.has(m.key)).map((m) => ({ label: m.key, key: m.key, type: m.type, autoFilledByVariant: m.autoFilledByVariant }));
148
+ const p = (e.requiredPlacements ?? []).filter((h) => typeof h.key == "string" && h.key !== "" && a.has(h.key)).map((h) => ({ label: h.key, key: h.key, type: h.type, autoFilledByVariant: h.autoFilledByVariant }));
149
149
  return {
150
150
  kind: "bundle",
151
151
  product: {
152
152
  productId: e.id,
153
- mockupIds: g,
153
+ mockupIds: y,
154
154
  picks: i,
155
155
  variants: s,
156
156
  placements: b,
157
- mockups: d,
158
- ...f.length > 0 ? { requiredPlacements: f } : {},
157
+ mockups: m,
158
+ ...p.length > 0 ? { requiredPlacements: p } : {},
159
159
  ...typeof t.width == "number" ? { width: t.width } : {}
160
160
  },
161
161
  picks: i,
162
162
  variants: s,
163
- variantToken: wt(o),
164
- roles: u,
165
- placement: k,
166
- placements: p,
163
+ variantToken: Ot(o),
164
+ roles: d,
165
+ placement: x,
166
+ placements: c,
167
167
  placementKeys: b,
168
168
  roleNames: r,
169
- primaryMockupId: g[0]
169
+ primaryMockupId: y[0]
170
170
  };
171
171
  }
172
- const Rt = "[RealtimeEmbed]";
173
- function Te(e) {
172
+ const Nt = "[RealtimeEmbed]";
173
+ function pe(e) {
174
174
  var r, i;
175
175
  if ((r = e == null ? void 0 : e.requiredPlacements) != null && r.length)
176
176
  return e.requiredPlacements.filter((s) => !s.autoFilledByVariant).map((s) => s.label);
@@ -179,21 +179,21 @@ function Te(e) {
179
179
  );
180
180
  return !!(e != null && e.variantId) || t.size > 1 ? [] : (e == null ? void 0 : e.placements) ?? [];
181
181
  }
182
- function xt(e) {
182
+ function _t(e) {
183
183
  return !!(e != null && e.picks) || !!(e != null && e.variants);
184
184
  }
185
- function It(e) {
185
+ function Tt(e) {
186
186
  const t = /* @__PURE__ */ new Set();
187
187
  for (const n of e.placements ?? []) {
188
- const r = ye(n);
188
+ const r = Ee(n);
189
189
  r && t.add(r.role);
190
190
  }
191
191
  for (const n of Object.keys(e.picks ?? {})) t.add(n);
192
192
  for (const n of Object.keys(e.variants ?? {})) t.add(n);
193
193
  return [...t];
194
194
  }
195
- function Ae({ shop: e, product: t, design: n, hasGrant: r }) {
196
- var d, v;
195
+ function Le({ shop: e, product: t, design: n, hasGrant: r }) {
196
+ var m, E;
197
197
  const i = [];
198
198
  if (e || i.push({
199
199
  severity: "error",
@@ -203,67 +203,89 @@ function Ae({ shop: e, product: t, design: n, hasGrant: r }) {
203
203
  severity: "error",
204
204
  issue: "missing-grant",
205
205
  message: "no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) or `grant`. Without it the session can never authorize and no mockup renders."
206
- }), (d = t == null ? void 0 : t.mockupIds) != null && d.length || i.push({
206
+ }), (m = t == null ? void 0 : t.mockupIds) != null && m.length || i.push({
207
207
  severity: "error",
208
208
  issue: "empty-mockup-ids",
209
209
  message: 'product.mockupIds is empty — pass the catalog scene codes (product.mockups[].id) you want rendered, e.g. ["FV1qjO"].'
210
210
  }), t != null && t.options)
211
211
  try {
212
- at(t);
213
- } catch (g) {
212
+ ft(t);
213
+ } catch (y) {
214
214
  i.push({
215
215
  severity: "error",
216
216
  issue: "variant-required",
217
- message: g instanceof Error ? g.message : String(g)
217
+ message: y instanceof Error ? y.message : String(y)
218
218
  });
219
219
  }
220
- const s = n.toJSON(), o = s.artboards.map((g) => g.name), l = xt(t);
221
- let u = [];
220
+ const s = n.toJSON(), o = s.artboards.map((y) => y.name), l = _t(t);
221
+ let d = [];
222
222
  if (l) {
223
- const g = t.placements ?? [];
224
- u = o.filter((E) => !ye(E)), u.length > 0 && i.push({
223
+ const y = t.placements ?? [];
224
+ d = o.filter((v) => !Ee(v)), d.length > 0 && i.push({
225
225
  severity: "error",
226
226
  issue: "bundle-role-required",
227
- message: `product ${t.productId} is a bundle, but the design's artboard(s) [${u.join(", ")}] name no role. On a bundle every placement is addressed by its role-scoped key (<role>.<key>)${g.length ? ` — keys: [${g.join(", ")}]` : ""}. Seed the design from bundleToRenderConfig(product).placement.key, not from a bare label.`
227
+ message: `product ${t.productId} is a bundle, but the design's artboard(s) [${d.join(", ")}] name no role. On a bundle every placement is addressed by its role-scoped key (<role>.<key>)${y.length ? ` — keys: [${y.join(", ")}]` : ""}. Seed the design from bundleToRenderConfig(product).placement.key, not from a bare label.`
228
228
  }), t.variantId && i.push({
229
229
  severity: "error",
230
230
  issue: "bundle-role-required",
231
231
  message: `product ${t.productId} is a bundle, but product.variantId ("${t.variantId}") names no slot — the server refuses it (E_BUNDLE_ROLE_REQUIRED). Name the variant per role instead: product.variants = { <role>: <gvid> } (bundleToRenderConfig fills it), and leave variantId unset.`
232
232
  });
233
- const S = It(t).filter((E) => {
234
- var A;
235
- return !((A = t.variants) != null && A[E]);
233
+ const O = Tt(t).filter((v) => {
234
+ var B;
235
+ return !((B = t.variants) != null && B[v]);
236
236
  });
237
- S.length > 0 && i.push({
237
+ O.length > 0 && i.push({
238
238
  severity: "error",
239
239
  issue: "bundle-variant-required",
240
- message: `product ${t.productId} is a bundle, but role(s) [${S.join(", ")}] have no entry in product.variants (${JSON.stringify(t.variants ?? {})}). Every role needs a variant — the server keys the render on the per-role set. Build the product with bundleToRenderConfig(product, { picks, variants }), which fills each slot's default.`
240
+ message: `product ${t.productId} is a bundle, but role(s) [${O.join(", ")}] have no entry in product.variants (${JSON.stringify(t.variants ?? {})}). Every role needs a variant — the server keys the render on the per-role set. Build the product with bundleToRenderConfig(product, { picks, variants }), which fills each slot's default.`
241
241
  });
242
242
  }
243
- const a = Te(t), h = a.filter((g) => !o.includes(g));
244
- a.length > 1 && o.length > 1 && h.length > 0 && i.push({
245
- severity: "error",
246
- issue: "multi-placement",
247
- message: `product ${t.productId} requires placements [${a.join(", ")}] but the design only has artboards [${o.join(", ")}] — missing [${h.join(", ")}]. The render would time out waiting for the missing canvas_states. Add each missing placement to the seed: design(…).artboard('` + h[0] + "', { width, height })… (ADR-0088), or use the eject path — see https://developers.snowcone.app/embed-mode#eject."
243
+ const a = pe(t), u = a.filter((y) => !o.includes(y));
244
+ a.length > 1 && o.length > 1 && u.length > 0 && i.push({
245
+ severity: "warn",
246
+ issue: "placements-inherit-base",
247
+ message: `product ${t.productId} requires placements [${a.join(", ")}]; the design authors [${o.join(", ")}], so [${u.join(", ")}] inherit the base artboard "${o[0]}" (re-fit per placement, ADR-0101). Intended? Otherwise split them: design(…).artboard('` + u[0] + "', { width, height })… or usePlacements().split('" + u[0] + "') at runtime."
248
248
  });
249
- const p = (v = t == null ? void 0 : t.placements) != null && v.length ? o.filter((g) => !t.placements.includes(g) && !u.includes(g)) : [];
250
- p.length > 0 && i.push({
249
+ const c = (E = t == null ? void 0 : t.placements) != null && E.length ? o.filter((y) => !t.placements.includes(y) && !d.includes(y)) : [];
250
+ c.length > 0 && i.push({
251
251
  severity: "error",
252
252
  issue: "placement-mismatch",
253
- message: `the design's artboard(s) [${p.join(", ")}] are not in product.placements [${t.placements.join(", ")}]. Every artboard name must equal a real product placement label (renderState targets placements by that name), or the server renders a blank mockup. Fix the \`name\` passed to design({ name }) / design().artboard(name, …).`
253
+ message: `the design's artboard(s) [${c.join(", ")}] are not in product.placements [${t.placements.join(", ")}]. Every artboard name must equal a real product placement label (renderState targets placements by that name), or the server renders a blank mockup. Fix the \`name\` passed to design({ name }) / design().artboard(name, …).`
254
254
  });
255
- const b = s.elements.map((g) => g.name).filter((g) => !!g), k = b.filter((g, f) => b.indexOf(g) !== f);
256
- return k.length && i.push({
255
+ const b = s.elements.map((y) => y.name).filter((y) => !!y), x = b.filter((y, p) => b.indexOf(y) !== p);
256
+ return x.length && i.push({
257
257
  severity: "warn",
258
258
  issue: "duplicate-layer-names",
259
- message: `duplicate layer name(s) [${[...new Set(k)].join(", ")}] — useTextBinding(name) / useImageBinding(name) bind to the FIRST match, so a duplicate name makes a control edit the wrong layer. Keep names unique.`
259
+ message: `duplicate layer name(s) [${[...new Set(x)].join(", ")}] — useTextBinding(name) / useImageBinding(name) bind to the FIRST match, so a duplicate name makes a control edit the wrong layer. Keep names unique.`
260
260
  }), i;
261
261
  }
262
- function St(e) {
263
- for (const t of Ae(e))
264
- (t.severity === "error" && t.issue !== "placement-mismatch" ? console.error : console.warn)(`${Rt} ${t.message}`);
262
+ function At(e) {
263
+ for (const t of Le(e))
264
+ (t.severity === "error" && t.issue !== "placement-mismatch" ? console.error : console.warn)(`${Nt} ${t.message}`);
265
+ }
266
+ function Fe(e, t) {
267
+ const n = new Set(e);
268
+ if (t.length === 0)
269
+ return e.map((i) => ({ label: i, inherited: !1 }));
270
+ const r = t.map((i) => ({
271
+ label: i,
272
+ inherited: !n.has(i)
273
+ }));
274
+ for (const i of e)
275
+ t.includes(i) || r.push({ label: i, inherited: !1 });
276
+ return r;
277
+ }
278
+ function Ve(e, t) {
279
+ const n = e.artboards ?? [], r = n[0];
280
+ if (!r || t.length === 0) return e;
281
+ const i = n.map((d) => typeof d.name == "string" ? d.name : ""), s = new Map(n.map((d, a) => [i[a], d])), o = Fe(i, t);
282
+ if (o.every((d) => !d.inherited)) return e;
283
+ const l = o.map(
284
+ (d) => d.inherited ? { ...r, name: d.label } : s.get(d.label)
285
+ );
286
+ return { ...e, artboards: l };
265
287
  }
266
- function De({ registry: e, store: t, product: n }) {
288
+ function Pe({ registry: e, store: t, product: n }) {
267
289
  const r = [], i = e.getParts(), s = e.getTextFields(), o = e.requiresCanvasPartNames();
268
290
  o.length > 0 && !e.hasCanvas() && r.push({
269
291
  code: "A_REQUIRES_CANVAS",
@@ -271,48 +293,48 @@ function De({ registry: e, store: t, product: n }) {
271
293
  message: `${o.join(", ")} ${o.length === 1 ? "is" : "are"} mounted with no <Editor.Canvas> under this Root — they operate on the editable artboard (selection, editor commands) and throw E_REQUIRES_CANVAS.`,
272
294
  fix: `Mount <Editor.Canvas/> under the same <Editor.Root>, or remove ${o.join(", ")}. Canvas-free parts: Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.`
273
295
  });
274
- const l = i.filter((d) => d.name === "Editor.Canvas").some((d) => d.meta.floatingToolbar !== !1);
296
+ const l = i.filter((m) => m.name === "Editor.Canvas").some((m) => m.meta.floatingToolbar !== !1);
275
297
  e.hasDockedControls() && l && r.push({
276
298
  code: "A_CONTROLS_INERT",
277
299
  severity: "warn",
278
300
  message: "a docked <Editor.Controls> is mounted while <Editor.Canvas> still has floatingToolbar={true} (the default) — both contextual zones are armed, and the floating toolbar is suppressed only as a side effect of the docked Controls being mounted this frame (it silently reappears when the Controls unmounts).",
279
301
  fix: 'Declare contextual-zone ownership in the type surface: pass floatingToolbar={false} on <Editor.Canvas> when a <Editor.Controls placement="docked"> owns the zone.'
280
302
  });
281
- const u = (n == null ? void 0 : n.mockupIds) ?? [];
282
- if (u.length > 1) {
283
- const d = i.filter((v) => v.name === "Editor.Preview" && v.meta.mockupId === void 0);
284
- d.length > 0 && r.push({
303
+ const d = (n == null ? void 0 : n.mockupIds) ?? [];
304
+ if (d.length > 1) {
305
+ const m = i.filter((E) => E.name === "Editor.Preview" && E.meta.mockupId === void 0);
306
+ m.length > 0 && r.push({
285
307
  code: "A_PREVIEW_AMBIGUOUS",
286
308
  severity: "warn",
287
- message: `${d.length} <Editor.Preview> part${d.length === 1 ? " has" : "s have"} no mockupId while the product renders ${u.length} mockup scenes [${u.join(", ")}] — each shows whichever scene renders first, an ambiguous fan-out.`,
288
- fix: `Pin each <Editor.Preview> to a scene: mockupId="${u[0]}" (one of product.mockupIds).`
309
+ message: `${m.length} <Editor.Preview> part${m.length === 1 ? " has" : "s have"} no mockupId while the product renders ${d.length} mockup scenes [${d.join(", ")}] — each shows whichever scene renders first, an ambiguous fan-out.`,
310
+ fix: `Pin each <Editor.Preview> to a scene: mockupId="${d[0]}" (one of product.mockupIds).`
289
311
  });
290
312
  }
291
- const a = i.some((d) => d.name === "Editor.Buy");
313
+ const a = i.some((m) => m.name === "Editor.Buy");
292
314
  if (s.length > 0 && !a) {
293
- const d = s.map((v) => v.name);
315
+ const m = s.map((E) => E.name);
294
316
  r.push({
295
317
  code: "A_NO_BUY",
296
318
  severity: "info",
297
- message: `<Editor.TextField> parts are mounted (layers [${d.join(", ")}]) but no <Editor.Buy> — personalization has no commerce gate, so nothing enforces completeness (C2/C3) before the design is bought.`,
319
+ message: `<Editor.TextField> parts are mounted (layers [${m.join(", ")}]) but no <Editor.Buy> — personalization has no commerce gate, so nothing enforces completeness (C2/C3) before the design is bought.`,
298
320
  fix: "Mount <Editor.Buy onAddToCart={…}/> under the same <Editor.Root> (it assembles the payload and gates on completeness), or ignore if this composition is deliberately non-commerce."
299
321
  });
300
322
  }
301
- const h = [];
302
- for (const d of s)
303
- t.layerKindOf(d.name) === void 0 ? r.push({
323
+ const u = [];
324
+ for (const m of s)
325
+ t.layerKindOf(m.name) === void 0 ? r.push({
304
326
  code: "A_LAYER_UNMATCHED",
305
327
  severity: "error",
306
- message: `<Editor.TextField layer={design.layer("${d.name}")}> matches zero elements in the current design state — the layer was removed or renamed after the field mounted, so the binding is dead and writes will fail. Bindable layers now: ${JSON.stringify(t.bindableLayerNames())}.`,
307
- fix: `Restore a text layer named "${d.name}" to the design, or bind the field to an existing layer: layer={design.layer(<one of ${JSON.stringify(t.bindableLayerNames())}>)}.`
308
- }) : h.push(d);
309
- const p = h.filter((d) => !d.optional);
310
- if (p.length > 0 && p.every((d) => t.textOf(d.name) === t.seedTextOf(d.name))) {
311
- const d = p.map((v) => v.name);
328
+ message: `<Editor.TextField layer={design.layer("${m.name}")}> matches zero elements in the current design state — the layer was removed or renamed after the field mounted, so the binding is dead and writes will fail. Bindable layers now: ${JSON.stringify(t.bindableLayerNames())}.`,
329
+ fix: `Restore a text layer named "${m.name}" to the design, or bind the field to an existing layer: layer={design.layer(<one of ${JSON.stringify(t.bindableLayerNames())}>)}.`
330
+ }) : u.push(m);
331
+ const c = u.filter((m) => !m.optional);
332
+ if (c.length > 0 && c.every((m) => t.textOf(m.name) === t.seedTextOf(m.name))) {
333
+ const m = c.map((E) => E.name);
312
334
  r.push({
313
335
  code: "A_TEXT_AT_SEED",
314
336
  severity: "info",
315
- message: `every required <Editor.TextField> still equals its seed value (layers [${d.join(", ")}]) — <Editor.Buy>'s completeness rule C3 gates checkout until the shopper's text differs from the seed (placeholder text must not be bought).`,
337
+ message: `every required <Editor.TextField> still equals its seed value (layers [${m.join(", ")}]) — <Editor.Buy>'s completeness rule C3 gates checkout until the shopper's text differs from the seed (placeholder text must not be bought).`,
316
338
  fix: "Nothing to change for a fresh mount — this clears when the shopper edits the fields. For a field that should NOT gate Buy, pass optional on that <Editor.TextField>."
317
339
  });
318
340
  }
@@ -323,40 +345,40 @@ function De({ registry: e, store: t, product: n }) {
323
345
  fix: "Seed content on the builder passed to <Editor.Root design={…}> — design({…}).text(…)/.background(…)/.shape(…) — or add elements through <Editor.Add>."
324
346
  });
325
347
  const b = /* @__PURE__ */ new Map();
326
- for (const d of i) b.set(d.name, (b.get(d.name) ?? 0) + 1);
327
- const k = [...b.entries()].map(([d, v]) => ({ name: d, count: v })).sort((d, v) => d.name.localeCompare(v.name));
328
- return { findings: r, parts: k };
348
+ for (const m of i) b.set(m.name, (b.get(m.name) ?? 0) + 1);
349
+ const x = [...b.entries()].map(([m, E]) => ({ name: m, count: E })).sort((m, E) => m.name.localeCompare(E.name));
350
+ return { findings: r, parts: x };
329
351
  }
330
- const ee = [];
331
- function Ct(e) {
332
- return ee.push(e), () => {
333
- const t = ee.indexOf(e);
334
- t !== -1 && ee.splice(t, 1);
352
+ const ie = [];
353
+ function Dt(e) {
354
+ return ie.push(e), () => {
355
+ const t = ie.indexOf(e);
356
+ t !== -1 && ie.splice(t, 1);
335
357
  };
336
358
  }
337
- function bn() {
338
- const e = ee[ee.length - 1];
359
+ function $n() {
360
+ const e = ie[ie.length - 1];
339
361
  if (!e)
340
- throw new I(
362
+ throw new S(
341
363
  "E_AUDIT_NO_ROOT",
342
364
  "auditEditor() found no mounted <Editor.Root>. Mount a Root first — or, to audit at mount time, pass onAudit on the Root: <Editor.Root onAudit={(report) => …}>.",
343
365
  { docSlug: "embed-mode" }
344
366
  );
345
367
  return e.compute();
346
368
  }
347
- const Be = 8e3;
348
- function $t(e) {
349
- return `[RealtimeEmbed] No mockup after ${Math.round(Be / 1e3)}s. Common causes: a variant product missing \`variantId\` (pass \`product.options\` so the embed can flag it up front), a multi-placement product (the server waits for every required placement but <RealtimeEmbed> sends only "${e}" — pass \`product.requiredPlacements\` so this is flagged at mount; such products need the eject path), an unreachable or non-public asset URL in the design, or the placement "${e}" not existing on the product. The render may still arrive — this is a heads-up, not a failure.`;
369
+ const je = 8e3;
370
+ function Bt(e) {
371
+ return `[RealtimeEmbed] No mockup after ${Math.round(je / 1e3)}s. Common causes: a variant product missing \`variantId\` (pass \`product.options\` so the embed can flag it up front), a multi-placement product (the server waits for every required placement but <RealtimeEmbed> sends only "${e}" — pass \`product.requiredPlacements\` so this is flagged at mount; such products need the eject path), an unreachable or non-public asset URL in the design, or the placement "${e}" not existing on the product. The render may still arrive — this is a heads-up, not a failure.`;
350
372
  }
351
- function Ot(e) {
373
+ function Ut(e) {
352
374
  if ("grantUrl" in e && e.grantUrl)
353
375
  return { grantUrl: e.grantUrl };
354
376
  const t = e.grant;
355
377
  return typeof t == "function" ? { getToken: t } : { getToken: () => Promise.resolve(t) };
356
378
  }
357
- function Le({ error: e, onRetry: t }) {
358
- const n = Ce(e) ? e.code : "EDITOR_ERROR";
359
- return /* @__PURE__ */ F(
379
+ function Me({ error: e, onRetry: t }) {
380
+ const n = Te(e) ? e.code : "EDITOR_ERROR";
381
+ return /* @__PURE__ */ U(
360
382
  "div",
361
383
  {
362
384
  "data-sc-part": "error",
@@ -372,12 +394,12 @@ function Le({ error: e, onRetry: t }) {
372
394
  lineHeight: 1.5
373
395
  },
374
396
  children: [
375
- /* @__PURE__ */ F("p", { style: { margin: 0, fontWeight: 700 }, children: [
397
+ /* @__PURE__ */ U("p", { style: { margin: 0, fontWeight: 700 }, children: [
376
398
  "Editor failed: ",
377
399
  n
378
400
  ] }),
379
- /* @__PURE__ */ c("p", { style: { margin: "4px 0 0" }, children: e.message }),
380
- t ? /* @__PURE__ */ c(
401
+ /* @__PURE__ */ g("p", { style: { margin: "4px 0 0" }, children: e.message }),
402
+ t ? /* @__PURE__ */ g(
381
403
  "button",
382
404
  {
383
405
  type: "button",
@@ -401,7 +423,7 @@ function Le({ error: e, onRetry: t }) {
401
423
  }
402
424
  );
403
425
  }
404
- class Nt extends st {
426
+ class Lt extends mt {
405
427
  constructor() {
406
428
  super(...arguments), this.state = { caught: null };
407
429
  }
@@ -410,20 +432,20 @@ class Nt extends st {
410
432
  }
411
433
  componentDidCatch(t) {
412
434
  var n;
413
- mt(t), typeof P < "u" && ((n = P.env) == null ? void 0 : n.NODE_ENV) !== "production" && console.error("[Editor.Root] contained a composition error:", t);
435
+ vt(t), typeof z < "u" && ((n = z.env) == null ? void 0 : n.NODE_ENV) !== "production" && console.error("[Editor.Root] contained a composition error:", t);
414
436
  }
415
437
  render() {
416
- return this.state.caught ? /* @__PURE__ */ c(Le, { error: this.state.caught }) : this.props.children;
438
+ return this.state.caught ? /* @__PURE__ */ g(Me, { error: this.state.caught }) : this.props.children;
417
439
  }
418
440
  }
419
- function _t({ reportedError: e, onRetry: t, children: n }) {
441
+ function Ft({ reportedError: e, onRetry: t, children: n }) {
420
442
  if (e) {
421
- const r = Ce(e) && e.code === "E_CHUNK_LOAD_FAILED";
422
- return /* @__PURE__ */ c(Le, { error: e, onRetry: r ? t : void 0 });
443
+ const r = Te(e) && e.code === "E_CHUNK_LOAD_FAILED";
444
+ return /* @__PURE__ */ g(Me, { error: e, onRetry: r ? t : void 0 });
423
445
  }
424
- return /* @__PURE__ */ c(Nt, { reportedError: null, onRetry: t, children: n });
446
+ return /* @__PURE__ */ g(Lt, { reportedError: null, onRetry: t, children: n });
425
447
  }
426
- function Tt(e) {
448
+ function Vt(e) {
427
449
  const {
428
450
  shop: t,
429
451
  product: n,
@@ -432,251 +454,284 @@ function Tt(e) {
432
454
  onMockups: s,
433
455
  onRenderError: o,
434
456
  onIssue: l,
435
- wsUrl: u,
457
+ wsUrl: d,
436
458
  services: a,
437
- children: h,
438
- internals: p,
459
+ children: u,
460
+ internals: c,
439
461
  recordAudit: b,
440
- __validation: k = "throw"
441
- } = e, d = L(() => r.toJSON().activeArtboard, [r]), v = L(() => r.toJSON().artboards.map((y) => y.name), [r]), [g, f] = T(null), S = g && g.design === r ? g.label : d, E = L(
442
- () => (y) => {
443
- if (!v.includes(y))
444
- throw new I(
462
+ __validation: x = "throw"
463
+ } = e, m = A(() => r.toJSON().activeArtboard, [r]), y = J(c.store.subscribe, c.store.getState, c.store.getState).artboards.map((f) => f.name).join("\0"), p = A(
464
+ () => y ? y.split("\0") : [],
465
+ [y]
466
+ ), O = JSON.stringify(pe(n)), v = A(() => JSON.parse(O), [O]), [B, N] = D(null), _ = B && B.design === r ? B.label : m, F = A(
467
+ () => (f) => {
468
+ const k = [.../* @__PURE__ */ new Set([...v, ...p])];
469
+ if (!k.includes(f))
470
+ throw new S(
445
471
  "E_UNKNOWN_PLACEMENT",
446
- `no placement "${y}" in this design — its artboards are ${JSON.stringify(v)}. Add it to the seed with design(…).artboard('${y}', { width, height }) (ADR-0088).`,
447
- { placement: y, validNames: v, docSlug: "embed-mode" }
472
+ `no placement "${f}" — the product's placements are ${JSON.stringify(v)} and the design's artboards are ${JSON.stringify(p)} (ADR-0088 / ADR-0101).`,
473
+ { placement: f, validNames: k, docSlug: "embed-mode" }
448
474
  );
449
- f({ design: r, label: y });
475
+ const R = p[0] ?? f;
476
+ N({ design: r, label: p.includes(f) ? f : R });
477
+ },
478
+ [r, p, v]
479
+ ), h = C(null), $ = A(
480
+ () => (f) => {
481
+ var k;
482
+ if (!v.includes(f) && !p.includes(f))
483
+ throw new S(
484
+ "E_UNKNOWN_PLACEMENT",
485
+ `cannot split "${f}" — the product's placements are ${JSON.stringify(v)} (ADR-0101).`,
486
+ { placement: f, validNames: v, docSlug: "embed-mode" }
487
+ );
488
+ if (!p.includes(f)) {
489
+ const R = c.registry.getCanvasBridge();
490
+ R ? R.splitArtboard(f) : (c.store.splitArtboard(f), (k = h.current) == null || k.call(h, ee(c.store.getState())));
491
+ }
492
+ N({ design: r, label: f });
450
493
  },
451
- [r, v]
452
- ), A = L(() => {
453
- const y = r.toJSON().artboards[0];
454
- if (y)
494
+ [r, p, v, c]
495
+ ), V = A(
496
+ () => (f) => {
497
+ var P;
498
+ const k = p[0];
499
+ if (f === k)
500
+ throw new S(
501
+ "E_LINK_BASE",
502
+ `"${f}" 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(p)}.`,
503
+ { artboardName: f, validNames: p.slice(1), docSlug: "embed-mode" }
504
+ );
505
+ if (!p.includes(f)) return;
506
+ const R = c.registry.getCanvasBridge();
507
+ R ? R.removeArtboard(f) : (c.store.removeArtboard(f), (P = h.current) == null || P.call(h, ee(c.store.getState()))), _ === f && k && N({ design: r, label: k });
508
+ },
509
+ [r, p, c, _]
510
+ ), T = A(() => {
511
+ const f = r.toJSON().artboards[0];
512
+ if (f)
455
513
  return {
456
- name: y.name,
457
- width: y.width,
458
- height: y.height,
459
- ...y.backgroundColor ? { backgroundColor: y.backgroundColor } : {}
514
+ name: f.name,
515
+ width: f.width,
516
+ height: f.height,
517
+ ...f.backgroundColor ? { backgroundColor: f.backgroundColor } : {}
460
518
  };
461
519
  }, [r]);
462
520
  J(
463
- p.commerce.subscribe,
464
- p.commerce.getVersion,
465
- p.commerce.getVersion
521
+ c.commerce.subscribe,
522
+ c.commerce.getVersion,
523
+ c.commerce.getVersion
466
524
  );
467
- const C = p.commerce.renderVariantId(), D = ft(C ?? n.variantId ?? n.defaultGvid), V = L(() => {
468
- if (!D) return null;
469
- const y = r.toJSON().artboards[0];
470
- return ht(D, y) ?? null;
471
- }, [D, r]), m = O(s), R = O(o), N = O(l);
472
- m.current = s, R.current = o, N.current = l;
473
- const [_, Y] = T([]), [q, M] = T(!0), [ie, w] = T(null), le = !!("grantUrl" in e && e.grantUrl || "grant" in e && e.grant), ce = Ot(e), qe = "grantUrl" in ce ? ce.grantUrl : "getToken", be = `${n.productId}|${n.mockupIds.join(",")}|${n.variantId ?? ""}`, X = n.picks || n.variants ? JSON.stringify([n.picks ?? null, n.variants ?? null]) : "", H = `${t}|${be}|${X}|${d}|${le}`, ue = L(() => {
474
- var B;
475
- const y = Ae({ shop: t, product: n, design: r, hasGrant: le });
476
- if (k !== "throw") return y;
477
- const $ = y.find((z) => z.severity === "error");
478
- if ($)
479
- throw new I("E_EMBED_CONFIG", $.message, {
480
- issue: $.issue,
525
+ const j = c.commerce.renderVariantId(), M = Et(j ?? n.variantId ?? n.defaultGvid), K = A(() => {
526
+ if (!M) return null;
527
+ const f = r.toJSON().artboards, k = f.find((R) => R.name === _) ?? f[0];
528
+ return kt(M, k) ?? null;
529
+ }, [M, r, _]), X = C(s), w = C(o), Q = C(l);
530
+ X.current = s, w.current = o, Q.current = l;
531
+ const [ke, He] = D([]), [de, ne] = D(!0), [xe, le] = D(null), fe = !!("grantUrl" in e && e.grantUrl || "grant" in e && e.grant), he = Ut(e), Je = "grantUrl" in he ? he.grantUrl : "getToken", Se = `${n.productId}|${n.mockupIds.join(",")}|${n.variantId ?? ""}`, re = n.picks || n.variants ? JSON.stringify([n.picks ?? null, n.variants ?? null]) : "", Y = `${t}|${Se}|${re}|${m}|${fe}`, ge = A(() => {
532
+ var R;
533
+ const f = Le({ shop: t, product: n, design: r, hasGrant: fe });
534
+ if (x !== "throw") return f;
535
+ const k = f.find((P) => P.severity === "error");
536
+ if (k)
537
+ throw new S("E_EMBED_CONFIG", k.message, {
538
+ issue: k.issue,
481
539
  docSlug: "embed-mode"
482
540
  });
483
- for (const z of y)
484
- typeof P < "u" && ((B = P.env) == null ? void 0 : B.NODE_ENV) !== "production" && console.warn(`[Editor.Root] ${z.message}`);
485
- return y;
486
- }, [H, k]), ve = O(null);
487
- U(() => {
488
- var y;
489
- if (ue.length !== 0 && ve.current !== H) {
490
- ve.current = H;
491
- for (const $ of ue) (y = N.current) == null || y.call(N, $);
541
+ for (const P of f)
542
+ typeof z < "u" && ((R = z.env) == null ? void 0 : R.NODE_ENV) !== "production" && console.warn(`[Editor.Root] ${P.message}`);
543
+ return f;
544
+ }, [Y, x]), Re = C(null);
545
+ L(() => {
546
+ var f;
547
+ if (ge.length !== 0 && Re.current !== Y) {
548
+ Re.current = Y;
549
+ for (const k of ge) (f = Q.current) == null || f.call(Q, k);
492
550
  }
493
- }, [ue, H]);
494
- const we = O(null);
495
- U(() => {
496
- var y;
497
- if (k === "warn" && typeof P < "u" && ((y = P.env) == null ? void 0 : y.NODE_ENV) !== "production") {
498
- if (we.current === H) return;
499
- we.current = H, St({ shop: t, product: n, design: r, hasGrant: le });
551
+ }, [ge, Y]);
552
+ const Ie = C(null);
553
+ L(() => {
554
+ var f;
555
+ if (x === "warn" && typeof z < "u" && ((f = z.env) == null ? void 0 : f.NODE_ENV) !== "production") {
556
+ if (Ie.current === Y) return;
557
+ Ie.current = Y, At({ shop: t, product: n, design: r, hasGrant: fe });
500
558
  }
501
- }, [H, k]);
502
- const se = L(
559
+ }, [Y, x]);
560
+ const ce = A(
503
561
  () => {
504
562
  try {
505
- return { session: new dt({ shop: t, product: n, wsUrl: u, ...ce }) };
506
- } catch (y) {
507
- return { error: y instanceof Error ? y.message : String(y) };
563
+ return { session: new ht({ shop: t, product: n, wsUrl: d, ...he }) };
564
+ } catch (f) {
565
+ return { error: f instanceof Error ? f.message : String(f) };
508
566
  }
509
567
  },
510
568
  // eslint-disable-next-line react-hooks/exhaustive-deps
511
- [t, be, d, u, qe]
512
- ), x = "session" in se ? se.session : null, oe = "error" in se ? se.error : null, Z = L(() => (y, $ = i) => {
513
- if (!x) return;
514
- w(null), M(!0);
515
- const B = (j) => {
516
- var Ie;
517
- const ae = j instanceof Error ? j.message : String(j);
518
- w(ae), M(!1), (Ie = R.current) == null || Ie.call(R, ae);
519
- }, z = (j, ae) => void x.renderState(j, { schemaVersion: y.schemaVersion, artboards: [ae] }, $).catch(B), pe = y.artboards ?? [];
520
- if (pe.length > 1) {
521
- for (const j of pe)
522
- z(typeof j.name == "string" && j.name ? j.name : d, j);
569
+ [t, Se, m, d, Je]
570
+ ), I = "session" in ce ? ce.session : null, ue = "error" in ce ? ce.error : null, Z = A(() => (f, k = i) => {
571
+ if (!I) return;
572
+ le(null), ne(!0);
573
+ const R = (q) => {
574
+ var Ne;
575
+ const me = q instanceof Error ? q.message : String(q);
576
+ le(me), ne(!1), (Ne = w.current) == null || Ne.call(w, me);
577
+ }, P = (q, me) => void I.renderState(q, { schemaVersion: f.schemaVersion, artboards: [me] }, k).catch(R), Ce = Ve(f, pe(n)).artboards ?? [];
578
+ if (Ce.length > 1) {
579
+ for (const q of Ce)
580
+ P(typeof q.name == "string" && q.name ? q.name : m, q);
523
581
  return;
524
582
  }
525
- const Re = Te(n), xe = pe[0];
526
- if (xe && Re.length > 1) {
527
- for (const j of Re)
528
- z(j, { ...xe, name: j });
583
+ I.renderState(m, f, k).catch(R);
584
+ }, [I, m, n, i]);
585
+ h.current = Z, L(() => {
586
+ var f;
587
+ if (ue) {
588
+ le(ue), ne(!1), (f = w.current) == null || f.call(w, ue);
529
589
  return;
530
590
  }
531
- x.renderState(d, y, $).catch(B);
532
- }, [x, d, n, i]);
533
- U(() => {
534
- var y;
535
- if (oe) {
536
- w(oe), M(!1), (y = R.current) == null || y.call(R, oe);
537
- return;
538
- }
539
- if (x)
540
- return x.onMockups(($) => {
541
- var B;
542
- Y($), M(!1), (B = m.current) == null || B.call(m, $);
543
- }), x.onError(($) => {
544
- var B;
545
- w($), M(!1), (B = R.current) == null || B.call(R, $);
546
- }), Z(r.toServerRequest()), () => x.close();
547
- }, [x, oe]);
548
- const me = O({
591
+ if (I)
592
+ return I.onMockups((k) => {
593
+ var R;
594
+ He(k), ne(!1), (R = X.current) == null || R.call(X, k);
595
+ }), I.onError((k) => {
596
+ var R;
597
+ le(k), ne(!1), (R = w.current) == null || R.call(w, k);
598
+ }), Z(r.toServerRequest()), () => I.close();
599
+ }, [I, ue]);
600
+ const ye = C({
549
601
  session: null,
550
602
  variantId: void 0
551
603
  });
552
- U(() => {
553
- if (!x || !C) return;
554
- const y = me.current, $ = y.session === x ? y.variantId : n.variantId;
555
- if (C === $) {
556
- me.current = { session: x, variantId: $ };
604
+ L(() => {
605
+ if (!I || !j) return;
606
+ const f = ye.current, k = f.session === I ? f.variantId : n.variantId;
607
+ if (j === k) {
608
+ ye.current = { session: I, variantId: k };
557
609
  return;
558
610
  }
559
- me.current = { session: x, variantId: C }, x.setProduct({ ...n, variantId: C }), Z(de(p.store.getState()));
560
- }, [x, C]);
561
- const Ee = O({ session: null, key: "" });
562
- U(() => {
563
- if (!x || !X) return;
564
- const y = Ee.current;
565
- if (y.session === x && y.key === X) return;
566
- const $ = y.session !== x;
567
- Ee.current = { session: x, key: X }, !$ && (x.setProduct(n), Z(de(p.store.getState())));
568
- }, [x, X]), U(() => {
569
- if (!q) return;
570
- const y = setTimeout(() => {
571
- var B, z;
572
- const $ = $t(d);
573
- typeof P < "u" && ((B = P.env) == null ? void 0 : B.NODE_ENV) !== "production" && console.warn($), (z = N.current) == null || z.call(N, { severity: "warn", issue: "slow-render", message: $ });
574
- }, Be);
575
- return () => clearTimeout(y);
576
- }, [q, d]);
577
- const Pe = L(
611
+ ye.current = { session: I, variantId: j }, I.setProduct({ ...n, variantId: j }), Z(ee(c.store.getState()));
612
+ }, [I, j]);
613
+ const Oe = C({ session: null, key: "" });
614
+ L(() => {
615
+ if (!I || !re) return;
616
+ const f = Oe.current;
617
+ if (f.session === I && f.key === re) return;
618
+ const k = f.session !== I;
619
+ Oe.current = { session: I, key: re }, !k && (I.setProduct(n), Z(ee(c.store.getState())));
620
+ }, [I, re]), L(() => {
621
+ if (!de) return;
622
+ const f = setTimeout(() => {
623
+ var R, P;
624
+ const k = Bt(m);
625
+ typeof z < "u" && ((R = z.env) == null ? void 0 : R.NODE_ENV) !== "production" && console.warn(k), (P = Q.current) == null || P.call(Q, { severity: "warn", issue: "slow-render", message: k });
626
+ }, je);
627
+ return () => clearTimeout(f);
628
+ }, [de, m]);
629
+ const Qe = A(
578
630
  () => ({
579
- session: x,
631
+ session: I,
580
632
  design: r,
581
633
  // The ACTIVE placement (ADR-0088): Editor.Canvas follows it as its
582
634
  // controlled artboard; single-placement designs never see it move.
583
- placement: S,
584
- placements: v,
585
- selectPlacement: E,
635
+ placement: _,
636
+ placements: p,
637
+ selectPlacement: F,
638
+ requiredPlacements: v,
639
+ splitPlacement: $,
640
+ linkPlacement: V,
586
641
  product: n,
587
- mockups: _,
588
- isRendering: q,
589
- error: ie,
642
+ mockups: ke,
643
+ isRendering: de,
644
+ error: xe,
590
645
  throttleMs: i,
591
- pieceGuides: V,
646
+ pieceGuides: K,
592
647
  pushRender: Z,
593
- stateStore: p.store
648
+ stateStore: c.store
594
649
  }),
595
- [x, r, S, v, E, n, _, q, ie, i, V, Z, p.store]
596
- ), ze = J(
597
- p.registry.subscribe,
598
- p.registry.getVersion,
599
- p.registry.getVersion
650
+ [I, r, _, p, F, v, $, V, n, ke, de, xe, i, K, Z, c.store]
651
+ ), Ye = J(
652
+ c.registry.subscribe,
653
+ c.registry.getVersion,
654
+ c.registry.getVersion
600
655
  );
601
- L(() => {
656
+ A(() => {
602
657
  b(
603
- De({ registry: p.registry, store: p.store, product: n })
604
- ), p.registry.validate();
605
- }, [p.registry, ze]);
606
- const ke = /* @__PURE__ */ c(We.Provider, { value: p, children: /* @__PURE__ */ c(Ne.Provider, { value: Pe, children: /* @__PURE__ */ c(ct.Provider, { value: p.registry, children: /* @__PURE__ */ c(
607
- ut,
658
+ Pe({ registry: c.registry, store: c.store, product: n })
659
+ ), c.registry.validate();
660
+ }, [c.registry, Ye]);
661
+ const $e = /* @__PURE__ */ g(et.Provider, { value: c, children: /* @__PURE__ */ g(Be.Provider, { value: Qe, children: /* @__PURE__ */ g(yt.Provider, { value: c.registry, children: /* @__PURE__ */ g(
662
+ bt,
608
663
  {
609
- ...A ? { initialArtboardConfig: A } : {},
610
- children: h
664
+ ...T ? { initialArtboardConfig: T } : {},
665
+ children: u
611
666
  }
612
667
  ) }) }) });
613
- return a ? /* @__PURE__ */ c(He, { services: a, children: ke }) : ke;
668
+ return a ? /* @__PURE__ */ g(tt, { services: a, children: $e }) : $e;
614
669
  }
615
- function Ue(e) {
616
- const { design: t, product: n, onAudit: r } = e, i = `${n.productId}|${n.variantId ?? ""}`, s = O(null), o = O(null), [l, u] = T(null);
670
+ function qe(e) {
671
+ const { design: t, product: n, onAudit: r } = e, i = `${n.productId}|${n.variantId ?? ""}`, s = C(null), o = C(null), [l, d] = D(null);
617
672
  (s.current === null || s.current.design !== t) && (s.current = {
618
673
  design: t,
619
674
  internals: {
620
- store: new gt(t.toJSON()),
621
- registry: new Ke()
675
+ store: new xt(t.toJSON()),
676
+ registry: new Xe()
622
677
  }
623
- }), (o.current === null || o.current.productIdentity !== i) && (o.current = { productIdentity: i, commerce: new yt(n) });
624
- const a = L(
678
+ }), (o.current === null || o.current.productIdentity !== i) && (o.current = { productIdentity: i, commerce: new St(n) });
679
+ const a = A(
625
680
  () => ({
626
681
  ...s.current.internals,
627
682
  commerce: o.current.commerce,
628
- ...Ge(u)
683
+ ...Ze(d)
629
684
  }),
630
685
  // eslint-disable-next-line react-hooks/exhaustive-deps
631
686
  [s.current.internals, o.current.commerce]
632
- ), h = O(n);
633
- h.current = n;
634
- const p = O(r);
635
- p.current = r;
636
- const b = O(null), k = K((g) => {
637
- b.current = g;
638
- }, []), d = K(
639
- () => De({
687
+ ), u = C(n);
688
+ u.current = n;
689
+ const c = C(r);
690
+ c.current = r;
691
+ const b = C(null), x = G((y) => {
692
+ b.current = y;
693
+ }, []), m = G(
694
+ () => Pe({
640
695
  registry: s.current.internals.registry,
641
696
  store: s.current.internals.store,
642
- product: h.current
697
+ product: u.current
643
698
  }),
644
699
  []
645
700
  );
646
- re(() => Ct({ compute: d }), [d]);
647
- const v = O(!1);
648
- return U(() => {
649
- let g = !1;
701
+ ae(() => Dt({ compute: m }), [m]);
702
+ const E = C(!1);
703
+ return L(() => {
704
+ let y = !1;
650
705
  return queueMicrotask(() => {
651
- var f;
652
- g || v.current || (v.current = !0, (f = p.current) == null || f.call(p, b.current ?? d()));
706
+ var p;
707
+ y || E.current || (E.current = !0, (p = c.current) == null || p.call(c, b.current ?? m()));
653
708
  }), () => {
654
- g = !0;
709
+ y = !0;
655
710
  };
656
- }, [d]), // `display: contents` — the .sc-root scope without a layout box, so the
711
+ }, [m]), // `display: contents` — the .sc-root scope without a layout box, so the
657
712
  // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed
658
713
  // wrapper, which had no DOM at all, stays layout-identical).
659
- /* @__PURE__ */ c("div", { className: "sc-root", style: { display: "contents" }, "data-sc-part": "root", children: /* @__PURE__ */ c(_t, { reportedError: l, onRetry: () => u(null), children: /* @__PURE__ */ c(Tt, { ...e, internals: a, recordAudit: k }) }) });
714
+ /* @__PURE__ */ g("div", { className: "sc-root", style: { display: "contents" }, "data-sc-part": "root", children: /* @__PURE__ */ g(Ft, { reportedError: l, onRetry: () => d(null), children: /* @__PURE__ */ g(Vt, { ...e, internals: a, recordAudit: x }) }) });
660
715
  }
661
- let At = () => import("./EditorCanvasImpl-BRdFWZA5.js").then((e) => e.EditorCanvasImpl);
662
- function Fe() {
663
- return At();
716
+ let Pt = () => import("./EditorCanvasImpl-BnxEbr2p.js").then((e) => e.EditorCanvasImpl);
717
+ function ze() {
718
+ return Pt();
664
719
  }
665
- const Dt = $e(function({ children: t, maxHeight: n, floatingToolbar: r = !0, className: i, style: s }, o) {
666
- const l = te("Editor.Canvas");
667
- ne("Editor.Canvas", { floatingToolbar: r });
668
- const u = ge();
669
- re(() => l.registry.registerCanvas(u), [l.registry, u]);
670
- const [a, h] = T(null);
671
- return U(() => {
672
- let p = !1;
673
- return Fe().then(
720
+ const jt = Ae(function({ children: t, maxHeight: n, floatingToolbar: r = !0, className: i, style: s }, o) {
721
+ const l = se("Editor.Canvas");
722
+ oe("Editor.Canvas", { floatingToolbar: r });
723
+ const d = we();
724
+ ae(() => l.registry.registerCanvas(d), [l.registry, d]);
725
+ const [a, u] = D(null);
726
+ return L(() => {
727
+ let c = !1;
728
+ return ze().then(
674
729
  (b) => {
675
- p || h(() => b);
730
+ c || u(() => b);
676
731
  },
677
732
  (b) => {
678
- p || l.reportRuntimeError(
679
- new I(
733
+ c || l.reportRuntimeError(
734
+ new S(
680
735
  "E_CHUNK_LOAD_FAILED",
681
736
  `the editor's rendering chunk failed to load (${b instanceof Error ? b.message : String(b)}). This is a network/CDN failure, not a composition mistake — retry, or check the deployment serves the @snowcone-app/canvas lazy chunks.`,
682
737
  { cause: b instanceof Error ? b.message : String(b), docSlug: "embed-mode" }
@@ -684,14 +739,14 @@ const Dt = $e(function({ children: t, maxHeight: n, floatingToolbar: r = !0, cla
684
739
  );
685
740
  }
686
741
  ), () => {
687
- p = !0;
742
+ c = !0;
688
743
  };
689
744
  }, [l]), a ? (
690
745
  // `builtinControls`: the canvas owns the floating contextual toolbar
691
746
  // unless the host opts out via `floatingToolbar={false}` or a docked
692
747
  // <Editor.Controls> is mounted (ADR-0085 §5). Only here — the legacy
693
748
  // <RealtimeCanvas> wrapper stays chrome-less.
694
- /* @__PURE__ */ c(
749
+ /* @__PURE__ */ g(
695
750
  a,
696
751
  {
697
752
  ref: o,
@@ -704,7 +759,7 @@ const Dt = $e(function({ children: t, maxHeight: n, floatingToolbar: r = !0, cla
704
759
  children: t
705
760
  }
706
761
  )
707
- ) : /* @__PURE__ */ c(
762
+ ) : /* @__PURE__ */ g(
708
763
  "div",
709
764
  {
710
765
  "data-sc-part": "canvas",
@@ -715,55 +770,108 @@ const Dt = $e(function({ children: t, maxHeight: n, floatingToolbar: r = !0, cla
715
770
  }
716
771
  );
717
772
  });
718
- function Bt() {
719
- const { placements: e, placement: t, selectPlacement: n } = Q();
720
- return L(
721
- () => ({
722
- placements: e.map((r) => ({ label: r, active: r === t })),
723
- activePlacement: t,
724
- select: n
725
- }),
726
- [e, t, n]
727
- );
773
+ function Mt() {
774
+ const { placements: e, requiredPlacements: t, placement: n, selectPlacement: r, splitPlacement: i, linkPlacement: s } = te();
775
+ return A(() => {
776
+ const o = Fe(e, t), l = e[0] ?? n, d = o.map((u) => ({
777
+ label: u.label,
778
+ inherited: u.inherited,
779
+ active: u.inherited ? n === l : n === u.label
780
+ })), a = d.length > 1 && d.every((u) => u.inherited || u.label === l);
781
+ return {
782
+ placements: d,
783
+ activePlacement: n,
784
+ basePlacement: l,
785
+ linked: a,
786
+ select: r,
787
+ split: i,
788
+ link: s,
789
+ splitAll: () => {
790
+ for (const u of d) u.inherited && i(u.label);
791
+ },
792
+ linkAll: () => {
793
+ for (const u of d) !u.inherited && u.label !== l && s(u.label);
794
+ }
795
+ };
796
+ }, [e, t, n, r, i, s]);
728
797
  }
729
- function Lt({ className: e, style: t }) {
730
- const { placements: n, select: r } = Bt();
731
- return n.length < 2 ? null : /* @__PURE__ */ c(
798
+ const qt = (e) => e.length === 2 ? "Both sides" : `All ${e.length} areas`, zt = {
799
+ font: "inherit",
800
+ fontSize: "12px",
801
+ color: "var(--sc-color-muted-foreground, inherit)",
802
+ background: "transparent",
803
+ border: "none",
804
+ padding: "2px 8px",
805
+ cursor: "pointer",
806
+ textDecoration: "underline",
807
+ textUnderlineOffset: "4px"
808
+ };
809
+ function Kt({ className: e, style: t, labels: n }) {
810
+ const { placements: r, linked: i, select: s, splitAll: o, linkAll: l } = Mt();
811
+ if (r.length < 2) return null;
812
+ const d = r.map((a) => a.label);
813
+ return /* @__PURE__ */ U(
732
814
  "div",
733
815
  {
734
816
  "data-sc-part": "placements",
817
+ "data-sc-linked": i ? "true" : "false",
735
818
  className: e,
736
819
  style: { display: "flex", alignItems: "center", gap: "4px", ...t },
737
- children: n.map(({ label: i, active: s }) => /* @__PURE__ */ c(
738
- "button",
739
- {
740
- type: "button",
741
- "data-sc-part": "placements-item",
742
- "data-sc-active": s ? "true" : "false",
743
- "aria-pressed": s,
744
- onClick: () => r(i),
745
- style: {
746
- font: "inherit",
747
- fontSize: "13px",
748
- fontWeight: s ? 700 : 400,
749
- color: "var(--sc-color-foreground, inherit)",
750
- background: "transparent",
751
- border: "none",
752
- borderRadius: "9999px",
753
- padding: "2px 8px",
754
- cursor: s ? "default" : "pointer",
755
- textDecoration: s ? "underline" : "none",
756
- textUnderlineOffset: "4px"
820
+ children: [
821
+ i ? /* @__PURE__ */ g(
822
+ "span",
823
+ {
824
+ "data-sc-part": "placements-item",
825
+ "data-sc-active": "true",
826
+ "data-sc-linked": "true",
827
+ title: d.join(" · "),
828
+ style: { fontSize: "13px", fontWeight: 700, padding: "2px 8px", color: "var(--sc-color-foreground, inherit)" },
829
+ children: ((n == null ? void 0 : n.linked) ?? qt)(d)
830
+ }
831
+ ) : r.map(({ label: a, active: u, inherited: c }) => /* @__PURE__ */ g(
832
+ "button",
833
+ {
834
+ type: "button",
835
+ "data-sc-part": "placements-item",
836
+ "data-sc-active": u ? "true" : "false",
837
+ "data-sc-linked": c ? "true" : "false",
838
+ "aria-pressed": u,
839
+ onClick: () => s(a),
840
+ style: {
841
+ font: "inherit",
842
+ fontSize: "13px",
843
+ fontWeight: u ? 700 : 400,
844
+ color: "var(--sc-color-foreground, inherit)",
845
+ opacity: c ? 0.6 : 1,
846
+ background: "transparent",
847
+ border: "none",
848
+ borderRadius: "9999px",
849
+ padding: "2px 8px",
850
+ cursor: u ? "default" : "pointer",
851
+ textDecoration: u ? "underline" : "none",
852
+ textUnderlineOffset: "4px"
853
+ },
854
+ children: a
757
855
  },
758
- children: i
759
- },
760
- i
761
- ))
856
+ a
857
+ )),
858
+ /* @__PURE__ */ g(
859
+ "button",
860
+ {
861
+ type: "button",
862
+ "data-sc-part": "placements-link-toggle",
863
+ "data-sc-linked": i ? "true" : "false",
864
+ onClick: i ? o : l,
865
+ style: zt,
866
+ children: i ? (n == null ? void 0 : n.customizeSeparately) ?? "Customize separately" : (n == null ? void 0 : n.useOneDesign) ?? "Use one design for all"
867
+ }
868
+ )
869
+ ]
762
870
  }
763
871
  );
764
872
  }
765
- const Ut = 200, Ft = 400;
766
- function Vt() {
873
+ const Gt = 200, Wt = 400;
874
+ function Ht() {
767
875
  return Array.from({ length: 10 }, () => ({
768
876
  left: 2 + Math.random() * 96,
769
877
  top: 2 + Math.random() * 96,
@@ -772,10 +880,10 @@ function Vt() {
772
880
  size: 3 + Math.random() * 5
773
881
  }));
774
882
  }
775
- let Se = !1;
776
- function jt() {
777
- if (!(Se || typeof CSS > "u" || typeof CSS.registerProperty != "function")) {
778
- Se = !0;
883
+ let _e = !1;
884
+ function Jt() {
885
+ if (!(_e || typeof CSS > "u" || typeof CSS.registerProperty != "function")) {
886
+ _e = !0;
779
887
  try {
780
888
  CSS.registerProperty({ name: "--sc-prism-mount", syntax: "<number>", initialValue: "0", inherits: !0 });
781
889
  } catch {
@@ -786,89 +894,89 @@ function jt() {
786
894
  }
787
895
  }
788
896
  }
789
- const Ve = ot(function({
897
+ const Ke = pt(function({
790
898
  visible: t = !0,
791
899
  onExited: n,
792
900
  variant: r = "dark"
793
901
  }) {
794
- jt();
795
- const [i, s] = T([]);
796
- U(() => {
797
- s(Vt());
902
+ Jt();
903
+ const [i, s] = D([]);
904
+ L(() => {
905
+ s(Ht());
798
906
  }, []);
799
- const [o, l] = T(!1);
800
- U(() => {
801
- const h = requestAnimationFrame(() => l(!0));
802
- return () => cancelAnimationFrame(h);
907
+ const [o, l] = D(!1);
908
+ L(() => {
909
+ const u = requestAnimationFrame(() => l(!0));
910
+ return () => cancelAnimationFrame(u);
803
911
  }, []);
804
- const u = K(
805
- (h) => {
806
- h.propertyName === "background-color" && (t || n == null || n());
912
+ const d = G(
913
+ (u) => {
914
+ u.propertyName === "background-color" && (t || n == null || n());
807
915
  },
808
916
  [t, n]
809
917
  );
810
918
  let a = "";
811
- return t ? o && (a = "sc-prism-fade-in") : a = "sc-prism-fade-out", /* @__PURE__ */ F(
919
+ return t ? o && (a = "sc-prism-fade-in") : a = "sc-prism-fade-out", /* @__PURE__ */ U(
812
920
  "div",
813
921
  {
814
922
  "data-sc-part": "preview-loading",
815
923
  className: ["sc-prism-overlay", r === "light" ? "sc-prism-on-light" : "", a].filter(Boolean).join(" "),
816
- onTransitionEnd: u,
924
+ onTransitionEnd: d,
817
925
  "aria-hidden": "true",
818
926
  children: [
819
- Array.from({ length: 6 }, (h, p) => /* @__PURE__ */ c("div", { className: "sc-prism-band" }, `b-${p}`)),
820
- i.map((h, p) => /* @__PURE__ */ c(
927
+ Array.from({ length: 6 }, (u, c) => /* @__PURE__ */ g("div", { className: "sc-prism-band" }, `b-${c}`)),
928
+ i.map((u, c) => /* @__PURE__ */ g(
821
929
  "div",
822
930
  {
823
931
  className: "sc-prism-particle",
824
932
  style: {
825
- left: `${h.left}%`,
826
- top: `${h.top}%`,
827
- animationDelay: `${h.delay}s`,
828
- animationDuration: `${h.duration}s`,
829
- width: `${h.size}px`,
830
- height: `${h.size}px`
933
+ left: `${u.left}%`,
934
+ top: `${u.top}%`,
935
+ animationDelay: `${u.delay}s`,
936
+ animationDuration: `${u.duration}s`,
937
+ width: `${u.size}px`,
938
+ height: `${u.size}px`
831
939
  }
832
940
  },
833
- `p-${p}`
941
+ `p-${c}`
834
942
  ))
835
943
  ]
836
944
  }
837
945
  );
838
946
  });
839
- function je(e) {
840
- const [t, n] = T(!1), [r, i] = T(!1), s = O(null), o = O(null), l = O(!1);
841
- l.current = t, U(() => (e ? (i(!1), o.current && clearTimeout(o.current), s.current = setTimeout(() => n(!0), Ut)) : (s.current && (clearTimeout(s.current), s.current = null), l.current && (i(!0), o.current = setTimeout(() => i(!1), Ft))), () => {
947
+ function Ge(e) {
948
+ const [t, n] = D(!1), [r, i] = D(!1), s = C(null), o = C(null), l = C(!1);
949
+ l.current = t, L(() => (e ? (i(!1), o.current && clearTimeout(o.current), s.current = setTimeout(() => n(!0), Gt)) : (s.current && (clearTimeout(s.current), s.current = null), l.current && (i(!0), o.current = setTimeout(() => i(!1), Wt))), () => {
842
950
  s.current && clearTimeout(s.current), o.current && clearTimeout(o.current);
843
951
  }), [e]);
844
- const u = K(() => n(!1), []);
952
+ const d = G(() => n(!1), []);
845
953
  return {
846
954
  showOverlay: t,
847
955
  overlayVisible: e || r,
848
- handleExited: u
956
+ handleExited: d
849
957
  };
850
958
  }
851
- const Mt = 1.2, fe = [1200, 1400, 1600, 1800, 2e3, 2500, 3e3, 4e3];
852
- function qt(e) {
853
- for (const t of fe)
959
+ const Qt = 1.2, be = [1200, 1400, 1600, 1800, 2e3, 2500, 3e3, 4e3];
960
+ function Yt(e) {
961
+ for (const t of be)
854
962
  if (t >= e) return t;
855
- return fe[fe.length - 1];
963
+ return be[be.length - 1];
856
964
  }
857
- function Pt(e, t) {
858
- if (!(e > 0) || !(t > 0) || t <= e * Mt) return null;
859
- const n = qt(t);
965
+ function Xt(e, t) {
966
+ if (!(e > 0) || !(t > 0) || t <= e * Qt) return null;
967
+ const n = Yt(t);
860
968
  return `[RealtimeMockup] mockup rendered at ${e}px but displayed at ~${t} device px — the preview will look soft. Pass \`product.width\` (e.g. ${n}) on the embed for a crisp preview.`;
861
969
  }
862
- function zt(e) {
970
+ function Zt(e) {
863
971
  if (e === void 0 || e === !0 || e === "dark") return "dark";
864
- if (e === "light" || e === "host-owned" || Oe(e)) return e;
865
- throw new I(
972
+ if (e === "light" || e === "host-owned" || De(e)) return e;
973
+ throw new S(
866
974
  "E_PREVIEW_NO_LOADER",
867
975
  `Editor.Preview: invalid loadingOverlay value ${JSON.stringify(e)}. A mockup preview always has a render-in-flight treatment (the loader paints over the still-visible previous mockup). Omit the prop for the default rainbow overlay, pass "dark" | "light", pass a custom ReactElement, or declare "host-owned" if the host renders its own indicator off data-sc-preview-state / <Editor.LoadingOverlay>.`,
868
976
  { docSlug: "preview-loading-overlay" }
869
977
  );
870
978
  }
871
- function Me({
979
+ function We({
872
980
  mockupId: e,
873
981
  fallback: t = null,
874
982
  alt: n = "Live product mockup",
@@ -876,73 +984,73 @@ function Me({
876
984
  className: i,
877
985
  style: s
878
986
  }) {
879
- const { mockups: o, error: l, isRendering: u } = Q();
880
- ne("Editor.Preview", { ...e !== void 0 ? { mockupId: e } : {} });
881
- const a = zt(r), h = a === "dark" || a === "light" ? a : null, p = Oe(a) ? a : null, b = a !== "host-owned", { showOverlay: k, overlayVisible: d, handleExited: v } = je(
882
- b && u
883
- ), g = O(/* @__PURE__ */ new Set()), f = e ? o.find((E) => E.mockupId === e && E.imageUrl) : o.find((E) => E.imageUrl), S = (E) => {
884
- var m;
885
- if (!f || typeof P > "u" || ((m = P.env) == null ? void 0 : m.NODE_ENV) === "production" || typeof window > "u" || g.current.has(f.mockupId)) return;
886
- const A = E.currentTarget, C = A.getBoundingClientRect().width;
887
- if (C <= 0) return;
888
- const D = Math.round(C * (window.devicePixelRatio || 1)), V = Pt(A.naturalWidth, D);
889
- V && (g.current.add(f.mockupId), console.warn(V));
987
+ const { mockups: o, error: l, isRendering: d } = te();
988
+ oe("Editor.Preview", { ...e !== void 0 ? { mockupId: e } : {} });
989
+ const a = Zt(r), u = a === "dark" || a === "light" ? a : null, c = De(a) ? a : null, b = a !== "host-owned", { showOverlay: x, overlayVisible: m, handleExited: E } = Ge(
990
+ b && d
991
+ ), y = C(/* @__PURE__ */ new Set()), p = e ? o.find((v) => v.mockupId === e && v.imageUrl) : o.find((v) => v.imageUrl), O = (v) => {
992
+ var h;
993
+ if (!p || typeof z > "u" || ((h = z.env) == null ? void 0 : h.NODE_ENV) === "production" || typeof window > "u" || y.current.has(p.mockupId)) return;
994
+ const B = v.currentTarget, N = B.getBoundingClientRect().width;
995
+ if (N <= 0) return;
996
+ const _ = Math.round(N * (window.devicePixelRatio || 1)), F = Xt(B.naturalWidth, _);
997
+ F && (y.current.add(p.mockupId), console.warn(F));
890
998
  };
891
999
  if (b) {
892
- const E = f != null && f.imageUrl ? u ? "rendering" : "ready" : l ? "error" : "rendering";
893
- return /* @__PURE__ */ F(
1000
+ const v = p != null && p.imageUrl ? d ? "rendering" : "ready" : l ? "error" : "rendering";
1001
+ return /* @__PURE__ */ U(
894
1002
  "div",
895
1003
  {
896
1004
  "data-sc-part": "preview",
897
- "data-sc-preview-state": E,
898
- "aria-busy": E === "rendering" || void 0,
1005
+ "data-sc-preview-state": v,
1006
+ "aria-busy": v === "rendering" || void 0,
899
1007
  className: `sc-preview-frame${i ? ` ${i}` : ""}`,
900
1008
  style: s,
901
1009
  children: [
902
- f != null && f.imageUrl ? (
1010
+ p != null && p.imageUrl ? (
903
1011
  // eslint-disable-next-line @next/next/no-img-element
904
- /* @__PURE__ */ c("img", { "data-sc-part": "preview-image", src: f.imageUrl, alt: n, onLoad: S })
905
- ) : l ? /* @__PURE__ */ c("div", { "data-sc-part": "preview-error", role: "alert", "data-sc-error": l, children: t ?? `Render failed: ${l}` }) : t,
906
- p ? (
1012
+ /* @__PURE__ */ g("img", { "data-sc-part": "preview-image", src: p.imageUrl, alt: n, onLoad: O })
1013
+ ) : l ? /* @__PURE__ */ g("div", { "data-sc-part": "preview-error", role: "alert", "data-sc-error": l, children: t ?? `Render failed: ${l}` }) : t,
1014
+ c ? (
907
1015
  // Custom indicator: same show-delay + linger window; no exit fade
908
1016
  // (the host owns its animation), so it unmounts when the window
909
1017
  // closes.
910
- k && d ? /* @__PURE__ */ c(
1018
+ x && m ? /* @__PURE__ */ g(
911
1019
  "div",
912
1020
  {
913
1021
  "data-sc-part": "preview-loading",
914
1022
  className: "sc-preview-custom-loading",
915
1023
  "aria-hidden": "true",
916
- children: p
1024
+ children: c
917
1025
  }
918
1026
  ) : null
919
- ) : k && h ? /* @__PURE__ */ c(
920
- Ve,
1027
+ ) : x && u ? /* @__PURE__ */ g(
1028
+ Ke,
921
1029
  {
922
- visible: d,
923
- variant: h,
924
- onExited: v
1030
+ visible: m,
1031
+ variant: u,
1032
+ onExited: E
925
1033
  }
926
1034
  ) : null
927
1035
  ]
928
1036
  }
929
1037
  );
930
1038
  }
931
- return f != null && f.imageUrl ? (
1039
+ return p != null && p.imageUrl ? (
932
1040
  // eslint-disable-next-line @next/next/no-img-element
933
- /* @__PURE__ */ c(
1041
+ /* @__PURE__ */ g(
934
1042
  "img",
935
1043
  {
936
1044
  "data-sc-part": "preview",
937
- "data-sc-preview-state": u ? "rendering" : "ready",
938
- src: f.imageUrl,
1045
+ "data-sc-preview-state": d ? "rendering" : "ready",
1046
+ src: p.imageUrl,
939
1047
  alt: n,
940
1048
  className: i,
941
1049
  style: s,
942
- onLoad: S
1050
+ onLoad: O
943
1051
  }
944
1052
  )
945
- ) : l ? /* @__PURE__ */ c(
1053
+ ) : l ? /* @__PURE__ */ g(
946
1054
  "div",
947
1055
  {
948
1056
  "data-sc-part": "preview-error",
@@ -953,45 +1061,45 @@ function Me({
953
1061
  style: s,
954
1062
  children: t ?? `Render failed: ${l}`
955
1063
  }
956
- ) : /* @__PURE__ */ c("div", { "data-sc-part": "preview", "data-sc-preview-state": "rendering", "aria-busy": "true", style: { display: "contents" }, children: t });
1064
+ ) : /* @__PURE__ */ g("div", { "data-sc-part": "preview", "data-sc-preview-state": "rendering", "aria-busy": "true", style: { display: "contents" }, children: t });
957
1065
  }
958
- function Kt(e) {
959
- const { layer: t, optional: n = !1, placeholder: r, className: i, style: s } = e, o = te("Editor.TextField");
960
- ne("Editor.TextField");
961
- const { pushRender: l, throttleMs: u, stateStore: a } = Q(), h = ge(), p = O(null);
962
- if (!pt(t))
963
- throw new I(
1066
+ function en(e) {
1067
+ const { layer: t, optional: n = !1, placeholder: r, className: i, style: s } = e, o = se("Editor.TextField");
1068
+ oe("Editor.TextField");
1069
+ const { pushRender: l, throttleMs: d, stateStore: a } = te(), u = we(), c = C(null);
1070
+ if (!wt(t))
1071
+ throw new S(
964
1072
  "E_LAYER_TOKEN_REQUIRED",
965
1073
  `the \`layer\` prop must be a token minted by the design — pass layer={design.layer("name")}, not ${typeof t == "string" ? `the bare string "${t}"` : "a plain value"}. Tokens validate the name against the design's layers at mint time.`,
966
1074
  { received: typeof t == "string" ? t : typeof t, docSlug: "embed-mode" }
967
1075
  );
968
- if (p.current !== t.name) {
969
- const d = a.layerKindOf(t.name);
970
- if (d === void 0)
971
- throw new I(
1076
+ if (c.current !== t.name) {
1077
+ const m = a.layerKindOf(t.name);
1078
+ if (m === void 0)
1079
+ throw new S(
972
1080
  "E_LAYER_NOT_FOUND",
973
1081
  `no layer "${t.name}" in this Root's design — the token was minted from a different design than the one passed to <Editor.Root design={…}>. Bindable layers here: ${JSON.stringify(a.bindableLayerNames())}.`,
974
1082
  { layerName: t.name, validNames: a.bindableLayerNames(), docSlug: "embed-mode" }
975
1083
  );
976
- if (d !== "text")
977
- throw new I(
1084
+ if (m !== "text")
1085
+ throw new S(
978
1086
  "E_LAYER_WRONG_KIND",
979
- `layer "${t.name}" is ${d === null ? "not a bindable kind" : `an ${d} layer`} — <Editor.TextField> binds text layers only.`,
980
- { layerName: t.name, actualKind: d, docSlug: "embed-mode" }
1087
+ `layer "${t.name}" is ${m === null ? "not a bindable kind" : `an ${m} layer`} — <Editor.TextField> binds text layers only.`,
1088
+ { layerName: t.name, actualKind: m, docSlug: "embed-mode" }
981
1089
  );
982
- p.current = t.name;
1090
+ c.current = t.name;
983
1091
  }
984
- re(() => o.registry.registerTextField(h, { name: t.name, optional: n }), [o.registry, h, t.name, n]);
1092
+ ae(() => o.registry.registerTextField(u, { name: t.name, optional: n }), [o.registry, u, t.name, n]);
985
1093
  const b = J(
986
1094
  a.subscribe,
987
1095
  () => a.textOf(t.name) ?? "",
988
1096
  () => a.textOf(t.name) ?? ""
989
- ), k = K(
990
- (d) => {
991
- const v = d.target.value, g = o.registry.getCanvasBridge();
992
- if (g) {
993
- g.setTextByName(t.name, v) || o.reportInvariant(
994
- new I(
1097
+ ), x = G(
1098
+ (m) => {
1099
+ const E = m.target.value, y = o.registry.getCanvasBridge();
1100
+ if (y) {
1101
+ y.setTextByName(t.name, E) || o.reportInvariant(
1102
+ new S(
995
1103
  "E_LAYER_NOT_FOUND",
996
1104
  `layer "${t.name}" no longer exists in the mounted canvas — it was removed or renamed after this <Editor.TextField> bound to it. Bound layers must not be renamed or deleted while a field is mounted (ADR-0085 §3).`,
997
1105
  { layerName: t.name, docSlug: "embed-mode" }
@@ -999,18 +1107,18 @@ function Kt(e) {
999
1107
  );
1000
1108
  return;
1001
1109
  }
1002
- a.updateTextLayer(t.name, v), l(de(a.getState()), u);
1110
+ a.updateTextLayer(t.name, E), l(ee(a.getState()), d);
1003
1111
  },
1004
- [o, t.name, a, l, u]
1112
+ [o, t.name, a, l, d]
1005
1113
  );
1006
- return /* @__PURE__ */ c(
1114
+ return /* @__PURE__ */ g(
1007
1115
  "input",
1008
1116
  {
1009
1117
  "data-sc-part": "textfield",
1010
1118
  "data-sc-layer": t.name,
1011
1119
  type: "text",
1012
1120
  value: b,
1013
- onChange: k,
1121
+ onChange: x,
1014
1122
  placeholder: r,
1015
1123
  "aria-label": e["aria-label"] ?? t.name,
1016
1124
  className: i,
@@ -1018,7 +1126,7 @@ function Kt(e) {
1018
1126
  }
1019
1127
  );
1020
1128
  }
1021
- function Gt(e) {
1129
+ function tn(e) {
1022
1130
  const t = [];
1023
1131
  for (const n of e.missingOptionKeys)
1024
1132
  t.push(`option:${n}`);
@@ -1035,13 +1143,13 @@ function Gt(e) {
1035
1143
  }
1036
1144
  return e.hasRenderableElement || t.push("empty-design"), (!Number.isInteger(e.quantity) || e.quantity < 1) && t.push("quantity"), t;
1037
1145
  }
1038
- function Wt(e, t) {
1146
+ function nn(e, t) {
1039
1147
  const n = t.getCombinations(), r = t.getAttributes();
1040
1148
  if (Object.keys(r).length === 0 || n.length === 0) return null;
1041
1149
  const i = Object.fromEntries(
1042
- Object.entries(r).map(([s, o]) => [s, { ...o, choices: bt(o) }])
1150
+ Object.entries(r).map(([s, o]) => [s, { ...o, choices: Rt(o) }])
1043
1151
  );
1044
- return lt({
1152
+ return gt({
1045
1153
  productId: e.productId,
1046
1154
  quantity: t.getQuantity(),
1047
1155
  selection: t.getSelection(),
@@ -1049,97 +1157,103 @@ function Wt(e, t) {
1049
1157
  attributes: i
1050
1158
  });
1051
1159
  }
1052
- function Ht(e) {
1053
- const { onAddToCart: t, defaultQuantity: n, children: r, className: i, style: s } = e, o = te("Editor.Buy");
1054
- ne("Editor.Buy");
1055
- const { product: l, stateStore: u } = Q(), a = o.commerce;
1160
+ function rn(e) {
1161
+ const { onAddToCart: t, defaultQuantity: n, children: r, className: i, style: s } = e, o = se("Editor.Buy");
1162
+ oe("Editor.Buy");
1163
+ const { product: l, stateStore: d } = te(), a = o.commerce;
1056
1164
  if (!(l != null && l.productId))
1057
- throw new I(
1165
+ throw new S(
1058
1166
  "E_BUY_NO_PRODUCT",
1059
1167
  "<Editor.Buy> has no product context — pass `product` (with `productId`) on <Editor.Root product={…}>. Buy assembles its cart payload from the Root product and the live design state.",
1060
1168
  { docSlug: "embed-mode" }
1061
1169
  );
1062
- const h = O(!1);
1063
- re(() => {
1064
- h.current || (h.current = !0, typeof n == "number" && a.setQuantity(n));
1170
+ const u = C(!1);
1171
+ ae(() => {
1172
+ u.current || (u.current = !0, typeof n == "number" && a.setQuantity(n));
1065
1173
  }, [a]);
1066
- const p = J(u.subscribe, u.getState, u.getState), b = J(a.subscribe, a.getVersion, a.getVersion), k = J(
1174
+ const c = J(d.subscribe, d.getState, d.getState), b = J(a.subscribe, a.getVersion, a.getVersion), x = J(
1067
1175
  o.registry.subscribe,
1068
1176
  o.registry.getVersion,
1069
1177
  o.registry.getVersion
1070
- ), d = a.getQuantity(), v = L(
1071
- () => Gt({
1072
- quantity: d,
1178
+ ), m = a.getQuantity(), E = A(
1179
+ () => tn({
1180
+ quantity: m,
1073
1181
  missingOptionKeys: a.missingOptionKeys(),
1074
1182
  selectionValid: a.selectionValid(),
1075
1183
  textFields: o.registry.getTextFields(),
1076
- textOf: (C) => u.textOf(C),
1077
- seedTextOf: (C) => u.seedTextOf(C),
1078
- hasRenderableElement: u.hasRenderableElement()
1184
+ textOf: (N) => d.textOf(N),
1185
+ seedTextOf: (N) => d.seedTextOf(N),
1186
+ hasRenderableElement: d.hasRenderableElement()
1079
1187
  }),
1080
1188
  // eslint-disable-next-line react-hooks/exhaustive-deps
1081
- [a, d, p, b, k]
1082
- ), g = v.length === 0, [f, S] = T(!1), E = O(!1), A = K(() => {
1083
- if (E.current || !g) return;
1084
- E.current = !0, S(!0);
1085
- const C = u.getState(), D = a.resolvedVariantId(), V = {
1189
+ [a, m, c, b, x]
1190
+ ), y = E.length === 0, [p, O] = D(!1), v = C(!1), B = G(() => {
1191
+ if (v.current || !y) return;
1192
+ v.current = !0, O(!0);
1193
+ const N = d.getState(), _ = a.resolvedVariantId(), F = {
1086
1194
  productId: l.productId,
1087
- ...D ? { variantId: D } : {},
1195
+ ..._ ? { variantId: _ } : {},
1088
1196
  quantity: a.getQuantity(),
1089
1197
  selection: a.getSelection(),
1090
- cartDetail: Wt(l, a),
1091
- designState: C,
1092
- serverRequest: de(C)
1198
+ cartDetail: nn(l, a),
1199
+ designState: N,
1200
+ // ADR-0101: one artboard per REQUIRED placement — linked placements
1201
+ // carry the base relabelled — so buy and preview are the same bytes
1202
+ // and the order pipeline never re-derives the link rule.
1203
+ serverRequest: Ve(
1204
+ ee(N),
1205
+ pe(l)
1206
+ )
1093
1207
  };
1094
- let m;
1208
+ let h;
1095
1209
  try {
1096
- m = t(V);
1097
- } catch (R) {
1098
- throw E.current = !1, S(!1), R;
1210
+ h = t(F);
1211
+ } catch ($) {
1212
+ throw v.current = !1, O(!1), $;
1099
1213
  }
1100
- Promise.resolve(m).finally(() => {
1101
- E.current = !1, S(!1);
1214
+ Promise.resolve(h).finally(() => {
1215
+ v.current = !1, O(!1);
1102
1216
  });
1103
- }, [g, l, a, u, t]);
1104
- return /* @__PURE__ */ c(
1217
+ }, [y, l, a, d, t]);
1218
+ return /* @__PURE__ */ g(
1105
1219
  "button",
1106
1220
  {
1107
1221
  type: "button",
1108
1222
  "data-sc-part": "buy",
1109
- "data-sc-buy-state": f ? "busy" : g ? "ready" : "incomplete",
1110
- "data-sc-buy-missing": v.join(",") || void 0,
1111
- disabled: !g || f,
1112
- "aria-busy": f || void 0,
1113
- onClick: A,
1223
+ "data-sc-buy-state": p ? "busy" : y ? "ready" : "incomplete",
1224
+ "data-sc-buy-missing": E.join(",") || void 0,
1225
+ disabled: !y || p,
1226
+ "aria-busy": p || void 0,
1227
+ onClick: B,
1114
1228
  className: i,
1115
1229
  style: s,
1116
1230
  children: r ?? "Add to cart"
1117
1231
  }
1118
1232
  );
1119
1233
  }
1120
- function Jt({
1234
+ function sn({
1121
1235
  placement: e = "docked",
1122
1236
  className: t,
1123
1237
  style: n
1124
1238
  }) {
1125
- const r = te("Editor.Controls");
1126
- Je("Editor.Controls"), ne("Editor.Controls");
1127
- const i = ge();
1128
- re(
1239
+ const r = se("Editor.Controls");
1240
+ nt("Editor.Controls"), oe("Editor.Controls");
1241
+ const i = we();
1242
+ ae(
1129
1243
  () => r.registry.registerControls(i, e),
1130
1244
  [r.registry, i, e]
1131
1245
  );
1132
- const s = e === "docked", [o, l] = T(null);
1133
- return U(() => {
1246
+ const s = e === "docked", [o, l] = D(null);
1247
+ return L(() => {
1134
1248
  if (!s) return;
1135
- let u = !1;
1136
- return import("./ContextualToolbars-CG5Gmv_i.js").then((a) => a.s).then(
1249
+ let d = !1;
1250
+ return import("./ContextualToolbars-C62As-xY.js").then((a) => a.s).then(
1137
1251
  (a) => {
1138
- u || l(() => a.ContextualToolbars);
1252
+ d || l(() => a.ContextualToolbars);
1139
1253
  },
1140
1254
  (a) => {
1141
- u || r.reportRuntimeError(
1142
- new I(
1255
+ d || r.reportRuntimeError(
1256
+ new S(
1143
1257
  "E_CHUNK_LOAD_FAILED",
1144
1258
  `the editor's controls chunk failed to load (${a instanceof Error ? a.message : String(a)}). This is a network/CDN failure, not a composition mistake — retry, or check the deployment serves the @snowcone-app/canvas lazy chunks.`,
1145
1259
  { cause: a instanceof Error ? a.message : String(a), docSlug: "embed-mode" }
@@ -1147,9 +1261,9 @@ function Jt({
1147
1261
  );
1148
1262
  }
1149
1263
  ), () => {
1150
- u = !0;
1264
+ d = !0;
1151
1265
  };
1152
- }, [s, r]), s ? /* @__PURE__ */ c(
1266
+ }, [s, r]), s ? /* @__PURE__ */ g(
1153
1267
  "div",
1154
1268
  {
1155
1269
  "data-sc-part": "controls",
@@ -1157,30 +1271,30 @@ function Jt({
1157
1271
  className: t,
1158
1272
  style: n,
1159
1273
  "aria-busy": o ? void 0 : "true",
1160
- children: o ? /* @__PURE__ */ c(o, { mode: "embedded" }) : null
1274
+ children: o ? /* @__PURE__ */ g(o, { mode: "embedded" }) : null
1161
1275
  }
1162
1276
  ) : null;
1163
1277
  }
1164
- function Qt({
1278
+ function on({
1165
1279
  variant: e = "dark",
1166
1280
  className: t,
1167
1281
  style: n
1168
1282
  }) {
1169
- const { isRendering: r } = Q(), { showOverlay: i, overlayVisible: s, handleExited: o } = je(r);
1170
- return i ? /* @__PURE__ */ c(
1283
+ const { isRendering: r } = te(), { showOverlay: i, overlayVisible: s, handleExited: o } = Ge(r);
1284
+ return i ? /* @__PURE__ */ g(
1171
1285
  "div",
1172
1286
  {
1173
1287
  "data-sc-part": "loading-overlay",
1174
1288
  className: `sc-loading-overlay-host${t ? ` ${t}` : ""}`,
1175
1289
  style: n,
1176
1290
  "aria-hidden": "true",
1177
- children: /* @__PURE__ */ c(Ve, { visible: s, variant: e, onExited: o })
1291
+ children: /* @__PURE__ */ g(Ke, { visible: s, variant: e, onExited: o })
1178
1292
  }
1179
1293
  ) : null;
1180
1294
  }
1181
- function Yt() {
1182
- const t = te("useProductSelection").commerce, n = J(t.subscribe, t.getVersion, t.getVersion), r = K((s, o) => t.select(s, o), [t]), i = K((s) => t.setQuantity(s), [t]);
1183
- return L(
1295
+ function an() {
1296
+ const t = se("useProductSelection").commerce, n = J(t.subscribe, t.getVersion, t.getVersion), r = G((s, o) => t.select(s, o), [t]), i = G((s) => t.setQuantity(s), [t]);
1297
+ return A(
1184
1298
  () => ({
1185
1299
  attributes: t.getAttributes(),
1186
1300
  selection: t.getSelection(),
@@ -1197,53 +1311,53 @@ function Yt() {
1197
1311
  [t, r, i, n]
1198
1312
  );
1199
1313
  }
1200
- const W = {
1314
+ const H = {
1201
1315
  /** The one provider boundary — session, design, live state, error boundary. */
1202
- Root: Ue,
1316
+ Root: qe,
1203
1317
  /** The editable artboard (the ONE lazy renderer boundary — D9). */
1204
- Canvas: Dt,
1318
+ Canvas: jt,
1205
1319
  /** Live product mockup. ×N under one Root is valid. */
1206
- Preview: Me,
1320
+ Preview: We,
1207
1321
  /** Placement switcher tabs (ADR-0088). Renders nothing for a
1208
1322
  * single-placement design; headless floor = usePlacements(). */
1209
- Placements: Lt,
1323
+ Placements: Kt,
1210
1324
  /** Form input bound to a design text layer by typed token (T1). */
1211
- TextField: Kt,
1325
+ TextField: en,
1212
1326
  /** Smart commerce part: completeness + payload assembly; submit = host callback. */
1213
- Buy: Ht,
1327
+ Buy: rn,
1214
1328
  /** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */
1215
- Layers: Ze,
1329
+ Layers: ot,
1216
1330
  /** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */
1217
- Controls: Jt,
1331
+ Controls: sn,
1218
1332
  /** Undo/redo controls. Requires Editor.Canvas. */
1219
- History: Xe,
1333
+ History: st,
1220
1334
  /** The one ⋯ overflow menu. Requires Editor.Canvas. */
1221
- Menu: Ye,
1335
+ Menu: it,
1222
1336
  /** The ⊕ add-element menu. Requires Editor.Canvas. */
1223
- Add: Qe,
1337
+ Add: rt,
1224
1338
  /** Standalone render-in-flight rainbow for host-owned preview surfaces.
1225
1339
  * Fills its positioned parent; rides the session (canvas-free). */
1226
- LoadingOverlay: Qt
1340
+ LoadingOverlay: on
1227
1341
  };
1228
- function vn(e) {
1229
- return /* @__PURE__ */ c(Ue, { ...e, __validation: "warn" });
1342
+ function Cn(e) {
1343
+ return /* @__PURE__ */ g(qe, { ...e, __validation: "warn" });
1230
1344
  }
1231
- const wn = $e(
1345
+ const Nn = Ae(
1232
1346
  function(t, n) {
1233
- const { children: r, className: i, style: s, maxHeight: o, ...l } = t, [u, a] = T(null);
1234
- return U(() => {
1235
- let h = !1;
1236
- return Fe().then(
1237
- (p) => {
1238
- h || a(() => p);
1347
+ const { children: r, className: i, style: s, maxHeight: o, ...l } = t, [d, a] = D(null);
1348
+ return L(() => {
1349
+ let u = !1;
1350
+ return ze().then(
1351
+ (c) => {
1352
+ u || a(() => c);
1239
1353
  },
1240
- (p) => {
1241
- console.error("[RealtimeCanvas] failed to load the rendering chunk:", p);
1354
+ (c) => {
1355
+ console.error("[RealtimeCanvas] failed to load the rendering chunk:", c);
1242
1356
  }
1243
1357
  ), () => {
1244
- h = !0;
1358
+ u = !0;
1245
1359
  };
1246
- }, []), u ? /* @__PURE__ */ c(u, { ref: n, selfScope: !0, maxHeight: o, className: i, style: s, ...l, children: r }) : /* @__PURE__ */ c(
1360
+ }, []), d ? /* @__PURE__ */ g(d, { ref: n, selfScope: !0, maxHeight: o, className: i, style: s, ...l, children: r }) : /* @__PURE__ */ g(
1247
1361
  "div",
1248
1362
  {
1249
1363
  className: `sc-root${i ? ` ${i}` : ""}`,
@@ -1253,52 +1367,52 @@ const wn = $e(
1253
1367
  );
1254
1368
  }
1255
1369
  );
1256
- function En(e) {
1257
- return /* @__PURE__ */ c(Me, { ...e });
1370
+ function _n(e) {
1371
+ return /* @__PURE__ */ g(We, { ...e });
1258
1372
  }
1259
- function kn() {
1260
- const { mockups: e, isRendering: t, error: n } = Q();
1373
+ function Tn() {
1374
+ const { mockups: e, isRendering: t, error: n } = te();
1261
1375
  return { mockups: e, isRendering: t, error: n };
1262
1376
  }
1263
- function Xt(e) {
1377
+ function dn(e) {
1264
1378
  return e.type !== "color" && typeof e.width == "number" && e.width > 0 && typeof e.height == "number" && e.height > 0;
1265
1379
  }
1266
- function Rn(e, t = {}) {
1267
- var b, k, d, v, g;
1268
- if (_e(e))
1269
- throw new I(
1380
+ function An(e, t = {}) {
1381
+ var b, x, m, E, y;
1382
+ if (Ue(e))
1383
+ throw new S(
1270
1384
  "E_BUNDLE_CONFIG_REQUIRED",
1271
- `product ${e.id} is a bundle (roles: [${e.bundle.members.map((f) => f.role).join(", ")}]) — it has per-role variants and role-scoped placement keys, which the single-product config cannot describe. Use bundleToRenderConfig(product, { picks?, variants?, placement?, width? }) instead.`,
1385
+ `product ${e.id} is a bundle (roles: [${e.bundle.members.map((p) => p.role).join(", ")}]) — it has per-role variants and role-scoped placement keys, which the single-product config cannot describe. Use bundleToRenderConfig(product, { picks?, variants?, placement?, width? }) instead.`,
1272
1386
  {
1273
1387
  productId: e.id,
1274
- validNames: e.bundle.members.map((f) => f.role),
1388
+ validNames: e.bundle.members.map((p) => p.role),
1275
1389
  docSlug: "bundles"
1276
1390
  }
1277
1391
  );
1278
- const n = (e.placements ?? []).filter(Xt), r = n.map((f) => f.label), i = t.placement ? n.find((f) => f.label === t.placement) : n[0];
1392
+ const n = (e.placements ?? []).filter(dn), r = n.map((p) => p.label), i = t.placement ? n.find((p) => p.label === t.placement) : n[0];
1279
1393
  if (!i)
1280
- throw t.placement ? new I(
1394
+ throw t.placement ? new S(
1281
1395
  "E_PRODUCT_NOT_RENDERABLE",
1282
1396
  `product ${e.id} has no renderable placement "${t.placement}". Renderable image placements: [${r.join(", ")}].`,
1283
1397
  { productId: e.id, requested: t.placement, validNames: r, docSlug: "embed-mode" }
1284
- ) : new I(
1398
+ ) : new S(
1285
1399
  "E_PRODUCT_NOT_RENDERABLE",
1286
1400
  `product ${e.id} has no renderable image placement (a non-color placement with width/height). The catalog payload may be incomplete — fetch it via getProduct(), not a search hit.`,
1287
1401
  { productId: e.id, docSlug: "embed-mode" }
1288
1402
  );
1289
1403
  const s = ((b = e.options) == null ? void 0 : b.attributes) ?? {}, l = Object.values(s).some(
1290
- (f) => {
1291
- var S;
1292
- return (S = f == null ? void 0 : f.choices) == null ? void 0 : S.some((E) => E == null ? void 0 : E.hex);
1404
+ (p) => {
1405
+ var O;
1406
+ return (O = p == null ? void 0 : p.choices) == null ? void 0 : O.some((v) => v == null ? void 0 : v.hex);
1293
1407
  }
1294
- ) ? (v = (d = (k = e.options) == null ? void 0 : k.combinations) == null ? void 0 : d.find(
1295
- (f) => typeof f.variantId == "string" && f.variantId !== ""
1296
- )) == null ? void 0 : v.variantId : void 0, u = e.mockups ?? [], a = l ? u.filter((f) => {
1297
- var S;
1298
- return (S = f.gvids) == null ? void 0 : S.includes(l);
1299
- }) : u, h = (a.length > 0 ? a : u).map((f) => f.id);
1300
- if (h.length === 0)
1301
- throw new I(
1408
+ ) ? (E = (m = (x = e.options) == null ? void 0 : x.combinations) == null ? void 0 : m.find(
1409
+ (p) => typeof p.variantId == "string" && p.variantId !== ""
1410
+ )) == null ? void 0 : E.variantId : void 0, d = e.mockups ?? [], a = l ? d.filter((p) => {
1411
+ var O;
1412
+ return (O = p.gvids) == null ? void 0 : O.includes(l);
1413
+ }) : d, u = (a.length > 0 ? a : d).map((p) => p.id);
1414
+ if (u.length === 0)
1415
+ throw new S(
1302
1416
  "E_PRODUCT_NOT_RENDERABLE",
1303
1417
  `product ${e.id} has no mockup scenes — nothing to render a preview into.`,
1304
1418
  { productId: e.id, docSlug: "embed-mode" }
@@ -1306,11 +1420,11 @@ function Rn(e, t = {}) {
1306
1420
  return {
1307
1421
  product: {
1308
1422
  productId: e.id,
1309
- mockupIds: h,
1423
+ mockupIds: u,
1310
1424
  ...typeof l == "string" ? { variantId: l } : {},
1311
1425
  options: e.options,
1312
- placements: (g = e.placements) == null ? void 0 : g.map((f) => f.label),
1313
- mockups: u,
1426
+ placements: (y = e.placements) == null ? void 0 : y.map((p) => p.label),
1427
+ mockups: d,
1314
1428
  requiredPlacements: e.requiredPlacements,
1315
1429
  ...e.defaultGvid ? { defaultGvid: e.defaultGvid } : {},
1316
1430
  ...typeof t.width == "number" ? { width: t.width } : {}
@@ -1322,17 +1436,17 @@ function Rn(e, t = {}) {
1322
1436
  aspectRatio: i.width / i.height
1323
1437
  },
1324
1438
  placementLabels: r,
1325
- placements: n.map((f) => ({
1326
- label: f.label,
1327
- width: f.width,
1328
- height: f.height,
1329
- aspectRatio: f.width / f.height
1439
+ placements: n.map((p) => ({
1440
+ label: p.label,
1441
+ width: p.width,
1442
+ height: p.height,
1443
+ aspectRatio: p.width / p.height
1330
1444
  })),
1331
- primaryMockupId: h[0],
1445
+ primaryMockupId: u[0],
1332
1446
  variantId: l
1333
1447
  };
1334
1448
  }
1335
- function Zt(e) {
1449
+ function ln(e) {
1336
1450
  return new Intl.NumberFormat("en-US", {
1337
1451
  style: "currency",
1338
1452
  currency: "USD",
@@ -1340,7 +1454,7 @@ function Zt(e) {
1340
1454
  maximumFractionDigits: e % 100 === 0 ? 0 : 2
1341
1455
  }).format(e / 100);
1342
1456
  }
1343
- const en = {
1457
+ const cn = {
1344
1458
  display: "inline-flex",
1345
1459
  alignItems: "center",
1346
1460
  justifyContent: "center",
@@ -1355,7 +1469,7 @@ const en = {
1355
1469
  fontSize: 16,
1356
1470
  lineHeight: 1,
1357
1471
  cursor: "pointer"
1358
- }, tn = {
1472
+ }, un = {
1359
1473
  display: "flex",
1360
1474
  alignItems: "center",
1361
1475
  gap: 10,
@@ -1371,23 +1485,23 @@ const en = {
1371
1485
  textAlign: "left",
1372
1486
  cursor: "pointer"
1373
1487
  };
1374
- function he({
1488
+ function ve({
1375
1489
  label: e,
1376
1490
  onSelect: t
1377
1491
  }) {
1378
- return /* @__PURE__ */ c(
1492
+ return /* @__PURE__ */ g(
1379
1493
  "button",
1380
1494
  {
1381
1495
  type: "button",
1382
1496
  role: "menuitem",
1383
1497
  "data-sc-part": "snowcone-editor-menu-item",
1384
- style: tn,
1498
+ style: un,
1385
1499
  onClick: t,
1386
1500
  children: e
1387
1501
  }
1388
1502
  );
1389
1503
  }
1390
- function nn({
1504
+ function mn({
1391
1505
  fullscreen: e,
1392
1506
  onToggleFullscreen: t,
1393
1507
  viewCount: n,
@@ -1395,9 +1509,9 @@ function nn({
1395
1509
  onSelectView: i,
1396
1510
  onExport: s
1397
1511
  }) {
1398
- const [o, l] = T(!1), u = () => l(!1);
1399
- return /* @__PURE__ */ F("div", { style: { position: "relative" }, children: [
1400
- /* @__PURE__ */ c(
1512
+ const [o, l] = D(!1), d = () => l(!1);
1513
+ return /* @__PURE__ */ U("div", { style: { position: "relative" }, children: [
1514
+ /* @__PURE__ */ g(
1401
1515
  "button",
1402
1516
  {
1403
1517
  type: "button",
@@ -1405,21 +1519,21 @@ function nn({
1405
1519
  "aria-haspopup": "menu",
1406
1520
  "aria-expanded": o,
1407
1521
  "data-sc-part": "snowcone-editor-menu",
1408
- style: en,
1522
+ style: cn,
1409
1523
  onClick: () => l((a) => !a),
1410
1524
  children: "⋮"
1411
1525
  }
1412
1526
  ),
1413
- o ? /* @__PURE__ */ F(nt, { children: [
1414
- /* @__PURE__ */ c(
1527
+ o ? /* @__PURE__ */ U(lt, { children: [
1528
+ /* @__PURE__ */ g(
1415
1529
  "div",
1416
1530
  {
1417
1531
  style: { position: "fixed", inset: 0, zIndex: 39 },
1418
- onClick: u,
1532
+ onClick: d,
1419
1533
  "aria-hidden": "true"
1420
1534
  }
1421
1535
  ),
1422
- /* @__PURE__ */ F(
1536
+ /* @__PURE__ */ U(
1423
1537
  "div",
1424
1538
  {
1425
1539
  role: "menu",
@@ -1438,31 +1552,31 @@ function nn({
1438
1552
  zIndex: 40
1439
1553
  },
1440
1554
  children: [
1441
- /* @__PURE__ */ c(
1442
- he,
1555
+ /* @__PURE__ */ g(
1556
+ ve,
1443
1557
  {
1444
1558
  label: e ? "Exit fullscreen" : "Fullscreen",
1445
1559
  onSelect: () => {
1446
- u(), t();
1560
+ d(), t();
1447
1561
  }
1448
1562
  }
1449
1563
  ),
1450
- n > 1 ? Array.from({ length: n }, (a, h) => /* @__PURE__ */ c(
1451
- he,
1564
+ n > 1 ? Array.from({ length: n }, (a, u) => /* @__PURE__ */ g(
1565
+ ve,
1452
1566
  {
1453
- label: `View ${h + 1}${h === r ? " ✓" : ""}`,
1567
+ label: `View ${u + 1}${u === r ? " ✓" : ""}`,
1454
1568
  onSelect: () => {
1455
- u(), i(h);
1569
+ d(), i(u);
1456
1570
  }
1457
1571
  },
1458
- h
1572
+ u
1459
1573
  )) : null,
1460
- /* @__PURE__ */ c(
1461
- he,
1574
+ /* @__PURE__ */ g(
1575
+ ve,
1462
1576
  {
1463
1577
  label: "Export PNG",
1464
1578
  onSelect: () => {
1465
- u(), s();
1579
+ d(), s();
1466
1580
  }
1467
1581
  }
1468
1582
  )
@@ -1472,19 +1586,19 @@ function nn({
1472
1586
  ] }) : null
1473
1587
  ] });
1474
1588
  }
1475
- function rn() {
1476
- const { flatLayers: e, selectLayer: t, generateAllPreviews: n } = et({ previewSize: 96 });
1477
- return U(() => {
1589
+ function pn() {
1590
+ const { flatLayers: e, selectLayer: t, generateAllPreviews: n } = at({ previewSize: 96 });
1591
+ return L(() => {
1478
1592
  e.length > 0 && n();
1479
- }, [e.length, n]), /* @__PURE__ */ F(
1593
+ }, [e.length, n]), /* @__PURE__ */ U(
1480
1594
  "div",
1481
1595
  {
1482
1596
  "data-sc-part": "snowcone-editor-idle-dock",
1483
1597
  style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 8, minHeight: 44 },
1484
1598
  children: [
1485
- /* @__PURE__ */ c(W.Add, {}),
1486
- e.length > 0 ? /* @__PURE__ */ c("div", { style: { width: 1, height: 28, background: "rgba(0,0,0,0.1)", flexShrink: 0 }, "aria-hidden": "true" }) : null,
1487
- e.map((r) => /* @__PURE__ */ c(
1599
+ /* @__PURE__ */ g(H.Add, {}),
1600
+ e.length > 0 ? /* @__PURE__ */ g("div", { style: { width: 1, height: 28, background: "rgba(0,0,0,0.1)", flexShrink: 0 }, "aria-hidden": "true" }) : null,
1601
+ e.map((r) => /* @__PURE__ */ g(
1488
1602
  "button",
1489
1603
  {
1490
1604
  type: "button",
@@ -1507,8 +1621,8 @@ function rn() {
1507
1621
  },
1508
1622
  children: r.previewUrl ? (
1509
1623
  // eslint-disable-next-line @next/next/no-img-element
1510
- /* @__PURE__ */ c("img", { src: r.previewUrl, alt: "", style: { width: "100%", height: "100%", objectFit: "contain" } })
1511
- ) : /* @__PURE__ */ c(
1624
+ /* @__PURE__ */ g("img", { src: r.previewUrl, alt: "", style: { width: "100%", height: "100%", objectFit: "contain" } })
1625
+ ) : /* @__PURE__ */ g(
1512
1626
  "span",
1513
1627
  {
1514
1628
  style: {
@@ -1529,13 +1643,13 @@ function rn() {
1529
1643
  }
1530
1644
  );
1531
1645
  }
1532
- function sn({
1646
+ function fn({
1533
1647
  onAddToCart: e,
1534
1648
  defaultQuantity: t
1535
1649
  }) {
1536
- const { price: n, complete: r } = Yt();
1537
- return /* @__PURE__ */ F(
1538
- W.Buy,
1650
+ const { price: n, complete: r } = an();
1651
+ return /* @__PURE__ */ U(
1652
+ H.Buy,
1539
1653
  {
1540
1654
  onAddToCart: e,
1541
1655
  ...typeof t == "number" ? { defaultQuantity: t } : {},
@@ -1558,12 +1672,12 @@ function sn({
1558
1672
  },
1559
1673
  children: [
1560
1674
  "Add to cart",
1561
- typeof n == "number" ? ` · ${Zt(n)}` : ""
1675
+ typeof n == "number" ? ` · ${ln(n)}` : ""
1562
1676
  ]
1563
1677
  }
1564
1678
  );
1565
1679
  }
1566
- function on({
1680
+ function hn({
1567
1681
  title: e,
1568
1682
  height: t,
1569
1683
  mockupIds: n,
@@ -1572,15 +1686,15 @@ function on({
1572
1686
  className: s,
1573
1687
  style: o
1574
1688
  }) {
1575
- const [l, u] = T(!1), [a, h] = T(0), [p, b] = T(!1), k = O(null), d = vt(), v = n[Math.min(a, n.length - 1)], g = K(async () => {
1576
- var V;
1577
- const E = await ((V = k.current) == null ? void 0 : V.exportArtboards({ format: "dataUrl" }));
1578
- if (!E) return;
1579
- const [A, C] = Object.entries(E)[0] ?? [];
1580
- if (typeof C != "string") return;
1581
- const D = document.createElement("a");
1582
- D.href = C, D.download = `${A ?? "design"}.png`, D.click();
1583
- }, []), f = {
1689
+ const [l, d] = D(!1), [a, u] = D(0), [c, b] = D(!1), x = C(null), m = It(), E = n[Math.min(a, n.length - 1)], y = G(async () => {
1690
+ var F;
1691
+ const v = await ((F = x.current) == null ? void 0 : F.exportArtboards({ format: "dataUrl" }));
1692
+ if (!v) return;
1693
+ const [B, N] = Object.entries(v)[0] ?? [];
1694
+ if (typeof N != "string") return;
1695
+ const _ = document.createElement("a");
1696
+ _.href = N, _.download = `${B ?? "design"}.png`, _.click();
1697
+ }, []), p = {
1584
1698
  display: "flex",
1585
1699
  flexDirection: "column",
1586
1700
  overflow: "hidden",
@@ -1601,7 +1715,7 @@ function on({
1601
1715
  boxShadow: "0 1px 3px rgba(0,0,0,0.08)"
1602
1716
  },
1603
1717
  ...o
1604
- }, S = {
1718
+ }, O = {
1605
1719
  position: "absolute",
1606
1720
  top: 8,
1607
1721
  right: 12,
@@ -1616,15 +1730,15 @@ function on({
1616
1730
  cursor: "pointer",
1617
1731
  zIndex: 2
1618
1732
  };
1619
- return /* @__PURE__ */ F(
1733
+ return /* @__PURE__ */ U(
1620
1734
  "div",
1621
1735
  {
1622
1736
  "data-sc-part": "snowcone-editor",
1623
1737
  "data-sc-fullscreen": l ? "true" : void 0,
1624
1738
  className: s,
1625
- style: f,
1739
+ style: p,
1626
1740
  children: [
1627
- /* @__PURE__ */ F(
1741
+ /* @__PURE__ */ U(
1628
1742
  "div",
1629
1743
  {
1630
1744
  "data-sc-part": "snowcone-editor-header",
@@ -1636,35 +1750,35 @@ function on({
1636
1750
  flexShrink: 0
1637
1751
  },
1638
1752
  children: [
1639
- /* @__PURE__ */ c("span", { style: { fontSize: 14, fontWeight: 700, marginRight: "auto" }, children: e }),
1640
- /* @__PURE__ */ c(W.History, {}),
1641
- /* @__PURE__ */ c(
1642
- nn,
1753
+ /* @__PURE__ */ g("span", { style: { fontSize: 14, fontWeight: 700, marginRight: "auto" }, children: e }),
1754
+ /* @__PURE__ */ g(H.History, {}),
1755
+ /* @__PURE__ */ g(
1756
+ mn,
1643
1757
  {
1644
1758
  fullscreen: l,
1645
- onToggleFullscreen: () => u((E) => !E),
1759
+ onToggleFullscreen: () => d((v) => !v),
1646
1760
  viewCount: n.length,
1647
1761
  viewIndex: a,
1648
- onSelectView: h,
1649
- onExport: () => void g()
1762
+ onSelectView: u,
1763
+ onExport: () => void y()
1650
1764
  }
1651
1765
  ),
1652
- /* @__PURE__ */ c(sn, { onAddToCart: r, defaultQuantity: i })
1766
+ /* @__PURE__ */ g(fn, { onAddToCart: r, defaultQuantity: i })
1653
1767
  ]
1654
1768
  }
1655
1769
  ),
1656
- /* @__PURE__ */ F(
1770
+ /* @__PURE__ */ U(
1657
1771
  "div",
1658
1772
  {
1659
1773
  "data-sc-part": "snowcone-editor-stage",
1660
1774
  style: { position: "relative", flex: 1, minHeight: 0, padding: "4px 12px" },
1661
1775
  children: [
1662
- /* @__PURE__ */ c(W.Canvas, { ref: k, style: { height: "100%" } }),
1663
- p ? (
1776
+ /* @__PURE__ */ g(H.Canvas, { ref: x, style: { height: "100%" } }),
1777
+ c ? (
1664
1778
  // Swapped: the mockup IS the stage; the corner chip returns to the
1665
1779
  // artwork. The canvas stays mounted underneath (no document
1666
1780
  // teardown), just covered.
1667
- /* @__PURE__ */ F(
1781
+ /* @__PURE__ */ U(
1668
1782
  "div",
1669
1783
  {
1670
1784
  "data-sc-part": "snowcone-editor-swap-stage",
@@ -1679,17 +1793,17 @@ function on({
1679
1793
  padding: 8
1680
1794
  },
1681
1795
  children: [
1682
- /* @__PURE__ */ c(
1683
- W.Preview,
1796
+ /* @__PURE__ */ g(
1797
+ H.Preview,
1684
1798
  {
1685
- mockupId: v,
1799
+ mockupId: E,
1686
1800
  alt: "Product mockup",
1687
1801
  loadingOverlay: !0,
1688
- fallback: /* @__PURE__ */ c("div", { "aria-busy": "true", children: "Rendering…" }),
1802
+ fallback: /* @__PURE__ */ g("div", { "aria-busy": "true", children: "Rendering…" }),
1689
1803
  style: { maxWidth: "100%", maxHeight: "100%", borderRadius: 12 }
1690
1804
  }
1691
1805
  ),
1692
- /* @__PURE__ */ c(
1806
+ /* @__PURE__ */ g(
1693
1807
  "button",
1694
1808
  {
1695
1809
  type: "button",
@@ -1697,7 +1811,7 @@ function on({
1697
1811
  "data-sc-part": "snowcone-editor-swap-back",
1698
1812
  onClick: () => b(!1),
1699
1813
  style: {
1700
- ...S,
1814
+ ...O,
1701
1815
  display: "flex",
1702
1816
  alignItems: "center",
1703
1817
  justifyContent: "center",
@@ -1712,21 +1826,21 @@ function on({
1712
1826
  ]
1713
1827
  }
1714
1828
  )
1715
- ) : /* @__PURE__ */ c(
1829
+ ) : /* @__PURE__ */ g(
1716
1830
  "button",
1717
1831
  {
1718
1832
  type: "button",
1719
1833
  "aria-label": "Show product mockup",
1720
1834
  "data-sc-part": "snowcone-editor-pip",
1721
1835
  onClick: () => b(!0),
1722
- style: S,
1723
- children: /* @__PURE__ */ c(
1724
- W.Preview,
1836
+ style: O,
1837
+ children: /* @__PURE__ */ g(
1838
+ H.Preview,
1725
1839
  {
1726
- mockupId: v,
1840
+ mockupId: E,
1727
1841
  alt: "Product mockup preview",
1728
1842
  loadingOverlay: !0,
1729
- fallback: /* @__PURE__ */ c("span", { style: { fontSize: 10, opacity: 0.5 }, "aria-busy": "true", children: "mockup…" }),
1843
+ fallback: /* @__PURE__ */ g("span", { style: { fontSize: 10, opacity: 0.5 }, "aria-busy": "true", children: "mockup…" }),
1730
1844
  style: { width: "100%", height: "100%", display: "block" }
1731
1845
  }
1732
1846
  )
@@ -1735,15 +1849,15 @@ function on({
1735
1849
  ]
1736
1850
  }
1737
1851
  ),
1738
- /* @__PURE__ */ F(
1852
+ /* @__PURE__ */ U(
1739
1853
  "div",
1740
1854
  {
1741
1855
  "data-sc-part": "snowcone-editor-zone",
1742
- "data-sc-zone-state": d ? "selected" : "idle",
1856
+ "data-sc-zone-state": m ? "selected" : "idle",
1743
1857
  style: { flexShrink: 0, padding: "4px 16px 14px" },
1744
1858
  children: [
1745
- /* @__PURE__ */ c("div", { style: { display: d ? void 0 : "none" }, children: /* @__PURE__ */ c(W.Controls, { placement: "docked" }) }),
1746
- d ? null : /* @__PURE__ */ c(rn, {})
1859
+ /* @__PURE__ */ g("div", { style: { display: m ? void 0 : "none" }, children: /* @__PURE__ */ g(H.Controls, { placement: "docked" }) }),
1860
+ m ? null : /* @__PURE__ */ g(pn, {})
1747
1861
  ]
1748
1862
  }
1749
1863
  )
@@ -1751,7 +1865,7 @@ function on({
1751
1865
  }
1752
1866
  );
1753
1867
  }
1754
- function xn(e) {
1868
+ function Dn(e) {
1755
1869
  const {
1756
1870
  onAddToCart: t,
1757
1871
  defaultQuantity: n,
@@ -1761,8 +1875,8 @@ function xn(e) {
1761
1875
  style: o,
1762
1876
  ...l
1763
1877
  } = e;
1764
- return /* @__PURE__ */ c(W.Root, { ...l, children: /* @__PURE__ */ c(
1765
- on,
1878
+ return /* @__PURE__ */ g(H.Root, { ...l, children: /* @__PURE__ */ g(
1879
+ hn,
1766
1880
  {
1767
1881
  title: r,
1768
1882
  height: i,
@@ -1774,26 +1888,26 @@ function xn(e) {
1774
1888
  }
1775
1889
  ) });
1776
1890
  }
1777
- tt();
1891
+ dt();
1778
1892
  export {
1779
- W as E,
1780
- wn as R,
1781
- xn as S,
1782
- vn as a,
1783
- En as b,
1784
- bn as c,
1785
- yn as d,
1786
- wt as e,
1787
- Ae as f,
1788
- Zt as g,
1789
- xt as h,
1790
- _e as i,
1791
- Bt as j,
1792
- Yt as k,
1793
- kn as l,
1794
- Rn as p,
1795
- ye as s,
1796
- Q as u,
1797
- St as v
1893
+ H as E,
1894
+ Nn as R,
1895
+ Dn as S,
1896
+ Cn as a,
1897
+ _n as b,
1898
+ $n as c,
1899
+ On as d,
1900
+ Ot as e,
1901
+ Le as f,
1902
+ ln as g,
1903
+ _t as h,
1904
+ Ue as i,
1905
+ Mt as j,
1906
+ an as k,
1907
+ Tn as l,
1908
+ An as p,
1909
+ Ee as s,
1910
+ te as u,
1911
+ At as v
1798
1912
  };
1799
- //# sourceMappingURL=embed-CLz3CTcX.js.map
1913
+ //# sourceMappingURL=embed-SOFUZlGB.js.map