@snowcone-app/canvas 0.19.0 → 0.20.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 (64) hide show
  1. package/dist/{CanvasRenderer-DUc-MOeR.js → CanvasRenderer-CwiYq8qg.js} +3 -3
  2. package/dist/{CanvasRenderer-DUc-MOeR.js.map → CanvasRenderer-CwiYq8qg.js.map} +1 -1
  3. package/dist/{CanvasStateV1-Bq48qhv5.js → CanvasStateV1-BFabcAKC.js} +35 -30
  4. package/dist/{CanvasStateV1-Bq48qhv5.js.map → CanvasStateV1-BFabcAKC.js.map} +1 -1
  5. package/dist/{ContextualToolbars-CkLjHNPn.js → ContextualToolbars--vTtorNg.js} +5 -5
  6. package/dist/{ContextualToolbars-CkLjHNPn.js.map → ContextualToolbars--vTtorNg.js.map} +1 -1
  7. package/dist/{EditorCanvasImpl-Cthm-KSe.js → EditorCanvasImpl-UBKdG0c0.js} +18 -17
  8. package/dist/{EditorCanvasImpl-Cthm-KSe.js.map → EditorCanvasImpl-UBKdG0c0.js.map} +1 -1
  9. package/dist/{ImportManager-D--7JnvW.js → ExportManager-DK7CdI-G.js} +24758 -24758
  10. package/dist/ExportManager-DK7CdI-G.js.map +1 -0
  11. package/dist/{FontAnalyzer-DIlqmyuf.js → FontAnalyzer-BpsTYowD.js} +5 -2
  12. package/dist/FontAnalyzer-BpsTYowD.js.map +1 -0
  13. package/dist/SnowconeCanvas-B01o5LmS.js +1172 -0
  14. package/dist/SnowconeCanvas-B01o5LmS.js.map +1 -0
  15. package/dist/{MenuButton-CeoEAtzP.js → UnifiedFontService-B1PGVu8O.js} +3704 -3429
  16. package/dist/UnifiedFontService-B1PGVu8O.js.map +1 -0
  17. package/dist/advanced.mjs +13 -13
  18. package/dist/api/embed.d.ts +4 -2
  19. package/dist/api/stable.d.ts +2 -2
  20. package/dist/components/editor/commerceStore.d.ts +22 -2
  21. package/dist/components/editor/index.d.ts +1 -0
  22. package/dist/components/editor/useProductSelection.d.ts +15 -9
  23. package/dist/components/embed/SnowconeCanvas.d.ts +10 -2
  24. package/dist/core/ArtboardElement.d.ts +2 -1
  25. package/dist/default-editor/SnowconeEditor.d.ts +39 -0
  26. package/dist/design/design-builder.d.ts +44 -19
  27. package/dist/design/template-fields.d.ts +32 -0
  28. package/dist/design-builder-DMKx9UXD.js +368 -0
  29. package/dist/design-builder-DMKx9UXD.js.map +1 -0
  30. package/dist/{EditorContext-5QpqAhjh.js → editorErrors-CK1RISFa.js} +382 -358
  31. package/dist/editorErrors-CK1RISFa.js.map +1 -0
  32. package/dist/embed-uALcVSYN.js +1117 -0
  33. package/dist/embed-uALcVSYN.js.map +1 -0
  34. package/dist/embed.mjs +33 -31
  35. package/dist/hooks/useArtboards.d.ts +2 -1
  36. package/dist/index.mjs +8 -8
  37. package/dist/internals.mjs +5 -5
  38. package/dist/kits/sections.d.ts +11 -7
  39. package/dist/rendering/serialize-for-server.d.ts +3 -0
  40. package/dist/state/CanvasStateV1.d.ts +12 -0
  41. package/dist/template-fields-B9RagVpT.js +476 -0
  42. package/dist/template-fields-B9RagVpT.js.map +1 -0
  43. package/dist/testing.mjs +8 -8
  44. package/dist/types/index.d.ts +10 -0
  45. package/dist/{usePieceGuideBundle-DVOISsB1.js → usePieceGuideBundle-Ctnu5k2D.js} +2 -2
  46. package/dist/{usePieceGuideBundle-DVOISsB1.js.map → usePieceGuideBundle-Ctnu5k2D.js.map} +1 -1
  47. package/dist/{validation-0IscSfRb.js → validation-3YEMnKLB.js} +467 -463
  48. package/dist/validation-3YEMnKLB.js.map +1 -0
  49. package/package.json +6 -5
  50. package/dist/EditorContext-5QpqAhjh.js.map +0 -1
  51. package/dist/FontAnalyzer-DIlqmyuf.js.map +0 -1
  52. package/dist/ImportManager-D--7JnvW.js.map +0 -1
  53. package/dist/MenuButton-CeoEAtzP.js.map +0 -1
  54. package/dist/SnowconeCanvas-3PA17na3.js +0 -1166
  55. package/dist/SnowconeCanvas-3PA17na3.js.map +0 -1
  56. package/dist/design-builder-v4935TeS.js +0 -343
  57. package/dist/design-builder-v4935TeS.js.map +0 -1
  58. package/dist/editorErrors-DXNfVXtD.js +0 -29
  59. package/dist/editorErrors-DXNfVXtD.js.map +0 -1
  60. package/dist/embed-D0HHwCIO.js +0 -1093
  61. package/dist/embed-D0HHwCIO.js.map +0 -1
  62. package/dist/template-fields-Dr3fMItw.js +0 -329
  63. package/dist/template-fields-Dr3fMItw.js.map +0 -1
  64. package/dist/validation-0IscSfRb.js.map +0 -1
