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