@snowcone-app/canvas 0.17.3 → 0.18.1
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.
- package/dist/{ImportManager-C_wBjWaV.js → CanvasRenderer-DUc-MOeR.js} +586 -806
- package/dist/CanvasRenderer-DUc-MOeR.js.map +1 -0
- package/dist/{CanvasStateV1-BG2hEc3-.js → CanvasStateV1-Bq48qhv5.js} +3 -3
- package/dist/{CanvasStateV1-BG2hEc3-.js.map → CanvasStateV1-Bq48qhv5.js.map} +1 -1
- package/dist/ContextualToolbars-CkLjHNPn.js +5833 -0
- package/dist/ContextualToolbars-CkLjHNPn.js.map +1 -0
- package/dist/EditorCanvasImpl-Bv4yagew.js +81 -0
- package/dist/EditorCanvasImpl-Bv4yagew.js.map +1 -0
- package/dist/EditorContext-5QpqAhjh.js +1184 -0
- package/dist/{EditorContext-CGkfmbgo.js.map → EditorContext-5QpqAhjh.js.map} +1 -1
- package/dist/{FontAnalyzer-CLv7_msL.js → FontAnalyzer-DIlqmyuf.js} +35 -35
- package/dist/FontAnalyzer-DIlqmyuf.js.map +1 -0
- package/dist/{ElementFactory-CuHSAPfg.js → ImportManager-D--7JnvW.js} +699 -476
- package/dist/ImportManager-D--7JnvW.js.map +1 -0
- package/dist/MenuButton-CeoEAtzP.js +7444 -0
- package/dist/MenuButton-CeoEAtzP.js.map +1 -0
- package/dist/SnowconeCanvas-C_O-aeaQ.js +1166 -0
- package/dist/SnowconeCanvas-C_O-aeaQ.js.map +1 -0
- package/dist/advanced.mjs +266 -264
- package/dist/advanced.mjs.map +1 -1
- package/dist/api/embed.d.ts +1 -1
- package/dist/components/ContextualToolbars.d.ts +8 -0
- package/dist/components/editor/EditorAdd.d.ts +11 -0
- package/dist/components/editor/EditorCanvasImpl.d.ts +6 -0
- package/dist/components/editor/EditorControls.d.ts +14 -0
- package/dist/components/editor/EditorHistory.d.ts +11 -0
- package/dist/components/editor/EditorLayers.d.ts +16 -0
- package/dist/components/editor/EditorMenu.d.ts +11 -0
- package/dist/components/editor/RootInternals.d.ts +7 -0
- package/dist/components/editor/index.d.ts +20 -0
- package/dist/components/embed/addElementTypes.d.ts +9 -0
- package/dist/contexts/EditorContext.d.ts +38 -0
- package/dist/core/preview-registry.d.ts +34 -0
- package/dist/{editorErrors-BY4Pdg7a.js → editorErrors-DXNfVXtD.js} +2 -2
- package/dist/{editorErrors-BY4Pdg7a.js.map → editorErrors-DXNfVXtD.js.map} +1 -1
- package/dist/embed-Cdbjay9i.js +961 -0
- package/dist/embed-Cdbjay9i.js.map +1 -0
- package/dist/embed.mjs +5 -5
- package/dist/index.mjs +7 -7
- package/dist/internals.mjs +12 -12
- package/dist/{template-fields-Z9x13sjM.js → template-fields-DgoBtajp.js} +266 -240
- package/dist/template-fields-DgoBtajp.js.map +1 -0
- package/dist/testing.mjs +3 -3
- package/dist/{usePieceGuideBundle-C1ipFnZd.js → usePieceGuideBundle-DVOISsB1.js} +2 -2
- package/dist/{usePieceGuideBundle-C1ipFnZd.js.map → usePieceGuideBundle-DVOISsB1.js.map} +1 -1
- package/dist/validation-0IscSfRb.js +9304 -0
- package/dist/validation-0IscSfRb.js.map +1 -0
- package/package.json +3 -3
- package/dist/EditorCanvasImpl-DQxqdgpq.js +0 -70
- package/dist/EditorCanvasImpl-DQxqdgpq.js.map +0 -1
- package/dist/EditorContext-CGkfmbgo.js +0 -1178
- package/dist/ElementFactory-CuHSAPfg.js.map +0 -1
- package/dist/FontAnalyzer-CLv7_msL.js.map +0 -1
- package/dist/ImportManager-C_wBjWaV.js.map +0 -1
- package/dist/SnowconeCanvas-DBbmx9qW.js +0 -1187
- package/dist/SnowconeCanvas-DBbmx9qW.js.map +0 -1
- package/dist/UnifiedFontService-Dsu5cwfT.js +0 -1478
- package/dist/UnifiedFontService-Dsu5cwfT.js.map +0 -1
- package/dist/embed--B8ot6Lj.js +0 -746
- package/dist/embed--B8ot6Lj.js.map +0 -1
- package/dist/iconify-D6eVIEy4.js +0 -1089
- package/dist/iconify-D6eVIEy4.js.map +0 -1
- package/dist/template-fields-Z9x13sjM.js.map +0 -1
- package/dist/validation-C795COGQ.js +0 -19959
- package/dist/validation-C795COGQ.js.map +0 -1
|
@@ -0,0 +1,961 @@
|
|
|
1
|
+
import { C as Se, L as Re, I as re, o as q, M as Ce, D as Ie, k as ke, A as Te, l as Oe, T as Ne, h as _e, B as $e, i as De, S as Ae, e as Le } from "./MenuButton-CeoEAtzP.js";
|
|
2
|
+
import { y as S } from "./FontAnalyzer-DIlqmyuf.js";
|
|
3
|
+
import { jsx as l, jsxs as L, Fragment as Be } from "react/jsx-runtime";
|
|
4
|
+
import { useContext as se, createContext as ie, useId as P, useLayoutEffect as V, useRef as k, useState as R, useMemo as I, useEffect as _, useSyncExternalStore as $, Component as Ue, forwardRef as ae, useCallback as oe } from "react";
|
|
5
|
+
import { assertVariantSelected as le, RenderSession as Fe, createCartDetail as Me } from "@snowcone-app/sdk";
|
|
6
|
+
import { g as w, i as qe, h as de, B as Pe, E as Ve, j as je } from "./EditorContext-5QpqAhjh.js";
|
|
7
|
+
import { u as He, p as ze } from "./usePieceGuideBundle-DVOISsB1.js";
|
|
8
|
+
import { r as ce } from "./editorErrors-DXNfVXtD.js";
|
|
9
|
+
import { l as ne, i as Ke, s as ue, U as Ge } from "./template-fields-DgoBtajp.js";
|
|
10
|
+
import "./CanvasStateV1-Bq48qhv5.js";
|
|
11
|
+
const me = ie(void 0);
|
|
12
|
+
function j() {
|
|
13
|
+
const t = se(me);
|
|
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 We = "[RealtimeEmbed]";
|
|
21
|
+
function Ye(t) {
|
|
22
|
+
var r, s;
|
|
23
|
+
if ((r = t == null ? void 0 : t.requiredPlacements) != null && r.length)
|
|
24
|
+
return t.requiredPlacements.filter((i) => !i.autoFilledByVariant).map((i) => i.label);
|
|
25
|
+
const e = new Set(
|
|
26
|
+
(((s = t == null ? void 0 : t.options) == null ? void 0 : s.combinations) ?? []).map((i) => i.variantId).filter((i) => typeof i == "string" && i !== "")
|
|
27
|
+
);
|
|
28
|
+
return !!(t != null && t.variantId) || e.size > 1 ? [] : (t == null ? void 0 : t.placements) ?? [];
|
|
29
|
+
}
|
|
30
|
+
function he({ shop: t, product: e, design: n, hasGrant: r }) {
|
|
31
|
+
var m, u;
|
|
32
|
+
const s = [];
|
|
33
|
+
if (t || s.push({
|
|
34
|
+
severity: "error",
|
|
35
|
+
issue: "missing-shop",
|
|
36
|
+
message: "`shop` is required (your publishable shop id)."
|
|
37
|
+
}), r || s.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
|
+
}), (m = e == null ? void 0 : e.mockupIds) != null && m.length || s.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
|
+
le(e);
|
|
48
|
+
} catch (h) {
|
|
49
|
+
s.push({
|
|
50
|
+
severity: "error",
|
|
51
|
+
issue: "variant-required",
|
|
52
|
+
message: h instanceof Error ? h.message : String(h)
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const i = n.toJSON(), d = i.activeArtboard, o = Ye(e);
|
|
56
|
+
o.length > 1 && s.push({
|
|
57
|
+
severity: "error",
|
|
58
|
+
issue: "multi-placement",
|
|
59
|
+
message: `product ${e.productId} requires placements [${o.join(", ")}] but this embed renders a single placement ("${d}"). The render will time out waiting for the others. This product needs the eject path — see https://developers.snowcone.app/embed-mode#eject.`
|
|
60
|
+
}), (u = e == null ? void 0 : e.placements) != null && u.length && !e.placements.includes(d) && s.push({
|
|
61
|
+
severity: "error",
|
|
62
|
+
issue: "placement-mismatch",
|
|
63
|
+
message: `the design's placement "${d}" 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 c = i.elements.map((h) => h.name).filter((h) => !!h), a = c.filter((h, y) => c.indexOf(h) !== y);
|
|
66
|
+
return a.length && s.push({
|
|
67
|
+
severity: "warn",
|
|
68
|
+
issue: "duplicate-layer-names",
|
|
69
|
+
message: `duplicate layer name(s) [${[...new Set(a)].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
|
+
}), s;
|
|
71
|
+
}
|
|
72
|
+
function Je(t) {
|
|
73
|
+
for (const e of he(t))
|
|
74
|
+
(e.severity === "error" && e.issue !== "placement-mismatch" ? console.error : console.warn)(`${We} ${e.message}`);
|
|
75
|
+
}
|
|
76
|
+
function Y(t) {
|
|
77
|
+
return t.text;
|
|
78
|
+
}
|
|
79
|
+
function A(t) {
|
|
80
|
+
return t.name;
|
|
81
|
+
}
|
|
82
|
+
class Qe {
|
|
83
|
+
constructor(e) {
|
|
84
|
+
this.listeners = /* @__PURE__ */ new Set(), this.getState = () => this.state, this.subscribe = (r) => (this.listeners.add(r), () => this.listeners.delete(r)), this.state = e;
|
|
85
|
+
const n = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const r of e.elements) {
|
|
87
|
+
const s = A(r), i = Y(r);
|
|
88
|
+
s && typeof i == "string" && n.set(s, i);
|
|
89
|
+
}
|
|
90
|
+
this.seedTextByName = n;
|
|
91
|
+
}
|
|
92
|
+
/** Replace the whole state (the canvas `onChange` path). */
|
|
93
|
+
setState(e) {
|
|
94
|
+
this.state = e, this.emit();
|
|
95
|
+
}
|
|
96
|
+
/** The seed value of a named text layer (for completeness rule C3). */
|
|
97
|
+
seedTextOf(e) {
|
|
98
|
+
return this.seedTextByName.get(e);
|
|
99
|
+
}
|
|
100
|
+
/** Current text of a named text layer, or undefined when absent. */
|
|
101
|
+
textOf(e) {
|
|
102
|
+
const n = this.state.elements.find((r) => A(r) === e);
|
|
103
|
+
return n ? Y(n) : void 0;
|
|
104
|
+
}
|
|
105
|
+
/** Kind of the named layer in the CURRENT state ('text' | 'image' | null
|
|
106
|
+
* for unbindable), or undefined when no layer has the name. */
|
|
107
|
+
layerKindOf(e) {
|
|
108
|
+
const n = this.state.elements.find((r) => A(r) === e);
|
|
109
|
+
return n ? ne(n) : void 0;
|
|
110
|
+
}
|
|
111
|
+
/** Names of bindable layers in the current state, for error messages. */
|
|
112
|
+
bindableLayerNames() {
|
|
113
|
+
return this.state.elements.filter((e) => ne(e) !== null).map(A).filter((e) => !!e);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Direct write path for `Editor.TextField` when NO canvas is mounted (with
|
|
117
|
+
* one, writes route through the editor command path and arrive back here
|
|
118
|
+
* via `setState`). Immutable update; last-write-wins.
|
|
119
|
+
*/
|
|
120
|
+
updateTextLayer(e, n) {
|
|
121
|
+
let r = !1;
|
|
122
|
+
const s = this.state.elements.map((i) => A(i) !== e ? i : (r = !0, { ...i, text: n }));
|
|
123
|
+
if (!r)
|
|
124
|
+
throw new w(
|
|
125
|
+
"E_LAYER_NOT_FOUND",
|
|
126
|
+
`no layer "${e}" in the current design state. Bindable layers: ${JSON.stringify(this.bindableLayerNames())}.`,
|
|
127
|
+
{ layerName: e, validNames: this.bindableLayerNames(), docSlug: "embed-mode" }
|
|
128
|
+
);
|
|
129
|
+
this.setState({ ...this.state, elements: s });
|
|
130
|
+
}
|
|
131
|
+
/** ≥1 element with visible content (completeness rule C4): non-empty text,
|
|
132
|
+
* an image with a URL, or a shape. Hidden elements don't count. */
|
|
133
|
+
hasRenderableElement() {
|
|
134
|
+
return this.state.elements.some((e) => {
|
|
135
|
+
if (e.visible === !1) return !1;
|
|
136
|
+
const n = e.transformType;
|
|
137
|
+
if (n === "image") return !!e.imageUrl;
|
|
138
|
+
if (n === "shape" || n === "group" || n === "path") return !0;
|
|
139
|
+
const r = Y(e);
|
|
140
|
+
return typeof r == "string" && r.trim().length > 0;
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
emit() {
|
|
144
|
+
for (const e of [...this.listeners]) e();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
class Xe {
|
|
148
|
+
constructor() {
|
|
149
|
+
this.canvasIds = /* @__PURE__ */ new Set(), this.requirements = /* @__PURE__ */ new Map(), this.textFields = /* @__PURE__ */ new Map(), this.controls = /* @__PURE__ */ new Map(), this.bridge = null, this.listeners = /* @__PURE__ */ new Set(), this.version = 0, this.getVersion = () => this.version, this.subscribe = (e) => (this.listeners.add(e), () => this.listeners.delete(e));
|
|
150
|
+
}
|
|
151
|
+
registerCanvas(e) {
|
|
152
|
+
return this.canvasIds.add(e), this.bump(), () => {
|
|
153
|
+
this.canvasIds.delete(e), this.bump();
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
hasCanvas() {
|
|
157
|
+
return this.canvasIds.size > 0;
|
|
158
|
+
}
|
|
159
|
+
/** Declare that a part is meaningless without a mounted Canvas (ADR-0085 §4
|
|
160
|
+
* table). Validated by Root once per commit. */
|
|
161
|
+
requireCanvas(e, n) {
|
|
162
|
+
return this.requirements.set(e, n), this.bump(), () => {
|
|
163
|
+
this.requirements.delete(e), this.bump();
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
/** Run by Root during RENDER, re-triggered by every registry change — by
|
|
167
|
+
* then the whole commit's registrations are in, so there is no race
|
|
168
|
+
* against the lazy chunk (ADR-0085 §4). Throws land in Root's boundary. */
|
|
169
|
+
validate() {
|
|
170
|
+
if (this.canvasIds.size > 1)
|
|
171
|
+
throw new w(
|
|
172
|
+
"E_DUPLICATE_CANVAS",
|
|
173
|
+
"two <Editor.Canvas> parts are mounted under one <Editor.Root>. A Root owns exactly one editable artboard — remove one Canvas, or mount a second <Editor.Root> for a second editor. (Multiple <Editor.Preview> parts ARE valid.)",
|
|
174
|
+
{ docSlug: "embed-mode" }
|
|
175
|
+
);
|
|
176
|
+
if (this.requirements.size > 0 && !this.hasCanvas()) {
|
|
177
|
+
const e = [...new Set(this.requirements.values())];
|
|
178
|
+
throw new w(
|
|
179
|
+
"E_REQUIRES_CANVAS",
|
|
180
|
+
`${e.join(", ")} require${e.length === 1 ? "s" : ""} an <Editor.Canvas> under the same <Editor.Root> — they operate on the editable artboard (selection, editor commands). Mount <Editor.Canvas/>, or remove the part. Canvas-free parts: Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.`,
|
|
181
|
+
{ parts: e, docSlug: "embed-mode" }
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
registerTextField(e, n) {
|
|
186
|
+
return this.textFields.set(e, n), this.bump(), () => {
|
|
187
|
+
this.textFields.delete(e), this.bump();
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Mounted TextField registrations — Buy's required-layer list (C2/C3).
|
|
191
|
+
* Unmounted (incl. conditionally hidden) fields are absent by construction. */
|
|
192
|
+
getTextFields() {
|
|
193
|
+
return [...this.textFields.values()];
|
|
194
|
+
}
|
|
195
|
+
/** Bound-layer lookup for the mutation guard (ADR-0085 §3 /
|
|
196
|
+
* `E_BOUND_LAYER_MUTATION`): a layer is bound while ANY mounted
|
|
197
|
+
* `Editor.TextField` carries its name. Satisfies `BoundLayerGuard`
|
|
198
|
+
* structurally (subscribe/getVersion above). */
|
|
199
|
+
getBoundLayer(e) {
|
|
200
|
+
for (const n of this.textFields.values())
|
|
201
|
+
if (n.name === e) return { part: "Editor.TextField" };
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
/** `Editor.Controls` registration (ADR-0085 §5): a mounted DOCKED Controls
|
|
205
|
+
* suppresses the canvas's built-in floating contextual toolbar — one
|
|
206
|
+
* contextual zone at a time. `placement="floating"` registers without
|
|
207
|
+
* suppressing (it declares today's default explicitly). */
|
|
208
|
+
registerControls(e, n) {
|
|
209
|
+
return this.controls.set(e, n), this.bump(), () => {
|
|
210
|
+
this.controls.delete(e), this.bump();
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
hasDockedControls() {
|
|
214
|
+
for (const e of this.controls.values())
|
|
215
|
+
if (e === "docked") return !0;
|
|
216
|
+
return !1;
|
|
217
|
+
}
|
|
218
|
+
registerCanvasBridge(e) {
|
|
219
|
+
return this.bridge = e, this.bump(), () => {
|
|
220
|
+
this.bridge === e && (this.bridge = null), this.bump();
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
getCanvasBridge() {
|
|
224
|
+
return this.bridge;
|
|
225
|
+
}
|
|
226
|
+
bump() {
|
|
227
|
+
this.version++;
|
|
228
|
+
for (const e of [...this.listeners]) e();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const fe = ie(null);
|
|
232
|
+
function D(t) {
|
|
233
|
+
const e = se(fe);
|
|
234
|
+
if (!e)
|
|
235
|
+
throw new w(
|
|
236
|
+
"E_OUTSIDE_ROOT",
|
|
237
|
+
`<${t}> must be rendered inside <Editor.Root>. Wrap it: <Editor.Root shop={…} product={…} design={…} grantUrl={…}><${t}/></Editor.Root>`,
|
|
238
|
+
{ part: t, docSlug: "embed-mode" }
|
|
239
|
+
);
|
|
240
|
+
return e;
|
|
241
|
+
}
|
|
242
|
+
function H(t) {
|
|
243
|
+
const e = D(t), n = P();
|
|
244
|
+
V(
|
|
245
|
+
() => e.registry.requireCanvas(n, t),
|
|
246
|
+
[e.registry, n, t]
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
function Ze(t) {
|
|
250
|
+
return {
|
|
251
|
+
reportInvariant(e) {
|
|
252
|
+
if (qe()) throw e;
|
|
253
|
+
t(e);
|
|
254
|
+
},
|
|
255
|
+
reportRuntimeError(e) {
|
|
256
|
+
ce(e), t(e);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const pe = 8e3;
|
|
261
|
+
function et(t) {
|
|
262
|
+
return `[RealtimeEmbed] No mockup after ${Math.round(pe / 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.`;
|
|
263
|
+
}
|
|
264
|
+
function tt(t) {
|
|
265
|
+
if ("grantUrl" in t && t.grantUrl)
|
|
266
|
+
return { grantUrl: t.grantUrl };
|
|
267
|
+
const e = t.grant;
|
|
268
|
+
return typeof e == "function" ? { getToken: e } : { getToken: () => Promise.resolve(e) };
|
|
269
|
+
}
|
|
270
|
+
function ge({ error: t, onRetry: e }) {
|
|
271
|
+
const n = de(t) ? t.code : "EDITOR_ERROR";
|
|
272
|
+
return /* @__PURE__ */ L(
|
|
273
|
+
"div",
|
|
274
|
+
{
|
|
275
|
+
"data-sc-part": "error",
|
|
276
|
+
role: "alert",
|
|
277
|
+
style: {
|
|
278
|
+
padding: "16px",
|
|
279
|
+
borderRadius: "12px",
|
|
280
|
+
border: "1px solid var(--sc-color-destructive, #b91c1c)",
|
|
281
|
+
background: "var(--sc-color-surface, #fef2f2)",
|
|
282
|
+
color: "var(--sc-color-foreground, #7f1d1d)",
|
|
283
|
+
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
284
|
+
fontSize: "13px",
|
|
285
|
+
lineHeight: 1.5
|
|
286
|
+
},
|
|
287
|
+
children: [
|
|
288
|
+
/* @__PURE__ */ L("p", { style: { margin: 0, fontWeight: 700 }, children: [
|
|
289
|
+
"Editor failed: ",
|
|
290
|
+
n
|
|
291
|
+
] }),
|
|
292
|
+
/* @__PURE__ */ l("p", { style: { margin: "4px 0 0" }, children: t.message }),
|
|
293
|
+
e ? /* @__PURE__ */ l(
|
|
294
|
+
"button",
|
|
295
|
+
{
|
|
296
|
+
type: "button",
|
|
297
|
+
"data-sc-part": "error-retry",
|
|
298
|
+
onClick: e,
|
|
299
|
+
style: {
|
|
300
|
+
marginTop: "10px",
|
|
301
|
+
padding: "6px 14px",
|
|
302
|
+
borderRadius: "9999px",
|
|
303
|
+
border: "1px solid currentColor",
|
|
304
|
+
background: "transparent",
|
|
305
|
+
color: "inherit",
|
|
306
|
+
font: "inherit",
|
|
307
|
+
fontWeight: 600,
|
|
308
|
+
cursor: "pointer"
|
|
309
|
+
},
|
|
310
|
+
children: "Retry"
|
|
311
|
+
}
|
|
312
|
+
) : null
|
|
313
|
+
]
|
|
314
|
+
}
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
class nt extends Ue {
|
|
318
|
+
constructor() {
|
|
319
|
+
super(...arguments), this.state = { caught: null };
|
|
320
|
+
}
|
|
321
|
+
static getDerivedStateFromError(e) {
|
|
322
|
+
return { caught: e };
|
|
323
|
+
}
|
|
324
|
+
componentDidCatch(e) {
|
|
325
|
+
var n;
|
|
326
|
+
ce(e), typeof S < "u" && ((n = S.env) == null ? void 0 : n.NODE_ENV) !== "production" && console.error("[Editor.Root] contained a composition error:", e);
|
|
327
|
+
}
|
|
328
|
+
render() {
|
|
329
|
+
return this.state.caught ? /* @__PURE__ */ l(ge, { error: this.state.caught }) : this.props.children;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
function rt({ reportedError: t, onRetry: e, children: n }) {
|
|
333
|
+
if (t) {
|
|
334
|
+
const r = de(t) && t.code === "E_CHUNK_LOAD_FAILED";
|
|
335
|
+
return /* @__PURE__ */ l(ge, { error: t, onRetry: r ? e : void 0 });
|
|
336
|
+
}
|
|
337
|
+
return /* @__PURE__ */ l(nt, { reportedError: null, onRetry: e, children: n });
|
|
338
|
+
}
|
|
339
|
+
function st(t) {
|
|
340
|
+
const {
|
|
341
|
+
shop: e,
|
|
342
|
+
product: n,
|
|
343
|
+
design: r,
|
|
344
|
+
throttleMs: s = 200,
|
|
345
|
+
onMockups: i,
|
|
346
|
+
onRenderError: d,
|
|
347
|
+
wsUrl: o,
|
|
348
|
+
services: c,
|
|
349
|
+
children: a,
|
|
350
|
+
internals: m,
|
|
351
|
+
__validation: u = "throw"
|
|
352
|
+
} = t, h = I(() => r.toJSON().activeArtboard, [r]), y = He(n.variantId ?? n.defaultGvid), p = I(() => {
|
|
353
|
+
if (!y) return null;
|
|
354
|
+
const f = r.toJSON().artboards[0];
|
|
355
|
+
return ze(y, f) ?? null;
|
|
356
|
+
}, [y, r]), b = k(i), g = k(d);
|
|
357
|
+
b.current = i, g.current = d;
|
|
358
|
+
const [C, z] = R([]), [T, O] = R(!0), [Q, B] = R(null), K = !!("grantUrl" in t && t.grantUrl || "grant" in t && t.grant), G = tt(t), Ee = "grantUrl" in G ? G.grantUrl : "getToken", X = `${n.productId}|${n.mockupIds.join(",")}|${n.variantId ?? ""}`, U = `${e}|${X}|${h}|${K}`;
|
|
359
|
+
I(() => {
|
|
360
|
+
var E;
|
|
361
|
+
if (u !== "throw") return;
|
|
362
|
+
const f = he({ shop: e, product: n, design: r, hasGrant: K }), v = f.find((N) => N.severity === "error");
|
|
363
|
+
if (v)
|
|
364
|
+
throw new w("E_EMBED_CONFIG", v.message, {
|
|
365
|
+
issue: v.issue,
|
|
366
|
+
docSlug: "embed-mode"
|
|
367
|
+
});
|
|
368
|
+
for (const N of f)
|
|
369
|
+
typeof S < "u" && ((E = S.env) == null ? void 0 : E.NODE_ENV) !== "production" && console.warn(`[Editor.Root] ${N.message}`);
|
|
370
|
+
}, [U, u]);
|
|
371
|
+
const Z = k(null);
|
|
372
|
+
_(() => {
|
|
373
|
+
var f;
|
|
374
|
+
if (u === "warn" && typeof S < "u" && ((f = S.env) == null ? void 0 : f.NODE_ENV) !== "production") {
|
|
375
|
+
if (Z.current === U) return;
|
|
376
|
+
Z.current = U, Je({ shop: e, product: n, design: r, hasGrant: K });
|
|
377
|
+
}
|
|
378
|
+
}, [U, u]);
|
|
379
|
+
const F = I(
|
|
380
|
+
() => {
|
|
381
|
+
try {
|
|
382
|
+
return { session: new Fe({ shop: e, product: n, wsUrl: o, ...G }) };
|
|
383
|
+
} catch (f) {
|
|
384
|
+
return { error: f instanceof Error ? f.message : String(f) };
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
388
|
+
[e, X, h, o, Ee]
|
|
389
|
+
), x = "session" in F ? F.session : null, M = "error" in F ? F.error : null, W = I(() => (f, v = s) => {
|
|
390
|
+
x && (B(null), O(!0), x.renderState(h, f, v).catch((E) => {
|
|
391
|
+
var te;
|
|
392
|
+
const N = E instanceof Error ? E.message : String(E);
|
|
393
|
+
B(N), O(!1), (te = g.current) == null || te.call(g, N);
|
|
394
|
+
}));
|
|
395
|
+
}, [x, h, s]);
|
|
396
|
+
_(() => {
|
|
397
|
+
var f;
|
|
398
|
+
if (M) {
|
|
399
|
+
B(M), O(!1), (f = g.current) == null || f.call(g, M);
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (x)
|
|
403
|
+
return x.onMockups((v) => {
|
|
404
|
+
var E;
|
|
405
|
+
z(v), O(!1), (E = b.current) == null || E.call(b, v);
|
|
406
|
+
}), x.onError((v) => {
|
|
407
|
+
var E;
|
|
408
|
+
B(v), O(!1), (E = g.current) == null || E.call(g, v);
|
|
409
|
+
}), W(r.toServerRequest()), () => x.close();
|
|
410
|
+
}, [x, M]), _(() => {
|
|
411
|
+
var v;
|
|
412
|
+
if (!T || typeof S > "u" || ((v = S.env) == null ? void 0 : v.NODE_ENV) === "production") return;
|
|
413
|
+
const f = setTimeout(() => console.warn(et(h)), pe);
|
|
414
|
+
return () => clearTimeout(f);
|
|
415
|
+
}, [T, h]);
|
|
416
|
+
const we = I(
|
|
417
|
+
() => ({
|
|
418
|
+
session: x,
|
|
419
|
+
design: r,
|
|
420
|
+
placement: h,
|
|
421
|
+
product: n,
|
|
422
|
+
mockups: C,
|
|
423
|
+
isRendering: T,
|
|
424
|
+
error: Q,
|
|
425
|
+
throttleMs: s,
|
|
426
|
+
pieceGuides: p,
|
|
427
|
+
pushRender: W,
|
|
428
|
+
stateStore: m.store
|
|
429
|
+
}),
|
|
430
|
+
[x, r, h, n, C, T, Q, s, p, W, m.store]
|
|
431
|
+
), xe = $(
|
|
432
|
+
m.registry.subscribe,
|
|
433
|
+
m.registry.getVersion,
|
|
434
|
+
m.registry.getVersion
|
|
435
|
+
);
|
|
436
|
+
I(() => m.registry.validate(), [m.registry, xe]);
|
|
437
|
+
const ee = /* @__PURE__ */ l(fe.Provider, { value: m, children: /* @__PURE__ */ l(me.Provider, { value: we, children: /* @__PURE__ */ l(Pe.Provider, { value: m.registry, children: /* @__PURE__ */ l(Ve, { children: a }) }) }) });
|
|
438
|
+
return c ? /* @__PURE__ */ l(Se, { services: c, children: ee }) : ee;
|
|
439
|
+
}
|
|
440
|
+
function ye(t) {
|
|
441
|
+
const { design: e } = t, n = k(null), [r, s] = R(null);
|
|
442
|
+
(n.current === null || n.current.design !== e) && (n.current = {
|
|
443
|
+
design: e,
|
|
444
|
+
internals: {
|
|
445
|
+
store: new Qe(e.toJSON()),
|
|
446
|
+
registry: new Xe()
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
const i = I(
|
|
450
|
+
() => ({
|
|
451
|
+
...n.current.internals,
|
|
452
|
+
...Ze(s)
|
|
453
|
+
}),
|
|
454
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
455
|
+
[n.current.internals]
|
|
456
|
+
);
|
|
457
|
+
return (
|
|
458
|
+
// `display: contents` — the .sc-root scope without a layout box, so the
|
|
459
|
+
// host's grid/flex sees the parts directly (and the legacy RealtimeEmbed
|
|
460
|
+
// wrapper, which had no DOM at all, stays layout-identical).
|
|
461
|
+
/* @__PURE__ */ l("div", { className: "sc-root", style: { display: "contents" }, "data-sc-part": "root", children: /* @__PURE__ */ l(rt, { reportedError: r, onRetry: () => s(null), children: /* @__PURE__ */ l(st, { ...t, internals: i }) }) })
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
let it = () => import("./EditorCanvasImpl-Bv4yagew.js").then((t) => t.EditorCanvasImpl);
|
|
465
|
+
function ve() {
|
|
466
|
+
return it();
|
|
467
|
+
}
|
|
468
|
+
const at = ae(function({ children: e, maxHeight: n, className: r, style: s }, i) {
|
|
469
|
+
const d = D("Editor.Canvas"), o = P();
|
|
470
|
+
V(() => d.registry.registerCanvas(o), [d.registry, o]);
|
|
471
|
+
const [c, a] = R(null);
|
|
472
|
+
return _(() => {
|
|
473
|
+
let m = !1;
|
|
474
|
+
return ve().then(
|
|
475
|
+
(u) => {
|
|
476
|
+
m || a(() => u);
|
|
477
|
+
},
|
|
478
|
+
(u) => {
|
|
479
|
+
m || d.reportRuntimeError(
|
|
480
|
+
new w(
|
|
481
|
+
"E_CHUNK_LOAD_FAILED",
|
|
482
|
+
`the editor's rendering chunk failed to load (${u instanceof Error ? u.message : String(u)}). This is a network/CDN failure, not a composition mistake — retry, or check the deployment serves the @snowcone-app/canvas lazy chunks.`,
|
|
483
|
+
{ cause: u instanceof Error ? u.message : String(u), docSlug: "embed-mode" }
|
|
484
|
+
)
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
), () => {
|
|
488
|
+
m = !0;
|
|
489
|
+
};
|
|
490
|
+
}, [d]), c ? (
|
|
491
|
+
// `builtinControls`: the canvas owns the floating contextual toolbar
|
|
492
|
+
// unless a docked <Editor.Controls> is mounted (ADR-0085 §5). Only here —
|
|
493
|
+
// the legacy <RealtimeCanvas> wrapper stays chrome-less.
|
|
494
|
+
/* @__PURE__ */ l(c, { ref: i, kit: "embed-only", partAttr: "canvas", builtinControls: !0, maxHeight: n, className: r, style: s, children: e })
|
|
495
|
+
) : /* @__PURE__ */ l(
|
|
496
|
+
"div",
|
|
497
|
+
{
|
|
498
|
+
"data-sc-part": "canvas",
|
|
499
|
+
"data-sc-state": "loading",
|
|
500
|
+
className: r,
|
|
501
|
+
style: { minHeight: n ?? 200, ...s },
|
|
502
|
+
"aria-busy": "true"
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}), ot = 1.2, J = [1200, 1400, 1600, 1800, 2e3, 2500, 3e3, 4e3];
|
|
506
|
+
function lt(t) {
|
|
507
|
+
for (const e of J)
|
|
508
|
+
if (e >= t) return e;
|
|
509
|
+
return J[J.length - 1];
|
|
510
|
+
}
|
|
511
|
+
function dt(t, e) {
|
|
512
|
+
if (!(t > 0) || !(e > 0) || e <= t * ot) return null;
|
|
513
|
+
const n = lt(e);
|
|
514
|
+
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.`;
|
|
515
|
+
}
|
|
516
|
+
function be({
|
|
517
|
+
mockupId: t,
|
|
518
|
+
fallback: e = null,
|
|
519
|
+
alt: n = "Live product mockup",
|
|
520
|
+
className: r,
|
|
521
|
+
style: s
|
|
522
|
+
}) {
|
|
523
|
+
const { mockups: i } = j(), d = k(/* @__PURE__ */ new Set()), o = t ? i.find((a) => a.mockupId === t && a.imageUrl) : i.find((a) => a.imageUrl);
|
|
524
|
+
if (!(o != null && o.imageUrl))
|
|
525
|
+
return /* @__PURE__ */ l(Be, { children: e });
|
|
526
|
+
const c = (a) => {
|
|
527
|
+
var p;
|
|
528
|
+
if (typeof S > "u" || ((p = S.env) == null ? void 0 : p.NODE_ENV) === "production" || typeof window > "u" || d.current.has(o.mockupId)) return;
|
|
529
|
+
const m = a.currentTarget, u = m.getBoundingClientRect().width;
|
|
530
|
+
if (u <= 0) return;
|
|
531
|
+
const h = Math.round(u * (window.devicePixelRatio || 1)), y = dt(m.naturalWidth, h);
|
|
532
|
+
y && (d.current.add(o.mockupId), console.warn(y));
|
|
533
|
+
};
|
|
534
|
+
return (
|
|
535
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
536
|
+
/* @__PURE__ */ l(
|
|
537
|
+
"img",
|
|
538
|
+
{
|
|
539
|
+
"data-sc-part": "preview",
|
|
540
|
+
src: o.imageUrl,
|
|
541
|
+
alt: n,
|
|
542
|
+
className: r,
|
|
543
|
+
style: s,
|
|
544
|
+
onLoad: c
|
|
545
|
+
}
|
|
546
|
+
)
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
function ct(t) {
|
|
550
|
+
const { layer: e, optional: n = !1, placeholder: r, className: s, style: i } = t, d = D("Editor.TextField"), { pushRender: o, throttleMs: c, stateStore: a } = j(), m = P(), u = k(null);
|
|
551
|
+
if (!Ke(e))
|
|
552
|
+
throw new w(
|
|
553
|
+
"E_LAYER_TOKEN_REQUIRED",
|
|
554
|
+
`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.`,
|
|
555
|
+
{ received: typeof e == "string" ? e : typeof e, docSlug: "embed-mode" }
|
|
556
|
+
);
|
|
557
|
+
if (u.current !== e.name) {
|
|
558
|
+
const p = a.layerKindOf(e.name);
|
|
559
|
+
if (p === void 0)
|
|
560
|
+
throw new w(
|
|
561
|
+
"E_LAYER_NOT_FOUND",
|
|
562
|
+
`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(a.bindableLayerNames())}.`,
|
|
563
|
+
{ layerName: e.name, validNames: a.bindableLayerNames(), docSlug: "embed-mode" }
|
|
564
|
+
);
|
|
565
|
+
if (p !== "text")
|
|
566
|
+
throw new w(
|
|
567
|
+
"E_LAYER_WRONG_KIND",
|
|
568
|
+
`layer "${e.name}" is ${p === null ? "not a bindable kind" : `an ${p} layer`} — <Editor.TextField> binds text layers only.`,
|
|
569
|
+
{ layerName: e.name, actualKind: p, docSlug: "embed-mode" }
|
|
570
|
+
);
|
|
571
|
+
u.current = e.name;
|
|
572
|
+
}
|
|
573
|
+
V(() => d.registry.registerTextField(m, { name: e.name, optional: n }), [d.registry, m, e.name, n]);
|
|
574
|
+
const h = $(
|
|
575
|
+
a.subscribe,
|
|
576
|
+
() => a.textOf(e.name) ?? "",
|
|
577
|
+
() => a.textOf(e.name) ?? ""
|
|
578
|
+
), y = oe(
|
|
579
|
+
(p) => {
|
|
580
|
+
const b = p.target.value, g = d.registry.getCanvasBridge();
|
|
581
|
+
if (g) {
|
|
582
|
+
g.setTextByName(e.name, b) || d.reportInvariant(
|
|
583
|
+
new w(
|
|
584
|
+
"E_LAYER_NOT_FOUND",
|
|
585
|
+
`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).`,
|
|
586
|
+
{ layerName: e.name, docSlug: "embed-mode" }
|
|
587
|
+
)
|
|
588
|
+
);
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
a.updateTextLayer(e.name, b), o(ue(a.getState()), c);
|
|
592
|
+
},
|
|
593
|
+
[d, e.name, a, o, c]
|
|
594
|
+
);
|
|
595
|
+
return /* @__PURE__ */ l(
|
|
596
|
+
"input",
|
|
597
|
+
{
|
|
598
|
+
"data-sc-part": "textfield",
|
|
599
|
+
"data-sc-layer": e.name,
|
|
600
|
+
type: "text",
|
|
601
|
+
value: h,
|
|
602
|
+
onChange: y,
|
|
603
|
+
placeholder: r,
|
|
604
|
+
"aria-label": t["aria-label"] ?? e.name,
|
|
605
|
+
className: s,
|
|
606
|
+
style: i
|
|
607
|
+
}
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
function ut(t) {
|
|
611
|
+
const e = [];
|
|
612
|
+
if (t.product.options)
|
|
613
|
+
try {
|
|
614
|
+
le(t.product);
|
|
615
|
+
} catch {
|
|
616
|
+
e.push("variant");
|
|
617
|
+
}
|
|
618
|
+
for (const n of t.textFields) {
|
|
619
|
+
if (n.optional) continue;
|
|
620
|
+
const r = (t.textOf(n.name) ?? "").trim();
|
|
621
|
+
if (r.length === 0) {
|
|
622
|
+
e.push(`layer:${n.name}`);
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
const s = (t.seedTextOf(n.name) ?? "").trim();
|
|
626
|
+
s.length > 0 && r === s && e.push(`layer-seed:${n.name}`);
|
|
627
|
+
}
|
|
628
|
+
return t.hasRenderableElement || e.push("empty-design"), (!Number.isInteger(t.quantity) || t.quantity < 1) && e.push("quantity"), e;
|
|
629
|
+
}
|
|
630
|
+
function mt(t, e) {
|
|
631
|
+
const n = t.options, r = n == null ? void 0 : n.combinations;
|
|
632
|
+
if (!n || !(r != null && r.length)) return null;
|
|
633
|
+
const s = r.find((o) => o.variantId && o.variantId === t.variantId) ?? r[0];
|
|
634
|
+
if (!s) return null;
|
|
635
|
+
const i = {};
|
|
636
|
+
for (const [o, c] of Object.entries(s))
|
|
637
|
+
o === "variantId" || o === "price" || (typeof c == "string" ? i[o] = c : typeof c == "number" && (i[o] = String(c)));
|
|
638
|
+
const d = Object.fromEntries(
|
|
639
|
+
Object.keys(i).map((o) => [
|
|
640
|
+
o,
|
|
641
|
+
{ key: o, affectsCombinations: !0, choices: [...new Set(r.map((c) => String(c[o] ?? "")))] }
|
|
642
|
+
])
|
|
643
|
+
);
|
|
644
|
+
return Me({
|
|
645
|
+
productId: t.productId,
|
|
646
|
+
quantity: e,
|
|
647
|
+
selection: i,
|
|
648
|
+
combinations: r,
|
|
649
|
+
attributes: d
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
function ht(t) {
|
|
653
|
+
const { onAddToCart: e, quantity: n = 1, children: r, className: s, style: i } = t, d = D("Editor.Buy"), { product: o, stateStore: c } = j();
|
|
654
|
+
if (!(o != null && o.productId))
|
|
655
|
+
throw new w(
|
|
656
|
+
"E_BUY_NO_PRODUCT",
|
|
657
|
+
"<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.",
|
|
658
|
+
{ docSlug: "embed-mode" }
|
|
659
|
+
);
|
|
660
|
+
const a = $(c.subscribe, c.getState, c.getState), m = $(
|
|
661
|
+
d.registry.subscribe,
|
|
662
|
+
d.registry.getVersion,
|
|
663
|
+
d.registry.getVersion
|
|
664
|
+
), u = I(
|
|
665
|
+
() => ut({
|
|
666
|
+
product: o,
|
|
667
|
+
quantity: n,
|
|
668
|
+
textFields: d.registry.getTextFields(),
|
|
669
|
+
textOf: (C) => c.textOf(C),
|
|
670
|
+
seedTextOf: (C) => c.seedTextOf(C),
|
|
671
|
+
hasRenderableElement: c.hasRenderableElement()
|
|
672
|
+
}),
|
|
673
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
674
|
+
[o, n, a, m]
|
|
675
|
+
), h = u.length === 0, [y, p] = R(!1), b = k(!1), g = oe(() => {
|
|
676
|
+
if (b.current || !h) return;
|
|
677
|
+
b.current = !0, p(!0);
|
|
678
|
+
const C = c.getState(), z = {
|
|
679
|
+
productId: o.productId,
|
|
680
|
+
...o.variantId ? { variantId: o.variantId } : {},
|
|
681
|
+
quantity: n,
|
|
682
|
+
cartDetail: mt(o, n),
|
|
683
|
+
designState: C,
|
|
684
|
+
serverRequest: ue(C)
|
|
685
|
+
};
|
|
686
|
+
let T;
|
|
687
|
+
try {
|
|
688
|
+
T = e(z);
|
|
689
|
+
} catch (O) {
|
|
690
|
+
throw b.current = !1, p(!1), O;
|
|
691
|
+
}
|
|
692
|
+
Promise.resolve(T).finally(() => {
|
|
693
|
+
b.current = !1, p(!1);
|
|
694
|
+
});
|
|
695
|
+
}, [h, o, n, c, e]);
|
|
696
|
+
return /* @__PURE__ */ l(
|
|
697
|
+
"button",
|
|
698
|
+
{
|
|
699
|
+
type: "button",
|
|
700
|
+
"data-sc-part": "buy",
|
|
701
|
+
"data-sc-buy-state": y ? "busy" : h ? "ready" : "incomplete",
|
|
702
|
+
"data-sc-buy-missing": u.join(",") || void 0,
|
|
703
|
+
disabled: !h || y,
|
|
704
|
+
"aria-busy": y || void 0,
|
|
705
|
+
onClick: g,
|
|
706
|
+
className: s,
|
|
707
|
+
style: i,
|
|
708
|
+
children: r ?? "Add to cart"
|
|
709
|
+
}
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
function ft(t) {
|
|
713
|
+
const { elements: e } = t.getState();
|
|
714
|
+
return e.map((n, r) => {
|
|
715
|
+
const s = n, i = s.transformType ?? "custom", d = s.name ?? i.charAt(0).toUpperCase() + i.slice(1);
|
|
716
|
+
return {
|
|
717
|
+
key: `${r}:${s.name ?? ""}`,
|
|
718
|
+
name: d,
|
|
719
|
+
kind: i,
|
|
720
|
+
visible: s.visible !== !1
|
|
721
|
+
};
|
|
722
|
+
});
|
|
723
|
+
}
|
|
724
|
+
function pt(t) {
|
|
725
|
+
const e = k(null), n = () => {
|
|
726
|
+
var i;
|
|
727
|
+
const r = ft(t), s = r.map((d) => `${d.key}|${d.kind}|${d.visible}`).join(`
|
|
728
|
+
`);
|
|
729
|
+
return ((i = e.current) == null ? void 0 : i.key) !== s && (e.current = { key: s, rows: r }), e.current.rows;
|
|
730
|
+
};
|
|
731
|
+
return $(t.subscribe, n, n);
|
|
732
|
+
}
|
|
733
|
+
function gt(t) {
|
|
734
|
+
return t === "image" ? q.image : t === "shape" ? q.shapes : t === "group" ? "lucide:folder-open" : q.text;
|
|
735
|
+
}
|
|
736
|
+
function yt({
|
|
737
|
+
store: t,
|
|
738
|
+
direction: e
|
|
739
|
+
}) {
|
|
740
|
+
const r = [...pt(t)].reverse();
|
|
741
|
+
return /* @__PURE__ */ l(
|
|
742
|
+
"div",
|
|
743
|
+
{
|
|
744
|
+
style: {
|
|
745
|
+
display: "flex",
|
|
746
|
+
flexDirection: e === "horizontal" ? "row" : "column",
|
|
747
|
+
gap: 4
|
|
748
|
+
},
|
|
749
|
+
children: r.length === 0 ? /* @__PURE__ */ l("div", { style: { padding: 12, fontSize: 12, color: "var(--text-secondary, #999)" }, children: "No layers" }) : r.map((s) => /* @__PURE__ */ L(
|
|
750
|
+
"div",
|
|
751
|
+
{
|
|
752
|
+
"data-sc-part": "layers-item",
|
|
753
|
+
"data-sc-layer-kind": s.kind,
|
|
754
|
+
"data-sc-hidden": s.visible ? void 0 : "true",
|
|
755
|
+
style: {
|
|
756
|
+
display: "flex",
|
|
757
|
+
alignItems: "center",
|
|
758
|
+
gap: 8,
|
|
759
|
+
padding: "6px 8px",
|
|
760
|
+
minHeight: 36,
|
|
761
|
+
opacity: s.visible ? 1 : 0.4
|
|
762
|
+
},
|
|
763
|
+
children: [
|
|
764
|
+
/* @__PURE__ */ l(re, { icon: gt(s.kind), style: { fontSize: 18, color: "var(--text-secondary, #888)", flexShrink: 0 } }),
|
|
765
|
+
/* @__PURE__ */ l(
|
|
766
|
+
"span",
|
|
767
|
+
{
|
|
768
|
+
style: {
|
|
769
|
+
fontSize: 13,
|
|
770
|
+
color: "var(--foreground, #333)",
|
|
771
|
+
overflow: "hidden",
|
|
772
|
+
textOverflow: "ellipsis",
|
|
773
|
+
whiteSpace: "nowrap"
|
|
774
|
+
},
|
|
775
|
+
children: s.name
|
|
776
|
+
}
|
|
777
|
+
)
|
|
778
|
+
]
|
|
779
|
+
},
|
|
780
|
+
s.key
|
|
781
|
+
))
|
|
782
|
+
}
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
function vt({
|
|
786
|
+
direction: t = "vertical",
|
|
787
|
+
className: e,
|
|
788
|
+
style: n
|
|
789
|
+
}) {
|
|
790
|
+
const r = D("Editor.Layers"), { registry: s } = r, i = $(
|
|
791
|
+
s.subscribe,
|
|
792
|
+
() => s.hasCanvas(),
|
|
793
|
+
() => s.hasCanvas()
|
|
794
|
+
);
|
|
795
|
+
return /* @__PURE__ */ l("div", { "data-sc-part": "layers", "data-sc-direction": t, className: e, style: n, children: i ? /* @__PURE__ */ l(Re, { style: { width: "100%" } }) : /* @__PURE__ */ l(yt, { store: r.store, direction: t }) });
|
|
796
|
+
}
|
|
797
|
+
function bt({
|
|
798
|
+
placement: t = "docked",
|
|
799
|
+
className: e,
|
|
800
|
+
style: n
|
|
801
|
+
}) {
|
|
802
|
+
const r = D("Editor.Controls");
|
|
803
|
+
H("Editor.Controls");
|
|
804
|
+
const s = P();
|
|
805
|
+
V(
|
|
806
|
+
() => r.registry.registerControls(s, t),
|
|
807
|
+
[r.registry, s, t]
|
|
808
|
+
);
|
|
809
|
+
const i = t === "docked", [d, o] = R(null);
|
|
810
|
+
return _(() => {
|
|
811
|
+
if (!i) return;
|
|
812
|
+
let c = !1;
|
|
813
|
+
return import("./ContextualToolbars-CkLjHNPn.js").then((a) => a.x).then(
|
|
814
|
+
(a) => {
|
|
815
|
+
c || o(() => a.ContextualToolbars);
|
|
816
|
+
},
|
|
817
|
+
(a) => {
|
|
818
|
+
c || r.reportRuntimeError(
|
|
819
|
+
new w(
|
|
820
|
+
"E_CHUNK_LOAD_FAILED",
|
|
821
|
+
`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.`,
|
|
822
|
+
{ cause: a instanceof Error ? a.message : String(a), docSlug: "embed-mode" }
|
|
823
|
+
)
|
|
824
|
+
);
|
|
825
|
+
}
|
|
826
|
+
), () => {
|
|
827
|
+
c = !0;
|
|
828
|
+
};
|
|
829
|
+
}, [i, r]), i ? /* @__PURE__ */ l(
|
|
830
|
+
"div",
|
|
831
|
+
{
|
|
832
|
+
"data-sc-part": "controls",
|
|
833
|
+
"data-sc-placement": "docked",
|
|
834
|
+
className: e,
|
|
835
|
+
style: n,
|
|
836
|
+
"aria-busy": d ? void 0 : "true",
|
|
837
|
+
children: d ? /* @__PURE__ */ l(d, { mode: "embedded" }) : null
|
|
838
|
+
}
|
|
839
|
+
) : null;
|
|
840
|
+
}
|
|
841
|
+
function Et({ className: t, style: e }) {
|
|
842
|
+
return H("Editor.History"), /* @__PURE__ */ l("div", { "data-sc-part": "history", className: t, style: e, children: /* @__PURE__ */ l(Ge, {}) });
|
|
843
|
+
}
|
|
844
|
+
function wt({ className: t, style: e }) {
|
|
845
|
+
return H("Editor.Menu"), /* @__PURE__ */ l("div", { "data-sc-part": "menu", className: t, style: e, children: /* @__PURE__ */ l(Ce, {}) });
|
|
846
|
+
}
|
|
847
|
+
function xt({ className: t, style: e }) {
|
|
848
|
+
H("Editor.Add");
|
|
849
|
+
const { get: n } = je(), [r, s] = R(!1), [i, d] = R(!1), o = async (a) => {
|
|
850
|
+
if (s(!1), a === "shape") {
|
|
851
|
+
d(!0);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
await n().handleAddElement(a);
|
|
855
|
+
}, c = async (a) => {
|
|
856
|
+
d(!1), await n().handleAddElement("shape", { shapeType: a });
|
|
857
|
+
};
|
|
858
|
+
return /* @__PURE__ */ L("div", { "data-sc-part": "add", className: t, style: e, children: [
|
|
859
|
+
/* @__PURE__ */ l(
|
|
860
|
+
Ie,
|
|
861
|
+
{
|
|
862
|
+
trigger: /* @__PURE__ */ L(Ne, { delayDuration: 0, children: [
|
|
863
|
+
/* @__PURE__ */ l(_e, { asChild: !0, children: /* @__PURE__ */ l($e, { variant: "ghost", size: "icon", "aria-label": "Add element", children: /* @__PURE__ */ l(re, { icon: q.plus, className: "sc:size-6" }) }) }),
|
|
864
|
+
/* @__PURE__ */ l(De, { children: /* @__PURE__ */ l("p", { children: "Add element" }) })
|
|
865
|
+
] }),
|
|
866
|
+
isOpen: r,
|
|
867
|
+
onToggle: s,
|
|
868
|
+
position: "bottom",
|
|
869
|
+
align: "start",
|
|
870
|
+
children: /* @__PURE__ */ l(ke, { minWidth: "180px", children: Te.map((a) => /* @__PURE__ */ l(
|
|
871
|
+
Oe,
|
|
872
|
+
{
|
|
873
|
+
icon: a.icon,
|
|
874
|
+
label: a.label,
|
|
875
|
+
onClick: () => o(a.type)
|
|
876
|
+
},
|
|
877
|
+
a.type
|
|
878
|
+
)) })
|
|
879
|
+
}
|
|
880
|
+
),
|
|
881
|
+
/* @__PURE__ */ l(
|
|
882
|
+
Ae,
|
|
883
|
+
{
|
|
884
|
+
isOpen: i,
|
|
885
|
+
onClose: () => d(!1),
|
|
886
|
+
onSelectType: c
|
|
887
|
+
}
|
|
888
|
+
)
|
|
889
|
+
] });
|
|
890
|
+
}
|
|
891
|
+
const Dt = {
|
|
892
|
+
/** The one provider boundary — session, design, live state, error boundary. */
|
|
893
|
+
Root: ye,
|
|
894
|
+
/** The editable artboard (the ONE lazy renderer boundary — D9). */
|
|
895
|
+
Canvas: at,
|
|
896
|
+
/** Live product mockup. ×N under one Root is valid. */
|
|
897
|
+
Preview: be,
|
|
898
|
+
/** Form input bound to a design text layer by typed token (T1). */
|
|
899
|
+
TextField: ct,
|
|
900
|
+
/** Smart commerce part: completeness + payload assembly; submit = host callback. */
|
|
901
|
+
Buy: ht,
|
|
902
|
+
/** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */
|
|
903
|
+
Layers: vt,
|
|
904
|
+
/** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */
|
|
905
|
+
Controls: bt,
|
|
906
|
+
/** Undo/redo controls. Requires Editor.Canvas. */
|
|
907
|
+
History: Et,
|
|
908
|
+
/** The one ⋯ overflow menu. Requires Editor.Canvas. */
|
|
909
|
+
Menu: wt,
|
|
910
|
+
/** The ⊕ add-element menu. Requires Editor.Canvas. */
|
|
911
|
+
Add: xt
|
|
912
|
+
};
|
|
913
|
+
function At(t) {
|
|
914
|
+
return /* @__PURE__ */ l(ye, { ...t, __validation: "warn" });
|
|
915
|
+
}
|
|
916
|
+
const Lt = ae(
|
|
917
|
+
function(e, n) {
|
|
918
|
+
const { children: r, className: s, style: i, maxHeight: d, ...o } = e, [c, a] = R(null);
|
|
919
|
+
return _(() => {
|
|
920
|
+
let m = !1;
|
|
921
|
+
return ve().then(
|
|
922
|
+
(u) => {
|
|
923
|
+
m || a(() => u);
|
|
924
|
+
},
|
|
925
|
+
(u) => {
|
|
926
|
+
console.error("[RealtimeCanvas] failed to load the rendering chunk:", u);
|
|
927
|
+
}
|
|
928
|
+
), () => {
|
|
929
|
+
m = !0;
|
|
930
|
+
};
|
|
931
|
+
}, []), c ? /* @__PURE__ */ l(c, { ref: n, selfScope: !0, maxHeight: d, className: s, style: i, ...o, children: r }) : /* @__PURE__ */ l(
|
|
932
|
+
"div",
|
|
933
|
+
{
|
|
934
|
+
className: `sc-root${s ? ` ${s}` : ""}`,
|
|
935
|
+
style: { minHeight: d ?? 200, ...i },
|
|
936
|
+
"aria-busy": "true"
|
|
937
|
+
}
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
function Bt(t) {
|
|
942
|
+
return /* @__PURE__ */ l(be, { ...t });
|
|
943
|
+
}
|
|
944
|
+
function Ut() {
|
|
945
|
+
const { mockups: t, isRendering: e, error: n } = j();
|
|
946
|
+
return { mockups: t, isRendering: e, error: n };
|
|
947
|
+
}
|
|
948
|
+
Le();
|
|
949
|
+
export {
|
|
950
|
+
Qe as D,
|
|
951
|
+
fe as E,
|
|
952
|
+
Lt as R,
|
|
953
|
+
Dt as a,
|
|
954
|
+
At as b,
|
|
955
|
+
Bt as c,
|
|
956
|
+
he as d,
|
|
957
|
+
Ut as e,
|
|
958
|
+
j as u,
|
|
959
|
+
Je as v
|
|
960
|
+
};
|
|
961
|
+
//# sourceMappingURL=embed-Cdbjay9i.js.map
|