@@ -0,0 +1,1117 @@
1
+ import { E as ye, o as be, p as ve, C as xe, q, r as we, t as Ee, v as Se, w as ke, x as Ie, g as Re, e as Ce } from "./UnifiedFontService-B1PGVu8O.js";
2
+ import { y as N } from "./FontAnalyzer-BpsTYowD.js";
3
+ import { jsx as s, jsxs as k, Fragment as oe } from "react/jsx-runtime";
4
+ import { useContext as Oe, createContext as Ne, useRef as C, useState as I, useMemo as O, useSyncExternalStore as B, useEffect as A, Component as Te, forwardRef as se, useId as X, useLayoutEffect as W, useCallback as j } from "react";
5
+ import { assertVariantSelected as $e, RenderSession as _e, createCartDetail as De } from "@snowcone-app/sdk";
6
+ import { i as ie, g as F, B as Ve, E as Ae, r as Fe } from "./editorErrors-CK1RISFa.js";
7
+ import { u as Be, p as Ue } from "./usePieceGuideBundle-Ctnu5k2D.js";
8
+ import { s as Z, i as Le } from "./design-builder-DMKx9UXD.js";
9
+ import { D as Pe, C as je, g as qe, e as Me } from "./template-fields-B9RagVpT.js";
10
+ import "./CanvasStateV1-BFabcAKC.js";
11
+ const ae = Ne(void 0);
12
+ function G() {
13
+ const t = Oe(ae);
14
+ if (!t)
15
+ throw new Error(
16
+ "useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered inside <RealtimeEmbed>. Wrap them: <RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>"
17
+ );
18
+ return t;
19
+ }
20
+ const ze = "[RealtimeEmbed]";
21
+ function He(t) {
22
+ var r, o;
23
+ if ((r = t == null ? void 0 : t.requiredPlacements) != null && r.length)
24
+ return t.requiredPlacements.filter((a) => !a.autoFilledByVariant).map((a) => a.label);
25
+ const e = new Set(
26
+ (((o = t == null ? void 0 : t.options) == null ? void 0 : o.combinations) ?? []).map((a) => a.variantId).filter((a) => typeof a == "string" && a !== "")
27
+ );
28
+ return !!(t != null && t.variantId) || e.size > 1 ? [] : (t == null ? void 0 : t.placements) ?? [];
29
+ }
30
+ function ce({ shop: t, product: e, design: n, hasGrant: r }) {
31
+ var l, m;
32
+ const o = [];
33
+ if (t || o.push({
34
+ severity: "error",
35
+ issue: "missing-shop",
36
+ message: "`shop` is required (your publishable shop id)."
37
+ }), r || o.push({
38
+ severity: "error",
39
+ issue: "missing-grant",
40
+ message: "no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) or `grant`. Without it the session can never authorize and no mockup renders."
41
+ }), (l = e == null ? void 0 : e.mockupIds) != null && l.length || o.push({
42
+ severity: "error",
43
+ issue: "empty-mockup-ids",
44
+ message: 'product.mockupIds is empty — pass the catalog scene codes (product.mockups[].id) you want rendered, e.g. ["FV1qjO"].'
45
+ }), e != null && e.options)
46
+ try {
47
+ $e(e);
48
+ } catch (f) {
49
+ o.push({
50
+ severity: "error",
51
+ issue: "variant-required",
52
+ message: f instanceof Error ? f.message : String(f)
53
+ });
54
+ }
55
+ const a = n.toJSON(), c = a.activeArtboard, u = He(e);
56
+ u.length > 1 && o.push({
57
+ severity: "error",
58
+ issue: "multi-placement",
59
+ message: `product ${e.productId} requires placements [${u.join(", ")}] but this embed renders a single placement ("${c}"). The render will time out waiting for the others. This product needs the eject path — see https://developers.snowcone.app/embed-mode#eject.`
60
+ }), (m = e == null ? void 0 : e.placements) != null && m.length && !e.placements.includes(c) && o.push({
61
+ severity: "error",
62
+ issue: "placement-mismatch",
63
+ message: `the design's placement "${c}" is not in product.placements [${e.placements.join(", ")}]. The canvas artboard name and renderState placement must equal a real product placement label, or the server renders a blank mockup. Fix the \`name\` passed to design({ name }).`
64
+ });
65
+ const d = a.elements.map((f) => f.name).filter((f) => !!f), i = d.filter((f, h) => d.indexOf(f) !== h);
66
+ return i.length && o.push({
67
+ severity: "warn",
68
+ issue: "duplicate-layer-names",
69
+ message: `duplicate layer name(s) [${[...new Set(i)].join(", ")}] — useTextBinding(name) / useImageBinding(name) bind to the FIRST match, so a duplicate name makes a control edit the wrong layer. Keep names unique.`
70
+ }), o;
71
+ }
72
+ function Ke(t) {
73
+ for (const e of ce(t))
74
+ (e.severity === "error" && e.issue !== "placement-mismatch" ? console.error : console.warn)(`${ze} ${e.message}`);
75
+ }
76
+ const le = 8e3;
77
+ function We(t) {
78
+ return `[RealtimeEmbed] No mockup after ${Math.round(le / 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 "${t}" — 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 "${t}" not existing on the product. The render may still arrive — this is a heads-up, not a failure.`;
79
+ }
80
+ function Ge(t) {
81
+ if ("grantUrl" in t && t.grantUrl)
82
+ return { grantUrl: t.grantUrl };
83
+ const e = t.grant;
84
+ return typeof e == "function" ? { getToken: e } : { getToken: () => Promise.resolve(e) };
85
+ }
86
+ function de({ error: t, onRetry: e }) {
87
+ const n = ie(t) ? t.code : "EDITOR_ERROR";
88
+ return /* @__PURE__ */ k(
89
+ "div",
90
+ {
91
+ "data-sc-part": "error",
92
+ role: "alert",
93
+ style: {
94
+ padding: "16px",
95
+ borderRadius: "12px",
96
+ border: "1px solid var(--sc-color-destructive, #b91c1c)",
97
+ background: "var(--sc-color-surface, #fef2f2)",
98
+ color: "var(--sc-color-foreground, #7f1d1d)",
99
+ fontFamily: "ui-sans-serif, system-ui, sans-serif",
100
+ fontSize: "13px",
101
+ lineHeight: 1.5
102
+ },
103
+ children: [
104
+ /* @__PURE__ */ k("p", { style: { margin: 0, fontWeight: 700 }, children: [
105
+ "Editor failed: ",
106
+ n
107
+ ] }),
108
+ /* @__PURE__ */ s("p", { style: { margin: "4px 0 0" }, children: t.message }),
109
+ e ? /* @__PURE__ */ s(
110
+ "button",
111
+ {
112
+ type: "button",
113
+ "data-sc-part": "error-retry",
114
+ onClick: e,
115
+ style: {
116
+ marginTop: "10px",
117
+ padding: "6px 14px",
118
+ borderRadius: "9999px",
119
+ border: "1px solid currentColor",
120
+ background: "transparent",
121
+ color: "inherit",
122
+ font: "inherit",
123
+ fontWeight: 600,
124
+ cursor: "pointer"
125
+ },
126
+ children: "Retry"
127
+ }
128
+ ) : null
129
+ ]
130
+ }
131
+ );
132
+ }
133
+ class Qe extends Te {
134
+ constructor() {
135
+ super(...arguments), this.state = { caught: null };
136
+ }
137
+ static getDerivedStateFromError(e) {
138
+ return { caught: e };
139
+ }
140
+ componentDidCatch(e) {
141
+ var n;
142
+ Fe(e), typeof N < "u" && ((n = N.env) == null ? void 0 : n.NODE_ENV) !== "production" && console.error("[Editor.Root] contained a composition error:", e);
143
+ }
144
+ render() {
145
+ return this.state.caught ? /* @__PURE__ */ s(de, { error: this.state.caught }) : this.props.children;
146
+ }
147
+ }
148
+ function Je({ reportedError: t, onRetry: e, children: n }) {
149
+ if (t) {
150
+ const r = ie(t) && t.code === "E_CHUNK_LOAD_FAILED";
151
+ return /* @__PURE__ */ s(de, { error: t, onRetry: r ? e : void 0 });
152
+ }
153
+ return /* @__PURE__ */ s(Qe, { reportedError: null, onRetry: e, children: n });
154
+ }
155
+ function Ye(t) {
156
+ const {
157
+ shop: e,
158
+ product: n,
159
+ design: r,
160
+ throttleMs: o = 200,
161
+ onMockups: a,
162
+ onRenderError: c,
163
+ wsUrl: u,
164
+ services: d,
165
+ children: i,
166
+ internals: l,
167
+ __validation: m = "throw"
168
+ } = t, f = O(() => r.toJSON().activeArtboard, [r]);
169
+ B(
170
+ l.commerce.subscribe,
171
+ l.commerce.getVersion,
172
+ l.commerce.getVersion
173
+ );
174
+ const h = l.commerce.resolvedVariantId(), p = Be(h ?? n.variantId ?? n.defaultGvid), w = O(() => {
175
+ if (!p) return null;
176
+ const g = r.toJSON().artboards[0];
177
+ return Ue(p, g) ?? null;
178
+ }, [p, r]), E = C(a), b = C(c);
179
+ E.current = a, b.current = c;
180
+ const [T, R] = I([]), [D, x] = I(!0), [$, _] = I(null), U = !!("grantUrl" in t && t.grantUrl || "grant" in t && t.grant), P = Ge(t), pe = "grantUrl" in P ? P.grantUrl : "getToken", ee = `${n.productId}|${n.mockupIds.join(",")}|${n.variantId ?? ""}`, M = `${e}|${ee}|${f}|${U}`;
181
+ O(() => {
182
+ var S;
183
+ if (m !== "throw") return;
184
+ const g = ce({ shop: e, product: n, design: r, hasGrant: U }), y = g.find((L) => L.severity === "error");
185
+ if (y)
186
+ throw new F("E_EMBED_CONFIG", y.message, {
187
+ issue: y.issue,
188
+ docSlug: "embed-mode"
189
+ });
190
+ for (const L of g)
191
+ typeof N < "u" && ((S = N.env) == null ? void 0 : S.NODE_ENV) !== "production" && console.warn(`[Editor.Root] ${L.message}`);
192
+ }, [M, m]);
193
+ const te = C(null);
194
+ A(() => {
195
+ var g;
196
+ if (m === "warn" && typeof N < "u" && ((g = N.env) == null ? void 0 : g.NODE_ENV) !== "production") {
197
+ if (te.current === M) return;
198
+ te.current = M, Ke({ shop: e, product: n, design: r, hasGrant: U });
199
+ }
200
+ }, [M, m]);
201
+ const z = O(
202
+ () => {
203
+ try {
204
+ return { session: new _e({ shop: e, product: n, wsUrl: u, ...P }) };
205
+ } catch (g) {
206
+ return { error: g instanceof Error ? g.message : String(g) };
207
+ }
208
+ },
209
+ // eslint-disable-next-line react-hooks/exhaustive-deps
210
+ [e, ee, f, u, pe]
211
+ ), v = "session" in z ? z.session : null, H = "error" in z ? z.error : null, K = O(() => (g, y = o) => {
212
+ v && (_(null), x(!0), v.renderState(f, g, y).catch((S) => {
213
+ var re;
214
+ const L = S instanceof Error ? S.message : String(S);
215
+ _(L), x(!1), (re = b.current) == null || re.call(b, L);
216
+ }));
217
+ }, [v, f, o]);
218
+ A(() => {
219
+ var g;
220
+ if (H) {
221
+ _(H), x(!1), (g = b.current) == null || g.call(b, H);
222
+ return;
223
+ }
224
+ if (v)
225
+ return v.onMockups((y) => {
226
+ var S;
227
+ R(y), x(!1), (S = E.current) == null || S.call(E, y);
228
+ }), v.onError((y) => {
229
+ var S;
230
+ _(y), x(!1), (S = b.current) == null || S.call(b, y);
231
+ }), K(r.toServerRequest()), () => v.close();
232
+ }, [v, H]);
233
+ const Q = C({
234
+ session: null,
235
+ variantId: void 0
236
+ });
237
+ A(() => {
238
+ if (!v || !h) return;
239
+ const g = Q.current, y = g.session === v ? g.variantId : n.variantId;
240
+ if (h === y) {
241
+ Q.current = { session: v, variantId: y };
242
+ return;
243
+ }
244
+ Q.current = { session: v, variantId: h }, v.setProduct({ ...n, variantId: h }), K(Z(l.store.getState()));
245
+ }, [v, h]), A(() => {
246
+ var y;
247
+ if (!D || typeof N > "u" || ((y = N.env) == null ? void 0 : y.NODE_ENV) === "production") return;
248
+ const g = setTimeout(() => console.warn(We(f)), le);
249
+ return () => clearTimeout(g);
250
+ }, [D, f]);
251
+ const ge = O(
252
+ () => ({
253
+ session: v,
254
+ design: r,
255
+ placement: f,
256
+ product: n,
257
+ mockups: T,
258
+ isRendering: D,
259
+ error: $,
260
+ throttleMs: o,
261
+ pieceGuides: w,
262
+ pushRender: K,
263
+ stateStore: l.store
264
+ }),
265
+ [v, r, f, n, T, D, $, o, w, K, l.store]
266
+ ), he = B(
267
+ l.registry.subscribe,
268
+ l.registry.getVersion,
269
+ l.registry.getVersion
270
+ );
271
+ O(() => l.registry.validate(), [l.registry, he]);
272
+ const ne = /* @__PURE__ */ s(ve.Provider, { value: l, children: /* @__PURE__ */ s(ae.Provider, { value: ge, children: /* @__PURE__ */ s(Ve.Provider, { value: l.registry, children: /* @__PURE__ */ s(Ae, { children: i }) }) }) });
273
+ return d ? /* @__PURE__ */ s(xe, { services: d, children: ne }) : ne;
274
+ }
275
+ function ue(t) {
276
+ const { design: e, product: n } = t, r = `${n.productId}|${n.variantId ?? ""}`, o = C(null), a = C(null), [c, u] = I(null);
277
+ (o.current === null || o.current.design !== e) && (o.current = {
278
+ design: e,
279
+ internals: {
280
+ store: new Pe(e.toJSON()),
281
+ registry: new ye()
282
+ }
283
+ }), (a.current === null || a.current.productIdentity !== r) && (a.current = { productIdentity: r, commerce: new je(n) });
284
+ const d = O(
285
+ () => ({
286
+ ...o.current.internals,
287
+ commerce: a.current.commerce,
288
+ ...be(u)
289
+ }),
290
+ // eslint-disable-next-line react-hooks/exhaustive-deps
291
+ [o.current.internals, a.current.commerce]
292
+ );
293
+ return (
294
+ // `display: contents` — the .sc-root scope without a layout box, so the
295
+ // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed
296
+ // wrapper, which had no DOM at all, stays layout-identical).
297
+ /* @__PURE__ */ s("div", { className: "sc-root", style: { display: "contents" }, "data-sc-part": "root", children: /* @__PURE__ */ s(Je, { reportedError: c, onRetry: () => u(null), children: /* @__PURE__ */ s(Ye, { ...t, internals: d }) }) })
298
+ );
299
+ }
300
+ let Xe = () => import("./EditorCanvasImpl-UBKdG0c0.js").then((t) => t.EditorCanvasImpl);
301
+ function me() {
302
+ return Xe();
303
+ }
304
+ const Ze = se(function({ children: e, maxHeight: n, className: r, style: o }, a) {
305
+ const c = q("Editor.Canvas"), u = X();
306
+ W(() => c.registry.registerCanvas(u), [c.registry, u]);
307
+ const [d, i] = I(null);
308
+ return A(() => {
309
+ let l = !1;
310
+ return me().then(
311
+ (m) => {
312
+ l || i(() => m);
313
+ },
314
+ (m) => {
315
+ l || c.reportRuntimeError(
316
+ new F(
317
+ "E_CHUNK_LOAD_FAILED",
318
+ `the editor's rendering chunk failed to load (${m instanceof Error ? m.message : String(m)}). This is a network/CDN failure, not a composition mistake — retry, or check the deployment serves the @snowcone-app/canvas lazy chunks.`,
319
+ { cause: m instanceof Error ? m.message : String(m), docSlug: "embed-mode" }
320
+ )
321
+ );
322
+ }
323
+ ), () => {
324
+ l = !0;
325
+ };
326
+ }, [c]), d ? (
327
+ // `builtinControls`: the canvas owns the floating contextual toolbar
328
+ // unless a docked <Editor.Controls> is mounted (ADR-0085 §5). Only here —
329
+ // the legacy <RealtimeCanvas> wrapper stays chrome-less.
330
+ /* @__PURE__ */ s(d, { ref: a, kit: "embed-only", partAttr: "canvas", builtinControls: !0, maxHeight: n, className: r, style: o, children: e })
331
+ ) : /* @__PURE__ */ s(
332
+ "div",
333
+ {
334
+ "data-sc-part": "canvas",
335
+ "data-sc-state": "loading",
336
+ className: r,
337
+ style: { minHeight: n ?? 200, ...o },
338
+ "aria-busy": "true"
339
+ }
340
+ );
341
+ }), et = 1.2, J = [1200, 1400, 1600, 1800, 2e3, 2500, 3e3, 4e3];
342
+ function tt(t) {
343
+ for (const e of J)
344
+ if (e >= t) return e;
345
+ return J[J.length - 1];
346
+ }
347
+ function nt(t, e) {
348
+ if (!(t > 0) || !(e > 0) || e <= t * et) return null;
349
+ const n = tt(e);
350
+ return `[RealtimeMockup] mockup rendered at ${t}px but displayed at ~${e} device px — the preview will look soft. Pass \`product.width\` (e.g. ${n}) on the embed for a crisp preview.`;
351
+ }
352
+ function fe({
353
+ mockupId: t,
354
+ fallback: e = null,
355
+ alt: n = "Live product mockup",
356
+ className: r,
357
+ style: o
358
+ }) {
359
+ const { mockups: a, error: c } = G(), u = C(/* @__PURE__ */ new Set()), d = t ? a.find((l) => l.mockupId === t && l.imageUrl) : a.find((l) => l.imageUrl);
360
+ if (!(d != null && d.imageUrl))
361
+ return c ? /* @__PURE__ */ s("div", { "data-sc-part": "preview-error", role: "alert", "data-sc-error": c, className: r, style: o, children: e ?? `Render failed: ${c}` }) : /* @__PURE__ */ s(oe, { children: e });
362
+ const i = (l) => {
363
+ var w;
364
+ if (typeof N > "u" || ((w = N.env) == null ? void 0 : w.NODE_ENV) === "production" || typeof window > "u" || u.current.has(d.mockupId)) return;
365
+ const m = l.currentTarget, f = m.getBoundingClientRect().width;
366
+ if (f <= 0) return;
367
+ const h = Math.round(f * (window.devicePixelRatio || 1)), p = nt(m.naturalWidth, h);
368
+ p && (u.current.add(d.mockupId), console.warn(p));
369
+ };
370
+ return (
371
+ // eslint-disable-next-line @next/next/no-img-element
372
+ /* @__PURE__ */ s(
373
+ "img",
374
+ {
375
+ "data-sc-part": "preview",
376
+ src: d.imageUrl,
377
+ alt: n,
378
+ className: r,
379
+ style: o,
380
+ onLoad: i
381
+ }
382
+ )
383
+ );
384
+ }
385
+ function rt(t) {
386
+ const { layer: e, optional: n = !1, placeholder: r, className: o, style: a } = t, c = q("Editor.TextField"), { pushRender: u, throttleMs: d, stateStore: i } = G(), l = X(), m = C(null);
387
+ if (!Le(e))
388
+ throw new F(
389
+ "E_LAYER_TOKEN_REQUIRED",
390
+ `the \`layer\` prop must be a token minted by the design — pass layer={design.layer("name")}, not ${typeof e == "string" ? `the bare string "${e}"` : "a plain value"}. Tokens validate the name against the design's layers at mint time.`,
391
+ { received: typeof e == "string" ? e : typeof e, docSlug: "embed-mode" }
392
+ );
393
+ if (m.current !== e.name) {
394
+ const p = i.layerKindOf(e.name);
395
+ if (p === void 0)
396
+ throw new F(
397
+ "E_LAYER_NOT_FOUND",
398
+ `no layer "${e.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(i.bindableLayerNames())}.`,
399
+ { layerName: e.name, validNames: i.bindableLayerNames(), docSlug: "embed-mode" }
400
+ );
401
+ if (p !== "text")
402
+ throw new F(
403
+ "E_LAYER_WRONG_KIND",
404
+ `layer "${e.name}" is ${p === null ? "not a bindable kind" : `an ${p} layer`} — <Editor.TextField> binds text layers only.`,
405
+ { layerName: e.name, actualKind: p, docSlug: "embed-mode" }
406
+ );
407
+ m.current = e.name;
408
+ }
409
+ W(() => c.registry.registerTextField(l, { name: e.name, optional: n }), [c.registry, l, e.name, n]);
410
+ const f = B(
411
+ i.subscribe,
412
+ () => i.textOf(e.name) ?? "",
413
+ () => i.textOf(e.name) ?? ""
414
+ ), h = j(
415
+ (p) => {
416
+ const w = p.target.value, E = c.registry.getCanvasBridge();
417
+ if (E) {
418
+ E.setTextByName(e.name, w) || c.reportInvariant(
419
+ new F(
420
+ "E_LAYER_NOT_FOUND",
421
+ `layer "${e.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).`,
422
+ { layerName: e.name, docSlug: "embed-mode" }
423
+ )
424
+ );
425
+ return;
426
+ }
427
+ i.updateTextLayer(e.name, w), u(Z(i.getState()), d);
428
+ },
429
+ [c, e.name, i, u, d]
430
+ );
431
+ return /* @__PURE__ */ s(
432
+ "input",
433
+ {
434
+ "data-sc-part": "textfield",
435
+ "data-sc-layer": e.name,
436
+ type: "text",
437
+ value: f,
438
+ onChange: h,
439
+ placeholder: r,
440
+ "aria-label": t["aria-label"] ?? e.name,
441
+ className: o,
442
+ style: a
443
+ }
444
+ );
445
+ }
446
+ function ot(t) {
447
+ const e = [];
448
+ for (const n of t.missingOptionKeys)
449
+ e.push(`option:${n}`);
450
+ t.missingOptionKeys.length === 0 && !t.selectionValid && e.push("variant");
451
+ for (const n of t.textFields) {
452
+ if (n.optional) continue;
453
+ const r = (t.textOf(n.name) ?? "").trim();
454
+ if (r.length === 0) {
455
+ e.push(`layer:${n.name}`);
456
+ continue;
457
+ }
458
+ const o = (t.seedTextOf(n.name) ?? "").trim();
459
+ o.length > 0 && r === o && e.push(`layer-seed:${n.name}`);
460
+ }
461
+ return t.hasRenderableElement || e.push("empty-design"), (!Number.isInteger(t.quantity) || t.quantity < 1) && e.push("quantity"), e;
462
+ }
463
+ function st(t, e) {
464
+ const n = e.getCombinations(), r = e.getAttributes();
465
+ if (Object.keys(r).length === 0 || n.length === 0) return null;
466
+ const o = Object.fromEntries(
467
+ Object.entries(r).map(([a, c]) => [a, { ...c, choices: qe(c) }])
468
+ );
469
+ return De({
470
+ productId: t.productId,
471
+ quantity: e.getQuantity(),
472
+ selection: e.getSelection(),
473
+ combinations: n,
474
+ attributes: o
475
+ });
476
+ }
477
+ function it(t) {
478
+ const { onAddToCart: e, defaultQuantity: n, children: r, className: o, style: a } = t, c = q("Editor.Buy"), { product: u, stateStore: d } = G(), i = c.commerce;
479
+ if (!(u != null && u.productId))
480
+ throw new F(
481
+ "E_BUY_NO_PRODUCT",
482
+ "<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.",
483
+ { docSlug: "embed-mode" }
484
+ );
485
+ const l = C(!1);
486
+ W(() => {
487
+ l.current || (l.current = !0, typeof n == "number" && i.setQuantity(n));
488
+ }, [i]);
489
+ const m = B(d.subscribe, d.getState, d.getState), f = B(i.subscribe, i.getVersion, i.getVersion), h = B(
490
+ c.registry.subscribe,
491
+ c.registry.getVersion,
492
+ c.registry.getVersion
493
+ ), p = i.getQuantity(), w = O(
494
+ () => ot({
495
+ quantity: p,
496
+ missingOptionKeys: i.missingOptionKeys(),
497
+ selectionValid: i.selectionValid(),
498
+ textFields: c.registry.getTextFields(),
499
+ textOf: (x) => d.textOf(x),
500
+ seedTextOf: (x) => d.seedTextOf(x),
501
+ hasRenderableElement: d.hasRenderableElement()
502
+ }),
503
+ // eslint-disable-next-line react-hooks/exhaustive-deps
504
+ [i, p, m, f, h]
505
+ ), E = w.length === 0, [b, T] = I(!1), R = C(!1), D = j(() => {
506
+ if (R.current || !E) return;
507
+ R.current = !0, T(!0);
508
+ const x = d.getState(), $ = i.resolvedVariantId(), _ = {
509
+ productId: u.productId,
510
+ ...$ ? { variantId: $ } : {},
511
+ quantity: i.getQuantity(),
512
+ selection: i.getSelection(),
513
+ cartDetail: st(u, i),
514
+ designState: x,
515
+ serverRequest: Z(x)
516
+ };
517
+ let U;
518
+ try {
519
+ U = e(_);
520
+ } catch (P) {
521
+ throw R.current = !1, T(!1), P;
522
+ }
523
+ Promise.resolve(U).finally(() => {
524
+ R.current = !1, T(!1);
525
+ });
526
+ }, [E, u, i, d, e]);
527
+ return /* @__PURE__ */ s(
528
+ "button",
529
+ {
530
+ type: "button",
531
+ "data-sc-part": "buy",
532
+ "data-sc-buy-state": b ? "busy" : E ? "ready" : "incomplete",
533
+ "data-sc-buy-missing": w.join(",") || void 0,
534
+ disabled: !E || b,
535
+ "aria-busy": b || void 0,
536
+ onClick: D,
537
+ className: o,
538
+ style: a,
539
+ children: r ?? "Add to cart"
540
+ }
541
+ );
542
+ }
543
+ function at({
544
+ placement: t = "docked",
545
+ className: e,
546
+ style: n
547
+ }) {
548
+ const r = q("Editor.Controls");
549
+ we("Editor.Controls");
550
+ const o = X();
551
+ W(
552
+ () => r.registry.registerControls(o, t),
553
+ [r.registry, o, t]
554
+ );
555
+ const a = t === "docked", [c, u] = I(null);
556
+ return A(() => {
557
+ if (!a) return;
558
+ let d = !1;
559
+ return import("./ContextualToolbars--vTtorNg.js").then((i) => i.x).then(
560
+ (i) => {
561
+ d || u(() => i.ContextualToolbars);
562
+ },
563
+ (i) => {
564
+ d || r.reportRuntimeError(
565
+ new F(
566
+ "E_CHUNK_LOAD_FAILED",
567
+ `the editor's controls chunk failed to load (${i instanceof Error ? i.message : String(i)}). This is a network/CDN failure, not a composition mistake — retry, or check the deployment serves the @snowcone-app/canvas lazy chunks.`,
568
+ { cause: i instanceof Error ? i.message : String(i), docSlug: "embed-mode" }
569
+ )
570
+ );
571
+ }
572
+ ), () => {
573
+ d = !0;
574
+ };
575
+ }, [a, r]), a ? /* @__PURE__ */ s(
576
+ "div",
577
+ {
578
+ "data-sc-part": "controls",
579
+ "data-sc-placement": "docked",
580
+ className: e,
581
+ style: n,
582
+ "aria-busy": c ? void 0 : "true",
583
+ children: c ? /* @__PURE__ */ s(c, { mode: "embedded" }) : null
584
+ }
585
+ ) : null;
586
+ }
587
+ function ct() {
588
+ const e = q("useProductSelection").commerce, n = B(e.subscribe, e.getVersion, e.getVersion), r = j((a, c) => e.select(a, c), [e]), o = j((a) => e.setQuantity(a), [e]);
589
+ return O(
590
+ () => ({
591
+ attributes: e.getAttributes(),
592
+ selection: e.getSelection(),
593
+ select: r,
594
+ disabledChoices: e.disabledChoices(),
595
+ variantId: e.resolvedVariantId(),
596
+ price: e.resolvedPrice(),
597
+ quantity: e.getQuantity(),
598
+ setQuantity: o,
599
+ complete: e.selectionValid(),
600
+ missing: e.missingOptionKeys()
601
+ }),
602
+ // eslint-disable-next-line react-hooks/exhaustive-deps
603
+ [e, r, o, n]
604
+ );
605
+ }
606
+ const V = {
607
+ /** The one provider boundary — session, design, live state, error boundary. */
608
+ Root: ue,
609
+ /** The editable artboard (the ONE lazy renderer boundary — D9). */
610
+ Canvas: Ze,
611
+ /** Live product mockup. ×N under one Root is valid. */
612
+ Preview: fe,
613
+ /** Form input bound to a design text layer by typed token (T1). */
614
+ TextField: rt,
615
+ /** Smart commerce part: completeness + payload assembly; submit = host callback. */
616
+ Buy: it,
617
+ /** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */
618
+ Layers: Ie,
619
+ /** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */
620
+ Controls: at,
621
+ /** Undo/redo controls. Requires Editor.Canvas. */
622
+ History: ke,
623
+ /** The one ⋯ overflow menu. Requires Editor.Canvas. */
624
+ Menu: Se,
625
+ /** The ⊕ add-element menu. Requires Editor.Canvas. */
626
+ Add: Ee
627
+ };
628
+ function Rt(t) {
629
+ return /* @__PURE__ */ s(ue, { ...t, __validation: "warn" });
630
+ }
631
+ const Ct = se(
632
+ function(e, n) {
633
+ const { children: r, className: o, style: a, maxHeight: c, ...u } = e, [d, i] = I(null);
634
+ return A(() => {
635
+ let l = !1;
636
+ return me().then(
637
+ (m) => {
638
+ l || i(() => m);
639
+ },
640
+ (m) => {
641
+ console.error("[RealtimeCanvas] failed to load the rendering chunk:", m);
642
+ }
643
+ ), () => {
644
+ l = !0;
645
+ };
646
+ }, []), d ? /* @__PURE__ */ s(d, { ref: n, selfScope: !0, maxHeight: c, className: o, style: a, ...u, children: r }) : /* @__PURE__ */ s(
647
+ "div",
648
+ {
649
+ className: `sc-root${o ? ` ${o}` : ""}`,
650
+ style: { minHeight: c ?? 200, ...a },
651
+ "aria-busy": "true"
652
+ }
653
+ );
654
+ }
655
+ );
656
+ function Ot(t) {
657
+ return /* @__PURE__ */ s(fe, { ...t });
658
+ }
659
+ function Nt() {
660
+ const { mockups: t, isRendering: e, error: n } = G();
661
+ return { mockups: t, isRendering: e, error: n };
662
+ }
663
+ function lt(t) {
664
+ return new Intl.NumberFormat("en-US", {
665
+ style: "currency",
666
+ currency: "USD",
667
+ minimumFractionDigits: t % 100 === 0 ? 0 : 2,
668
+ maximumFractionDigits: t % 100 === 0 ? 0 : 2
669
+ }).format(t / 100);
670
+ }
671
+ const dt = {
672
+ display: "inline-flex",
673
+ alignItems: "center",
674
+ justifyContent: "center",
675
+ width: 32,
676
+ height: 32,
677
+ padding: 0,
678
+ borderRadius: 9999,
679
+ border: "none",
680
+ background: "transparent",
681
+ color: "var(--sc-color-foreground, #111)",
682
+ font: "inherit",
683
+ fontSize: 16,
684
+ lineHeight: 1,
685
+ cursor: "pointer"
686
+ }, ut = {
687
+ display: "flex",
688
+ alignItems: "center",
689
+ gap: 10,
690
+ width: "100%",
691
+ padding: "8px 10px",
692
+ borderRadius: 8,
693
+ border: "none",
694
+ background: "transparent",
695
+ color: "inherit",
696
+ font: "inherit",
697
+ fontSize: 12,
698
+ fontWeight: 500,
699
+ textAlign: "left",
700
+ cursor: "pointer"
701
+ };
702
+ function Y({
703
+ label: t,
704
+ onSelect: e
705
+ }) {
706
+ return /* @__PURE__ */ s(
707
+ "button",
708
+ {
709
+ type: "button",
710
+ role: "menuitem",
711
+ "data-sc-part": "snowcone-editor-menu-item",
712
+ style: ut,
713
+ onClick: e,
714
+ children: t
715
+ }
716
+ );
717
+ }
718
+ function mt({
719
+ fullscreen: t,
720
+ onToggleFullscreen: e,
721
+ viewCount: n,
722
+ viewIndex: r,
723
+ onSelectView: o,
724
+ onExport: a
725
+ }) {
726
+ const [c, u] = I(!1), d = () => u(!1);
727
+ return /* @__PURE__ */ k("div", { style: { position: "relative" }, children: [
728
+ /* @__PURE__ */ s(
729
+ "button",
730
+ {
731
+ type: "button",
732
+ "aria-label": "Editor menu",
733
+ "aria-haspopup": "menu",
734
+ "aria-expanded": c,
735
+ "data-sc-part": "snowcone-editor-menu",
736
+ style: dt,
737
+ onClick: () => u((i) => !i),
738
+ children: "⋮"
739
+ }
740
+ ),
741
+ c ? /* @__PURE__ */ k(oe, { children: [
742
+ /* @__PURE__ */ s(
743
+ "div",
744
+ {
745
+ style: { position: "fixed", inset: 0, zIndex: 39 },
746
+ onClick: d,
747
+ "aria-hidden": "true"
748
+ }
749
+ ),
750
+ /* @__PURE__ */ k(
751
+ "div",
752
+ {
753
+ role: "menu",
754
+ "data-sc-part": "snowcone-editor-menu-list",
755
+ style: {
756
+ position: "absolute",
757
+ right: 0,
758
+ top: "100%",
759
+ marginTop: 4,
760
+ minWidth: 176,
761
+ padding: 4,
762
+ borderRadius: 12,
763
+ background: "var(--sc-color-surface, #fff)",
764
+ boxShadow: "0 8px 24px rgba(0,0,0,0.14)",
765
+ border: "1px solid rgba(0,0,0,0.08)",
766
+ zIndex: 40
767
+ },
768
+ children: [
769
+ /* @__PURE__ */ s(
770
+ Y,
771
+ {
772
+ label: t ? "Exit fullscreen" : "Fullscreen",
773
+ onSelect: () => {
774
+ d(), e();
775
+ }
776
+ }
777
+ ),
778
+ n > 1 ? Array.from({ length: n }, (i, l) => /* @__PURE__ */ s(
779
+ Y,
780
+ {
781
+ label: `View ${l + 1}${l === r ? " ✓" : ""}`,
782
+ onSelect: () => {
783
+ d(), o(l);
784
+ }
785
+ },
786
+ l
787
+ )) : null,
788
+ /* @__PURE__ */ s(
789
+ Y,
790
+ {
791
+ label: "Export PNG",
792
+ onSelect: () => {
793
+ d(), a();
794
+ }
795
+ }
796
+ )
797
+ ]
798
+ }
799
+ )
800
+ ] }) : null
801
+ ] });
802
+ }
803
+ function ft() {
804
+ const { flatLayers: t, selectLayer: e, generateAllPreviews: n } = Re({ previewSize: 96 });
805
+ return A(() => {
806
+ t.length > 0 && n();
807
+ }, [t.length, n]), /* @__PURE__ */ k(
808
+ "div",
809
+ {
810
+ "data-sc-part": "snowcone-editor-idle-dock",
811
+ style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 8, minHeight: 44 },
812
+ children: [
813
+ /* @__PURE__ */ s(V.Add, {}),
814
+ t.length > 0 ? /* @__PURE__ */ s("div", { style: { width: 1, height: 28, background: "rgba(0,0,0,0.1)", flexShrink: 0 }, "aria-hidden": "true" }) : null,
815
+ t.map((r) => /* @__PURE__ */ s(
816
+ "button",
817
+ {
818
+ type: "button",
819
+ "data-sc-part": "snowcone-editor-layer-thumb",
820
+ "aria-label": `Select ${r.name}`,
821
+ onClick: () => e(r.id),
822
+ style: {
823
+ width: 44,
824
+ height: 44,
825
+ padding: 2,
826
+ borderRadius: 12,
827
+ border: "1px solid rgba(0,0,0,0.1)",
828
+ background: "var(--sc-color-surface, #fff)",
829
+ overflow: "hidden",
830
+ cursor: "pointer",
831
+ flexShrink: 0,
832
+ display: "inline-flex",
833
+ alignItems: "center",
834
+ justifyContent: "center"
835
+ },
836
+ children: r.previewUrl ? (
837
+ // eslint-disable-next-line @next/next/no-img-element
838
+ /* @__PURE__ */ s("img", { src: r.previewUrl, alt: "", style: { width: "100%", height: "100%", objectFit: "contain" } })
839
+ ) : /* @__PURE__ */ s(
840
+ "span",
841
+ {
842
+ style: {
843
+ fontSize: 10,
844
+ fontWeight: 600,
845
+ maxWidth: "100%",
846
+ overflow: "hidden",
847
+ textOverflow: "ellipsis",
848
+ whiteSpace: "nowrap"
849
+ },
850
+ children: r.name
851
+ }
852
+ )
853
+ },
854
+ r.id
855
+ ))
856
+ ]
857
+ }
858
+ );
859
+ }
860
+ function pt({
861
+ onAddToCart: t,
862
+ defaultQuantity: e
863
+ }) {
864
+ const { price: n, complete: r } = ct();
865
+ return /* @__PURE__ */ k(
866
+ V.Buy,
867
+ {
868
+ onAddToCart: t,
869
+ ...typeof e == "number" ? { defaultQuantity: e } : {},
870
+ style: {
871
+ display: "inline-flex",
872
+ alignItems: "center",
873
+ gap: 6,
874
+ padding: "7px 16px",
875
+ marginLeft: 4,
876
+ borderRadius: 9999,
877
+ border: "none",
878
+ background: "var(--sc-color-foreground, #111)",
879
+ color: "var(--sc-color-surface, #fff)",
880
+ font: "inherit",
881
+ fontSize: 12,
882
+ fontWeight: 700,
883
+ whiteSpace: "nowrap",
884
+ cursor: r ? "pointer" : "not-allowed",
885
+ opacity: r ? 1 : 0.5
886
+ },
887
+ children: [
888
+ "Add to cart",
889
+ typeof n == "number" ? ` · ${lt(n)}` : ""
890
+ ]
891
+ }
892
+ );
893
+ }
894
+ function gt({
895
+ title: t,
896
+ height: e,
897
+ mockupIds: n,
898
+ onAddToCart: r,
899
+ defaultQuantity: o,
900
+ className: a,
901
+ style: c
902
+ }) {
903
+ const [u, d] = I(!1), [i, l] = I(0), [m, f] = I(!1), h = C(null), p = Me(), w = n[Math.min(i, n.length - 1)], E = j(async () => {
904
+ var _;
905
+ const R = await ((_ = h.current) == null ? void 0 : _.exportArtboards({ format: "dataUrl" }));
906
+ if (!R) return;
907
+ const [D, x] = Object.entries(R)[0] ?? [];
908
+ if (typeof x != "string") return;
909
+ const $ = document.createElement("a");
910
+ $.href = x, $.download = `${D ?? "design"}.png`, $.click();
911
+ }, []), b = {
912
+ display: "flex",
913
+ flexDirection: "column",
914
+ overflow: "hidden",
915
+ background: "var(--sc-color-surface, #fff)",
916
+ color: "var(--sc-color-foreground, #111)",
917
+ fontFamily: "ui-sans-serif, system-ui, sans-serif",
918
+ ...u ? {
919
+ position: "fixed",
920
+ inset: 0,
921
+ zIndex: 9999,
922
+ height: "100dvh",
923
+ paddingBottom: "env(safe-area-inset-bottom)"
924
+ } : {
925
+ position: "relative",
926
+ height: e,
927
+ borderRadius: 16,
928
+ border: "1px solid rgba(0,0,0,0.08)",
929
+ boxShadow: "0 1px 3px rgba(0,0,0,0.08)"
930
+ },
931
+ ...c
932
+ }, T = {
933
+ position: "absolute",
934
+ top: 8,
935
+ right: 12,
936
+ width: 96,
937
+ aspectRatio: "2 / 3",
938
+ borderRadius: 12,
939
+ overflow: "hidden",
940
+ border: "1px solid rgba(0,0,0,0.1)",
941
+ boxShadow: "0 4px 12px rgba(0,0,0,0.12)",
942
+ background: "var(--sc-color-surface, #fff)",
943
+ padding: 0,
944
+ cursor: "pointer",
945
+ zIndex: 2
946
+ };
947
+ return /* @__PURE__ */ k(
948
+ "div",
949
+ {
950
+ "data-sc-part": "snowcone-editor",
951
+ "data-sc-fullscreen": u ? "true" : void 0,
952
+ className: a,
953
+ style: b,
954
+ children: [
955
+ /* @__PURE__ */ k(
956
+ "div",
957
+ {
958
+ "data-sc-part": "snowcone-editor-header",
959
+ style: {
960
+ display: "flex",
961
+ alignItems: "center",
962
+ gap: 2,
963
+ padding: "10px 12px 4px 16px",
964
+ flexShrink: 0
965
+ },
966
+ children: [
967
+ /* @__PURE__ */ s("span", { style: { fontSize: 14, fontWeight: 700, marginRight: "auto" }, children: t }),
968
+ /* @__PURE__ */ s(V.History, {}),
969
+ /* @__PURE__ */ s(
970
+ mt,
971
+ {
972
+ fullscreen: u,
973
+ onToggleFullscreen: () => d((R) => !R),
974
+ viewCount: n.length,
975
+ viewIndex: i,
976
+ onSelectView: l,
977
+ onExport: () => void E()
978
+ }
979
+ ),
980
+ /* @__PURE__ */ s(pt, { onAddToCart: r, defaultQuantity: o })
981
+ ]
982
+ }
983
+ ),
984
+ /* @__PURE__ */ k(
985
+ "div",
986
+ {
987
+ "data-sc-part": "snowcone-editor-stage",
988
+ style: { position: "relative", flex: 1, minHeight: 0, padding: "4px 12px" },
989
+ children: [
990
+ /* @__PURE__ */ s(V.Canvas, { ref: h, style: { height: "100%" } }),
991
+ m ? (
992
+ // Swapped: the mockup IS the stage; the corner chip returns to the
993
+ // artwork. The canvas stays mounted underneath (no document
994
+ // teardown), just covered.
995
+ /* @__PURE__ */ k(
996
+ "div",
997
+ {
998
+ "data-sc-part": "snowcone-editor-swap-stage",
999
+ style: {
1000
+ position: "absolute",
1001
+ inset: 0,
1002
+ zIndex: 1,
1003
+ display: "flex",
1004
+ alignItems: "center",
1005
+ justifyContent: "center",
1006
+ background: "var(--sc-color-surface, #fff)",
1007
+ padding: 8
1008
+ },
1009
+ children: [
1010
+ /* @__PURE__ */ s(
1011
+ V.Preview,
1012
+ {
1013
+ mockupId: w,
1014
+ alt: "Product mockup",
1015
+ fallback: /* @__PURE__ */ s("div", { "aria-busy": "true", children: "Rendering…" }),
1016
+ style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain", borderRadius: 12 }
1017
+ }
1018
+ ),
1019
+ /* @__PURE__ */ s(
1020
+ "button",
1021
+ {
1022
+ type: "button",
1023
+ "aria-label": "Back to artwork",
1024
+ "data-sc-part": "snowcone-editor-swap-back",
1025
+ onClick: () => f(!1),
1026
+ style: {
1027
+ ...T,
1028
+ display: "flex",
1029
+ alignItems: "center",
1030
+ justifyContent: "center",
1031
+ fontSize: 11,
1032
+ fontWeight: 600,
1033
+ color: "inherit",
1034
+ border: "1px dashed rgba(0,0,0,0.25)"
1035
+ },
1036
+ children: "artwork"
1037
+ }
1038
+ )
1039
+ ]
1040
+ }
1041
+ )
1042
+ ) : /* @__PURE__ */ s(
1043
+ "button",
1044
+ {
1045
+ type: "button",
1046
+ "aria-label": "Show product mockup",
1047
+ "data-sc-part": "snowcone-editor-pip",
1048
+ onClick: () => f(!0),
1049
+ style: T,
1050
+ children: /* @__PURE__ */ s(
1051
+ V.Preview,
1052
+ {
1053
+ mockupId: w,
1054
+ alt: "Product mockup preview",
1055
+ fallback: /* @__PURE__ */ s("span", { style: { fontSize: 10, opacity: 0.5 }, "aria-busy": "true", children: "mockup…" }),
1056
+ style: { width: "100%", height: "100%", objectFit: "cover", display: "block" }
1057
+ }
1058
+ )
1059
+ }
1060
+ )
1061
+ ]
1062
+ }
1063
+ ),
1064
+ /* @__PURE__ */ k(
1065
+ "div",
1066
+ {
1067
+ "data-sc-part": "snowcone-editor-zone",
1068
+ "data-sc-zone-state": p ? "selected" : "idle",
1069
+ style: { flexShrink: 0, padding: "4px 16px 14px" },
1070
+ children: [
1071
+ /* @__PURE__ */ s("div", { style: { display: p ? void 0 : "none" }, children: /* @__PURE__ */ s(V.Controls, { placement: "docked" }) }),
1072
+ p ? null : /* @__PURE__ */ s(ft, {})
1073
+ ]
1074
+ }
1075
+ )
1076
+ ]
1077
+ }
1078
+ );
1079
+ }
1080
+ function Tt(t) {
1081
+ const {
1082
+ onAddToCart: e,
1083
+ defaultQuantity: n,
1084
+ title: r = "Editor",
1085
+ height: o = 480,
1086
+ className: a,
1087
+ style: c,
1088
+ ...u
1089
+ } = t;
1090
+ return /* @__PURE__ */ s(V.Root, { ...u, children: /* @__PURE__ */ s(
1091
+ gt,
1092
+ {
1093
+ title: r,
1094
+ height: o,
1095
+ mockupIds: u.product.mockupIds,
1096
+ onAddToCart: e,
1097
+ ...typeof n == "number" ? { defaultQuantity: n } : {},
1098
+ className: a,
1099
+ style: c
1100
+ }
1101
+ ) });
1102
+ }
1103
+ Ce();
1104
+ export {
1105
+ V as E,
1106
+ Ct as R,
1107
+ Tt as S,
1108
+ Rt as a,
1109
+ Ot as b,
1110
+ ce as c,
1111
+ ct as d,
1112
+ Nt as e,
1113
+ lt as f,
1114
+ G as u,
1115
+ Ke as v
1116
+ };
1117
+ //# sourceMappingURL=embed-uALcVSYN.js.map