@snowcone-app/canvas 0.11.1 → 0.12.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.
- package/dist/{CanvasStateV1-D3THl2Zc.js → CanvasStateV1-CKsfggNP.js} +3 -3
- package/dist/{CanvasStateV1-D3THl2Zc.js.map → CanvasStateV1-CKsfggNP.js.map} +1 -1
- package/dist/{HybridHistoryManager-DANuzx7G.js → HybridHistoryManager-NL3zyEl4.js} +21 -21
- package/dist/{HybridHistoryManager-DANuzx7G.js.map → HybridHistoryManager-NL3zyEl4.js.map} +1 -1
- package/dist/{ImportManager-NCtkY5Z0.js → ImportManager-eotl7r5d.js} +2 -2
- package/dist/{ImportManager-NCtkY5Z0.js.map → ImportManager-eotl7r5d.js.map} +1 -1
- package/dist/{ThemeContext-U-VDtIiS.js → ThemeContext-Cl1JPVLZ.js} +2 -2
- package/dist/{ThemeContext-U-VDtIiS.js.map → ThemeContext-Cl1JPVLZ.js.map} +1 -1
- package/dist/advanced.mjs +8 -8
- package/dist/api/embed.d.ts +3 -1
- package/dist/api/stable.d.ts +3 -1
- package/dist/components/embed-realtime/context.d.ts +9 -0
- package/dist/components/embed-realtime/usePieceGuideBundle.d.ts +48 -0
- package/dist/design/template-fields.d.ts +39 -1
- package/dist/embed.mjs +215 -155
- package/dist/embed.mjs.map +1 -1
- package/dist/hooks/useDeadBindingWarning.d.ts +2 -2
- package/dist/hooks/useFontBinding.d.ts +23 -0
- package/dist/index.mjs +24 -23
- package/dist/internals.mjs +4 -4
- package/dist/template-fields-IgDV7PRY.js +1627 -0
- package/dist/template-fields-IgDV7PRY.js.map +1 -0
- package/dist/testing.mjs +2 -2
- package/dist/utils/UnifiedFontService.d.ts +7 -0
- package/dist/{validation-C857Ptxn.js → validation-BpmNOvuY.js} +14 -4
- package/dist/{validation-C857Ptxn.js.map → validation-BpmNOvuY.js.map} +1 -1
- package/package.json +3 -3
- package/dist/template-fields-C8Tj67ek.js +0 -1585
- package/dist/template-fields-C8Tj67ek.js.map +0 -1
package/dist/advanced.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { D as te, I as q, r as re, v as ne, i as oe, e as ae } from "./validation-
|
|
2
|
-
import { j as it, k as lt, l as ct, B as dt, m as ut, n as mt, o as ft, p as ht, q as pt, s as gt, t as xt, w as bt, x as yt, y as vt, F as wt, z as St, G as Ct, H as Tt, J as Et, K as $t, L as kt, N as At, O as Ft, Q as Pt, R as Nt, S as Rt, T as Bt, U as Mt, V as Dt, W as zt, X as It, Y as Ot, Z as Lt, _ as Wt, $ as Kt, a0 as _t, a1 as Gt, a2 as Ut, a3 as jt, a4 as Jt, a5 as qt, a6 as Vt, a7 as Xt, a8 as Yt, a9 as Zt, aa as Ht, ab as Qt, ac as er, ad as tr, ae as rr, af as nr } from "./validation-
|
|
3
|
-
import { u as V } from "./ThemeContext-
|
|
4
|
-
import { E as ar, P as sr, T as ir, p as lr, s as cr, b as dr, c as ur, d as mr, e as fr, f as hr, g as pr, a as gr } from "./ThemeContext-
|
|
5
|
-
import { c as se, G as ie, F as le, g as ce, r as de, u as ue } from "./HybridHistoryManager-
|
|
6
|
-
import { A as br, B as yr, I as vr, P as wr, R as Sr, S as Cr, T as Tr, h as Er, a as $r, b as kr, i as Ar, d as Fr, e as Pr, f as Nr, j as Rr, k as Br, l as Mr, m as Dr, n as zr, o as Ir, p as Or, q as Lr, s as Wr, t as Kr, v as _r, w as Gr, x as Ur } from "./HybridHistoryManager-
|
|
7
|
-
import { I as me } from "./ImportManager-
|
|
8
|
-
import { i as Jr, a as qr, b as Vr, c as Xr, d as Yr } from "./ImportManager-
|
|
1
|
+
import { D as te, I as q, r as re, v as ne, i as oe, e as ae } from "./validation-BpmNOvuY.js";
|
|
2
|
+
import { j as it, k as lt, l as ct, B as dt, m as ut, n as mt, o as ft, p as ht, q as pt, s as gt, t as xt, w as bt, x as yt, y as vt, F as wt, z as St, G as Ct, H as Tt, J as Et, K as $t, L as kt, N as At, O as Ft, Q as Pt, R as Nt, S as Rt, T as Bt, U as Mt, V as Dt, W as zt, X as It, Y as Ot, Z as Lt, _ as Wt, $ as Kt, a0 as _t, a1 as Gt, a2 as Ut, a3 as jt, a4 as Jt, a5 as qt, a6 as Vt, a7 as Xt, a8 as Yt, a9 as Zt, aa as Ht, ab as Qt, ac as er, ad as tr, ae as rr, af as nr } from "./validation-BpmNOvuY.js";
|
|
3
|
+
import { u as V } from "./ThemeContext-Cl1JPVLZ.js";
|
|
4
|
+
import { E as ar, P as sr, T as ir, p as lr, s as cr, b as dr, c as ur, d as mr, e as fr, f as hr, g as pr, a as gr } from "./ThemeContext-Cl1JPVLZ.js";
|
|
5
|
+
import { c as se, G as ie, F as le, g as ce, r as de, u as ue } from "./HybridHistoryManager-NL3zyEl4.js";
|
|
6
|
+
import { A as br, B as yr, I as vr, P as wr, R as Sr, S as Cr, T as Tr, h as Er, a as $r, b as kr, i as Ar, d as Fr, e as Pr, f as Nr, j as Rr, k as Br, l as Mr, m as Dr, n as zr, o as Ir, p as Or, q as Lr, s as Wr, t as Kr, v as _r, w as Gr, x as Ur } from "./HybridHistoryManager-NL3zyEl4.js";
|
|
7
|
+
import { I as me } from "./ImportManager-eotl7r5d.js";
|
|
8
|
+
import { i as Jr, a as qr, b as Vr, c as Xr, d as Yr } from "./ImportManager-eotl7r5d.js";
|
|
9
9
|
import { useState as A, useCallback as y, useEffect as X, useMemo as Y, useRef as B, memo as fe } from "react";
|
|
10
10
|
import { jsxs as b, jsx as s, Fragment as he } from "react/jsx-runtime";
|
|
11
11
|
import { Tooltip as M, TooltipTrigger as D, Button as pe, TooltipContent as z, Popover as ge, PopoverTrigger as xe, PopoverContent as be } from "@snowcone-app/ui";
|
package/dist/api/embed.d.ts
CHANGED
|
@@ -50,9 +50,11 @@ export { useTextBinding } from '../hooks/useTextBinding.js';
|
|
|
50
50
|
export { useImageBinding } from '../hooks/useImageBinding.js';
|
|
51
51
|
export { useColorBinding } from '../hooks/useColorBinding.js';
|
|
52
52
|
export type { ColorBindingResult } from '../hooks/useColorBinding.js';
|
|
53
|
+
export { useFontBinding } from '../hooks/useFontBinding.js';
|
|
54
|
+
export type { FontBindingResult } from '../hooks/useFontBinding.js';
|
|
53
55
|
export { useElementByName } from '../hooks/useElementByName.js';
|
|
54
56
|
export { readTemplateFields, withTemplateFields, TEMPLATE_FIELDS_KEY, } from '../design/template-fields.js';
|
|
55
|
-
export type { TemplateField, TemplateTextField, TemplateImageField, TemplateColorField, } from '../design/template-fields.js';
|
|
57
|
+
export type { TemplateField, TemplateTextField, TemplateImageField, TemplateColorField, TemplateSelectField, } from '../design/template-fields.js';
|
|
56
58
|
export { CanvasServicesProvider, useCanvasServices } from '../contexts/CanvasServicesContext.js';
|
|
57
59
|
export type { CanvasServices, ResolvedCanvasServices } from '../contexts/CanvasServicesContext.js';
|
|
58
60
|
export { createProxyImageSearch, createProxyGenerate } from '../services/imageSearch.js';
|
package/dist/api/stable.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export { useImageBinding } from '../hooks/useImageBinding.js';
|
|
|
32
32
|
export type { ImageBindingResult, ImageBindingOptions, ImageFitMode } from '../hooks/useImageBinding.js';
|
|
33
33
|
export { useColorBinding } from '../hooks/useColorBinding.js';
|
|
34
34
|
export type { ColorBindingResult } from '../hooks/useColorBinding.js';
|
|
35
|
+
export { useFontBinding } from '../hooks/useFontBinding.js';
|
|
36
|
+
export type { FontBindingResult } from '../hooks/useFontBinding.js';
|
|
35
37
|
export { useElementByName } from '../hooks/useElementByName.js';
|
|
36
38
|
export { useContentReady } from '../hooks/useContentReady.js';
|
|
37
39
|
export type { UseContentReadyOptions } from '../hooks/useContentReady.js';
|
|
@@ -51,5 +53,5 @@ export type { ServerRenderRequest } from '../rendering/serialize-for-server.js';
|
|
|
51
53
|
export { design, DesignBuilder } from '../design/design-builder.js';
|
|
52
54
|
export type { Anchor, ShapeKind, DesignArtboard, BackgroundOptions, ImageOptions, TextOptions, ShapeOptions, } from '../design/design-builder.js';
|
|
53
55
|
export { readTemplateFields, withTemplateFields, TEMPLATE_FIELDS_KEY, } from '../design/template-fields.js';
|
|
54
|
-
export type { TemplateField, TemplateTextField, TemplateImageField, TemplateColorField, } from '../design/template-fields.js';
|
|
56
|
+
export type { TemplateField, TemplateTextField, TemplateImageField, TemplateColorField, TemplateSelectField, } from '../design/template-fields.js';
|
|
55
57
|
export type { CanvasStateV1, SerializedArtboard, SerializedElement, DeserializeResult, ValidationResult, } from '../state/index.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RenderSession, RenderProduct, RenderState, MockupResult } from '@snowcone-app/sdk';
|
|
2
2
|
import { DesignBuilder } from '../../design/design-builder.js';
|
|
3
|
+
import { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';
|
|
3
4
|
export interface EmbedContextValue {
|
|
4
5
|
/** The single session the editor pushes renders to. `null` if the session
|
|
5
6
|
* failed to construct (a config fail-fast, surfaced via `error`). Escape
|
|
@@ -21,6 +22,14 @@ export interface EmbedContextValue {
|
|
|
21
22
|
error: string | null;
|
|
22
23
|
/** Default edit→render throttle (ms). */
|
|
23
24
|
throttleMs: number;
|
|
25
|
+
/**
|
|
26
|
+
* The product's printable-area guides (dead zones, safe areas) — fetched by
|
|
27
|
+
* `<RealtimeEmbed>` and already gated on the design's artboard matching the
|
|
28
|
+
* print-file frame they were authored in. `null` when the product has none,
|
|
29
|
+
* the fetch failed, or the dims don't line up. `<RealtimeCanvas>` forwards
|
|
30
|
+
* this to the editor so embedders get the same overlay snowcone.app shows.
|
|
31
|
+
*/
|
|
32
|
+
pieceGuides: PieceGuidesConfig | null;
|
|
24
33
|
/** Dispatch a server render for the embed's placement. Sets `isRendering`. */
|
|
25
34
|
pushRender: (state: RenderState, throttleMs?: number) => void;
|
|
26
35
|
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';
|
|
2
|
+
import { PieceGuide, PieceGuideRendererStyle } from '../../rendering/PieceGuideRenderer.js';
|
|
3
|
+
/** Backend base hosting `GET /printables/by-gvid/:gvid/piece-guides`. */
|
|
4
|
+
export declare const PIECE_GUIDES_API_BASE = "https://api.snowcone.app";
|
|
5
|
+
/** Wire shape of the piece-guides endpoint (the consumer-safe subset). */
|
|
6
|
+
interface RawPieceGuidesResponse {
|
|
7
|
+
artboardWidth: number;
|
|
8
|
+
artboardHeight: number;
|
|
9
|
+
/** Inches→px conversion factor for `safeAreaInsetInches`. */
|
|
10
|
+
templateDpi: number;
|
|
11
|
+
pieces: Array<{
|
|
12
|
+
id: string;
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
rotation?: number;
|
|
18
|
+
safeAreaInsetInches?: number;
|
|
19
|
+
}>;
|
|
20
|
+
pieceGuides?: Record<string, PieceGuide>;
|
|
21
|
+
pieceGuidesStyle?: PieceGuideRendererStyle;
|
|
22
|
+
}
|
|
23
|
+
/** A fetched bundle: the overlay config plus the artboard frame it was authored in. */
|
|
24
|
+
export interface PieceGuideBundle {
|
|
25
|
+
/** The print-file frame the piece coords live in. */
|
|
26
|
+
artboardWidth: number;
|
|
27
|
+
artboardHeight: number;
|
|
28
|
+
config: PieceGuidesConfig;
|
|
29
|
+
}
|
|
30
|
+
/** Convert the wire response into a renderer-ready bundle (inches → px, etc.). */
|
|
31
|
+
export declare function transformPieceGuides(raw: RawPieceGuidesResponse): PieceGuideBundle;
|
|
32
|
+
/**
|
|
33
|
+
* Gate the bundle on the design's artboard matching the print-file frame the
|
|
34
|
+
* guides were authored in — the same gate snowcone.app's editor applies. A
|
|
35
|
+
* design authored at other dims would render the overlay misaligned, so it's
|
|
36
|
+
* skipped (with a dev hint, since the fix — author at the placement's dims —
|
|
37
|
+
* is on the embedder's side).
|
|
38
|
+
*/
|
|
39
|
+
export declare function pieceGuidesForArtboard(bundle: PieceGuideBundle, artboard: {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
} | undefined): PieceGuidesConfig | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Fetch the piece-guide bundle for a variant (gvid). Returns null while
|
|
45
|
+
* loading, when `gvid` is undefined, and on any error (silent degrade).
|
|
46
|
+
*/
|
|
47
|
+
export declare function usePieceGuideBundle(gvid: string | undefined, apiBase?: string): PieceGuideBundle | null;
|
|
48
|
+
export {};
|
|
@@ -8,6 +8,14 @@ export interface TemplateTextField {
|
|
|
8
8
|
label: string;
|
|
9
9
|
/** Placeholder text for the input. */
|
|
10
10
|
placeholder?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Designer's length limit for the buyer's text — long names overflow fixed
|
|
13
|
+
* layouts. Intent, not enforcement: your control applies it (an input's
|
|
14
|
+
* `maxLength`); the canvas itself doesn't truncate.
|
|
15
|
+
*/
|
|
16
|
+
maxLength?: number;
|
|
17
|
+
/** Optional grouping label — consecutive fields sharing a group render together. */
|
|
18
|
+
group?: string;
|
|
11
19
|
}
|
|
12
20
|
/** A buyer-swappable image slot, bound to elements by their `name` property. */
|
|
13
21
|
export interface TemplateImageField {
|
|
@@ -20,6 +28,8 @@ export interface TemplateImageField {
|
|
|
20
28
|
placeholder?: string;
|
|
21
29
|
/** How the buyer's image fits the original element bounds. Default: "cover". */
|
|
22
30
|
fit?: ImageFitMode;
|
|
31
|
+
/** Optional grouping label — consecutive fields sharing a group render together. */
|
|
32
|
+
group?: string;
|
|
23
33
|
}
|
|
24
34
|
/** A buyer-editable color, matched by value across all elements that use it. */
|
|
25
35
|
export interface TemplateColorField {
|
|
@@ -28,9 +38,37 @@ export interface TemplateColorField {
|
|
|
28
38
|
color: string;
|
|
29
39
|
/** Label shown to the buyer (e.g. "Accent color"). */
|
|
30
40
|
label: string;
|
|
41
|
+
/** Optional grouping label — consecutive fields sharing a group render together. */
|
|
42
|
+
group?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A pick-one choice over designer-authored options — "one of these 3 badges",
|
|
46
|
+
* a curated font list, preset text variants. Binds to elements by `name` and
|
|
47
|
+
* swaps ONE property on them, chosen by `property`:
|
|
48
|
+
*
|
|
49
|
+
* - `'text'` → apply via `useTextBinding(name).setText(value)`
|
|
50
|
+
* - `'imageUrl'` → apply via `useImageBinding(name).setImageUrl(value)`
|
|
51
|
+
* - `'fontFamily'` → apply via `useFontBinding(name).setFontFamily(value)`
|
|
52
|
+
* (values must be Google Fonts families)
|
|
53
|
+
*/
|
|
54
|
+
export interface TemplateSelectField {
|
|
55
|
+
type: 'select';
|
|
56
|
+
/** Element name (matches canvas layer `name` property). */
|
|
57
|
+
name: string;
|
|
58
|
+
/** Label shown to the buyer (e.g. "Badge"). */
|
|
59
|
+
label: string;
|
|
60
|
+
/** Which property of the bound element(s) the chosen value sets. */
|
|
61
|
+
property: 'text' | 'imageUrl' | 'fontFamily';
|
|
62
|
+
/** The designer-authored choices, in display order. */
|
|
63
|
+
options: Array<{
|
|
64
|
+
label: string;
|
|
65
|
+
value: string;
|
|
66
|
+
}>;
|
|
67
|
+
/** Optional grouping label — consecutive fields sharing a group render together. */
|
|
68
|
+
group?: string;
|
|
31
69
|
}
|
|
32
70
|
/** One buyer-editable aspect of a template. */
|
|
33
|
-
export type TemplateField = TemplateTextField | TemplateImageField | TemplateColorField;
|
|
71
|
+
export type TemplateField = TemplateTextField | TemplateImageField | TemplateColorField | TemplateSelectField;
|
|
34
72
|
/**
|
|
35
73
|
* The key template fields are stored under on the state document.
|
|
36
74
|
* Kept as `personalization` for compatibility with designs saved on snowcone.app.
|
package/dist/embed.mjs
CHANGED
|
@@ -1,210 +1,270 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import { b as
|
|
3
|
-
import { y
|
|
4
|
-
import { jsx as
|
|
5
|
-
import { createContext as
|
|
6
|
-
import { assertVariantSelected as
|
|
7
|
-
import { S as
|
|
8
|
-
import { D as
|
|
9
|
-
const L =
|
|
10
|
-
function
|
|
11
|
-
const e =
|
|
1
|
+
import { a as z, e as J } from "./validation-BpmNOvuY.js";
|
|
2
|
+
import { b as Re, d as Te, f as xe } from "./validation-BpmNOvuY.js";
|
|
3
|
+
import { y } from "./HybridHistoryManager-NL3zyEl4.js";
|
|
4
|
+
import { jsx as $, Fragment as Y } from "react/jsx-runtime";
|
|
5
|
+
import { createContext as Q, useContext as X, useState as x, useEffect as U, useMemo as I, useRef as M } from "react";
|
|
6
|
+
import { assertVariantSelected as Z, RenderSession as ee } from "@snowcone-app/sdk";
|
|
7
|
+
import { S as te, s as ne } from "./template-fields-IgDV7PRY.js";
|
|
8
|
+
import { D as Me, T as Ae, d as Ce, r as Ge, a as Ne, e as Be, f as Pe, g as _e, h as Oe, w as qe } from "./template-fields-IgDV7PRY.js";
|
|
9
|
+
const L = Q(void 0);
|
|
10
|
+
function P() {
|
|
11
|
+
const e = X(L);
|
|
12
12
|
if (!e)
|
|
13
13
|
throw new Error(
|
|
14
14
|
"useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered inside <RealtimeEmbed>. Wrap them: <RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>"
|
|
15
15
|
);
|
|
16
16
|
return e;
|
|
17
17
|
}
|
|
18
|
-
const
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
18
|
+
const re = "https://api.snowcone.app";
|
|
19
|
+
function se(e) {
|
|
20
|
+
const t = e.pieces.map((n) => ({
|
|
21
|
+
id: n.id,
|
|
22
|
+
x: n.x,
|
|
23
|
+
y: n.y,
|
|
24
|
+
width: n.width,
|
|
25
|
+
height: n.height,
|
|
26
|
+
rotation: typeof n.rotation == "number" ? n.rotation : void 0,
|
|
27
|
+
safeAreaInsetPx: typeof n.safeAreaInsetInches == "number" && n.safeAreaInsetInches > 0 ? n.safeAreaInsetInches * e.templateDpi : void 0
|
|
28
|
+
}));
|
|
29
|
+
return {
|
|
30
|
+
artboardWidth: e.artboardWidth,
|
|
31
|
+
artboardHeight: e.artboardHeight,
|
|
32
|
+
config: {
|
|
33
|
+
pieces: t,
|
|
34
|
+
guides: e.pieceGuides ?? {},
|
|
35
|
+
style: e.pieceGuidesStyle
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function ie(e, t) {
|
|
40
|
+
var n;
|
|
41
|
+
if (t) {
|
|
42
|
+
if (t.width !== e.artboardWidth || t.height !== e.artboardHeight) {
|
|
43
|
+
typeof y < "u" && ((n = y.env) == null ? void 0 : n.NODE_ENV) !== "production" && console.warn(
|
|
44
|
+
`[RealtimeEmbed] This product has printable-area guides (authored at ${e.artboardWidth}×${e.artboardHeight}), but the design's artboard is ${t.width}×${t.height} — the dead-zone overlay is skipped because the coordinates wouldn't line up. Author the design at the placement's dimensions to get it.`
|
|
45
|
+
);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
return e.config;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function oe(e, t = re) {
|
|
52
|
+
const [n, s] = x(null);
|
|
53
|
+
return U(() => {
|
|
54
|
+
if (!e) {
|
|
55
|
+
s(null);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let i = !1;
|
|
59
|
+
return fetch(`${t}/printables/by-gvid/${encodeURIComponent(e)}/piece-guides`).then(async (r) => {
|
|
60
|
+
if (!r.ok) throw new Error(`status ${r.status}`);
|
|
61
|
+
return await r.json();
|
|
62
|
+
}).then((r) => {
|
|
63
|
+
i || s(se(r));
|
|
64
|
+
}).catch(() => {
|
|
65
|
+
i || s(null);
|
|
66
|
+
}), () => {
|
|
67
|
+
i = !0;
|
|
68
|
+
};
|
|
69
|
+
}, [e, t]), n;
|
|
70
|
+
}
|
|
71
|
+
const E = "[RealtimeEmbed]";
|
|
72
|
+
function ae(e) {
|
|
73
|
+
var s, i;
|
|
74
|
+
if ((s = e == null ? void 0 : e.requiredPlacements) != null && s.length)
|
|
75
|
+
return e.requiredPlacements.filter((r) => !r.autoFilledByVariant).map((r) => r.label);
|
|
76
|
+
const t = new Set(
|
|
77
|
+
(((i = e == null ? void 0 : e.options) == null ? void 0 : i.combinations) ?? []).map((r) => r.variantId).filter((r) => typeof r == "string" && r !== "")
|
|
25
78
|
);
|
|
26
|
-
return !!(e != null && e.variantId) ||
|
|
79
|
+
return !!(e != null && e.variantId) || t.size > 1 ? [] : (e == null ? void 0 : e.placements) ?? [];
|
|
27
80
|
}
|
|
28
|
-
function
|
|
29
|
-
var
|
|
30
|
-
if (e || console.error(`${
|
|
31
|
-
`${
|
|
32
|
-
), (
|
|
33
|
-
`${
|
|
34
|
-
),
|
|
81
|
+
function ce({ shop: e, product: t, design: n, hasGrant: s }) {
|
|
82
|
+
var l, a;
|
|
83
|
+
if (e || console.error(`${E} \`shop\` is required (your publishable shop id).`), s || console.error(
|
|
84
|
+
`${E} no grant source — pass \`grantUrl\` (a proxy to mintRealtimeGrant) or \`grant\`. Without it the session can never authorize and no mockup renders.`
|
|
85
|
+
), (l = t == null ? void 0 : t.mockupIds) != null && l.length || console.error(
|
|
86
|
+
`${E} product.mockupIds is empty — pass the catalog scene codes (product.mockups[].id) you want rendered, e.g. ["FV1qjO"].`
|
|
87
|
+
), t != null && t.options)
|
|
35
88
|
try {
|
|
36
|
-
|
|
37
|
-
} catch (
|
|
38
|
-
console.error(`${
|
|
89
|
+
Z(t);
|
|
90
|
+
} catch (o) {
|
|
91
|
+
console.error(`${E} ${o instanceof Error ? o.message : String(o)}`);
|
|
39
92
|
}
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
`${
|
|
43
|
-
), (a =
|
|
44
|
-
`${
|
|
93
|
+
const i = n.toJSON(), r = i.activeArtboard, h = ae(t);
|
|
94
|
+
h.length > 1 && console.error(
|
|
95
|
+
`${E} product ${t.productId} requires placements [${h.join(", ")}] but <RealtimeEmbed> renders a single placement ("${r}"). The render will time out waiting for the others. This product needs the eject path — see https://developers.snowcone.app/embed-mode#eject.`
|
|
96
|
+
), (a = t == null ? void 0 : t.placements) != null && a.length && !t.placements.includes(r) && console.warn(
|
|
97
|
+
`${E} the design's placement "${r}" is not in product.placements [${t.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 }).`
|
|
45
98
|
);
|
|
46
|
-
const c =
|
|
47
|
-
|
|
48
|
-
`${
|
|
99
|
+
const c = i.elements.map((o) => o.name).filter((o) => !!o), g = c.filter((o, p) => c.indexOf(o) !== p);
|
|
100
|
+
g.length && console.warn(
|
|
101
|
+
`${E} duplicate layer name(s) [${[...new Set(g)].join(", ")}] — useTextBinding(name) / useImageBinding(name) bind to the FIRST match, so a duplicate name makes a control edit the wrong layer. Keep names unique.`
|
|
49
102
|
);
|
|
50
103
|
}
|
|
51
|
-
function
|
|
104
|
+
function ue(e) {
|
|
52
105
|
if ("grantUrl" in e && e.grantUrl)
|
|
53
106
|
return { grantUrl: e.grantUrl };
|
|
54
|
-
const
|
|
55
|
-
return typeof
|
|
107
|
+
const t = e.grant;
|
|
108
|
+
return typeof t == "function" ? { getToken: t } : { getToken: () => Promise.resolve(t) };
|
|
56
109
|
}
|
|
57
110
|
const V = 8e3;
|
|
58
|
-
function
|
|
111
|
+
function le(e) {
|
|
59
112
|
return `[RealtimeEmbed] No mockup after ${Math.round(V / 1e3)}s. Common causes: a variant product missing \`variantId\` (pass \`product.options\` so the embed can flag it up front), a multi-placement product (the server waits for every required placement but <RealtimeEmbed> sends only "${e}" — pass \`product.requiredPlacements\` so this is flagged at mount; such products need the eject path), an unreachable or non-public asset URL in the design, or the placement "${e}" not existing on the product. The render may still arrive — this is a heads-up, not a failure.`;
|
|
60
113
|
}
|
|
61
|
-
function
|
|
62
|
-
const { shop:
|
|
63
|
-
|
|
64
|
-
|
|
114
|
+
function Ee(e) {
|
|
115
|
+
const { shop: t, product: n, design: s, throttleMs: i = 200, onMockups: r, onRenderError: h, wsUrl: c, services: g, children: l } = e, a = I(() => s.toJSON().activeArtboard, [s]), o = oe(n.variantId ?? n.defaultGvid), p = I(() => {
|
|
116
|
+
if (!o) return null;
|
|
117
|
+
const u = s.toJSON().artboards[0];
|
|
118
|
+
return ie(o, u) ?? null;
|
|
119
|
+
}, [o, s]), v = M(r), d = M(h);
|
|
120
|
+
v.current = r, d.current = h;
|
|
121
|
+
const [_, W] = x([]), [S, w] = x(!0), [O, k] = x(null), A = !!("grantUrl" in e && e.grantUrl || "grant" in e && e.grant), C = ue(e), H = "grantUrl" in C ? C.grantUrl : "getToken", G = `${n.productId}|${n.mockupIds.join(",")}|${n.variantId ?? ""}`, R = I(
|
|
65
122
|
() => {
|
|
66
123
|
try {
|
|
67
|
-
return { session: new
|
|
68
|
-
} catch (
|
|
69
|
-
return { error:
|
|
124
|
+
return { session: new ee({ shop: t, product: n, wsUrl: c, ...C }) };
|
|
125
|
+
} catch (u) {
|
|
126
|
+
return { error: u instanceof Error ? u.message : String(u) };
|
|
70
127
|
}
|
|
71
128
|
},
|
|
72
129
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
73
|
-
[
|
|
74
|
-
),
|
|
75
|
-
|
|
76
|
-
var
|
|
77
|
-
if (typeof
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
80
|
-
|
|
130
|
+
[t, G, a, c, H]
|
|
131
|
+
), f = "session" in R ? R.session : null, T = "error" in R ? R.error : null, q = M(null);
|
|
132
|
+
U(() => {
|
|
133
|
+
var u;
|
|
134
|
+
if (typeof y < "u" && ((u = y.env) == null ? void 0 : u.NODE_ENV) !== "production") {
|
|
135
|
+
const m = `${t}|${G}|${a}|${A}`;
|
|
136
|
+
if (q.current === m) return;
|
|
137
|
+
q.current = m, ce({ shop: t, product: n, design: s, hasGrant: A });
|
|
81
138
|
}
|
|
82
|
-
}, [
|
|
83
|
-
const N =
|
|
84
|
-
|
|
139
|
+
}, [t, G, a, A]);
|
|
140
|
+
const N = I(() => (u, m = i) => {
|
|
141
|
+
f && (k(null), w(!0), f.renderState(a, u, m).catch((b) => {
|
|
85
142
|
var F;
|
|
86
|
-
const
|
|
87
|
-
|
|
143
|
+
const j = b instanceof Error ? b.message : String(b);
|
|
144
|
+
k(j), w(!1), (F = d.current) == null || F.call(d, j);
|
|
88
145
|
}));
|
|
89
|
-
}, [
|
|
90
|
-
|
|
91
|
-
var
|
|
92
|
-
if (
|
|
93
|
-
|
|
146
|
+
}, [f, a, i]);
|
|
147
|
+
U(() => {
|
|
148
|
+
var u;
|
|
149
|
+
if (T) {
|
|
150
|
+
k(T), w(!1), (u = d.current) == null || u.call(d, T);
|
|
94
151
|
return;
|
|
95
152
|
}
|
|
96
|
-
if (
|
|
97
|
-
return
|
|
98
|
-
var
|
|
99
|
-
|
|
100
|
-
}),
|
|
101
|
-
var
|
|
102
|
-
|
|
103
|
-
}), N(
|
|
104
|
-
}, [
|
|
105
|
-
var
|
|
106
|
-
if (
|
|
107
|
-
const
|
|
108
|
-
return () => clearTimeout(
|
|
109
|
-
}, [
|
|
110
|
-
const K =
|
|
153
|
+
if (f)
|
|
154
|
+
return f.onMockups((m) => {
|
|
155
|
+
var b;
|
|
156
|
+
W(m), w(!1), (b = v.current) == null || b.call(v, m);
|
|
157
|
+
}), f.onError((m) => {
|
|
158
|
+
var b;
|
|
159
|
+
k(m), w(!1), (b = d.current) == null || b.call(d, m);
|
|
160
|
+
}), N(s.toServerRequest()), () => f.close();
|
|
161
|
+
}, [f, T]), U(() => {
|
|
162
|
+
var m;
|
|
163
|
+
if (!S || typeof y > "u" || ((m = y.env) == null ? void 0 : m.NODE_ENV) === "production") return;
|
|
164
|
+
const u = setTimeout(() => console.warn(le(a)), V);
|
|
165
|
+
return () => clearTimeout(u);
|
|
166
|
+
}, [S, a]);
|
|
167
|
+
const K = I(
|
|
111
168
|
() => ({
|
|
112
|
-
session:
|
|
113
|
-
design:
|
|
169
|
+
session: f,
|
|
170
|
+
design: s,
|
|
114
171
|
placement: a,
|
|
115
|
-
product:
|
|
116
|
-
mockups:
|
|
117
|
-
isRendering:
|
|
118
|
-
error:
|
|
119
|
-
throttleMs:
|
|
172
|
+
product: n,
|
|
173
|
+
mockups: _,
|
|
174
|
+
isRendering: S,
|
|
175
|
+
error: O,
|
|
176
|
+
throttleMs: i,
|
|
177
|
+
pieceGuides: p,
|
|
120
178
|
pushRender: N
|
|
121
179
|
}),
|
|
122
|
-
[
|
|
123
|
-
),
|
|
124
|
-
return
|
|
180
|
+
[f, s, a, n, _, S, O, i, p, N]
|
|
181
|
+
), D = /* @__PURE__ */ $(L.Provider, { value: K, children: l });
|
|
182
|
+
return g ? /* @__PURE__ */ $(z, { services: g, children: D }) : D;
|
|
125
183
|
}
|
|
126
|
-
function
|
|
184
|
+
function Ie({
|
|
127
185
|
children: e,
|
|
128
|
-
kit:
|
|
129
|
-
inheritTheme:
|
|
130
|
-
maxHeight:
|
|
131
|
-
services:
|
|
132
|
-
className:
|
|
133
|
-
style:
|
|
186
|
+
kit: t = "embed-only",
|
|
187
|
+
inheritTheme: n = !0,
|
|
188
|
+
maxHeight: s,
|
|
189
|
+
services: i,
|
|
190
|
+
className: r,
|
|
191
|
+
style: h
|
|
134
192
|
}) {
|
|
135
|
-
const { design: c, placement:
|
|
136
|
-
return /* @__PURE__ */
|
|
137
|
-
|
|
193
|
+
const { design: c, placement: g, throttleMs: l, pieceGuides: a, pushRender: o } = P(), p = I(() => c.toJSON(), [c]);
|
|
194
|
+
return /* @__PURE__ */ $("div", { className: `app-modern${r ? ` ${r}` : ""}`, style: h, children: /* @__PURE__ */ $(
|
|
195
|
+
te,
|
|
138
196
|
{
|
|
139
|
-
kit:
|
|
140
|
-
inheritTheme:
|
|
141
|
-
services:
|
|
142
|
-
artboards:
|
|
143
|
-
activeArtboard:
|
|
144
|
-
initialElements:
|
|
145
|
-
layoutConfig:
|
|
197
|
+
kit: t,
|
|
198
|
+
inheritTheme: n,
|
|
199
|
+
services: i,
|
|
200
|
+
artboards: p.artboards,
|
|
201
|
+
activeArtboard: g,
|
|
202
|
+
initialElements: p.elements,
|
|
203
|
+
layoutConfig: s ? { maxHeight: s } : void 0,
|
|
146
204
|
overlay: e,
|
|
147
|
-
|
|
205
|
+
pieceGuides: a ?? void 0,
|
|
206
|
+
onChange: (v) => o(ne(v), l)
|
|
148
207
|
}
|
|
149
208
|
) });
|
|
150
209
|
}
|
|
151
|
-
const
|
|
152
|
-
function
|
|
153
|
-
for (const
|
|
154
|
-
if (
|
|
155
|
-
return
|
|
210
|
+
const de = 1.2, B = [1200, 1400, 1600, 1800, 2e3, 2500, 3e3, 4e3];
|
|
211
|
+
function me(e) {
|
|
212
|
+
for (const t of B)
|
|
213
|
+
if (t >= e) return t;
|
|
214
|
+
return B[B.length - 1];
|
|
156
215
|
}
|
|
157
|
-
function
|
|
158
|
-
if (!(e > 0) || !(
|
|
159
|
-
const
|
|
160
|
-
return `[RealtimeMockup] mockup rendered at ${e}px but displayed at ~${
|
|
216
|
+
function he(e, t) {
|
|
217
|
+
if (!(e > 0) || !(t > 0) || t <= e * de) return null;
|
|
218
|
+
const n = me(t);
|
|
219
|
+
return `[RealtimeMockup] mockup rendered at ${e}px but displayed at ~${t} device px — the preview will look soft. Pass \`product.width\` (e.g. ${n}) on <RealtimeEmbed> for a crisp preview.`;
|
|
161
220
|
}
|
|
162
|
-
function
|
|
221
|
+
function $e({
|
|
163
222
|
mockupId: e,
|
|
164
|
-
fallback:
|
|
165
|
-
alt:
|
|
166
|
-
className:
|
|
167
|
-
style:
|
|
223
|
+
fallback: t = null,
|
|
224
|
+
alt: n = "Live product mockup",
|
|
225
|
+
className: s,
|
|
226
|
+
style: i
|
|
168
227
|
}) {
|
|
169
|
-
const { mockups:
|
|
228
|
+
const { mockups: r } = P(), h = M(/* @__PURE__ */ new Set()), c = e ? r.find((l) => l.mockupId === e && l.imageUrl) : r.find((l) => l.imageUrl);
|
|
170
229
|
if (!(c != null && c.imageUrl))
|
|
171
|
-
return /* @__PURE__ */
|
|
172
|
-
const
|
|
173
|
-
var
|
|
174
|
-
if (typeof
|
|
175
|
-
const a =
|
|
176
|
-
if (
|
|
177
|
-
const
|
|
178
|
-
|
|
230
|
+
return /* @__PURE__ */ $(Y, { children: t });
|
|
231
|
+
const g = (l) => {
|
|
232
|
+
var d;
|
|
233
|
+
if (typeof y > "u" || ((d = y.env) == null ? void 0 : d.NODE_ENV) === "production" || typeof window > "u" || h.current.has(c.mockupId)) return;
|
|
234
|
+
const a = l.currentTarget, o = a.getBoundingClientRect().width;
|
|
235
|
+
if (o <= 0) return;
|
|
236
|
+
const p = Math.round(o * (window.devicePixelRatio || 1)), v = he(a.naturalWidth, p);
|
|
237
|
+
v && (h.current.add(c.mockupId), console.warn(v));
|
|
179
238
|
};
|
|
180
239
|
return (
|
|
181
240
|
// eslint-disable-next-line @next/next/no-img-element
|
|
182
|
-
/* @__PURE__ */
|
|
241
|
+
/* @__PURE__ */ $("img", { src: c.imageUrl, alt: n, className: s, style: i, onLoad: g })
|
|
183
242
|
);
|
|
184
243
|
}
|
|
185
|
-
function
|
|
186
|
-
const { mockups: e, isRendering:
|
|
187
|
-
return { mockups: e, isRendering:
|
|
244
|
+
function we() {
|
|
245
|
+
const { mockups: e, isRendering: t, error: n } = P();
|
|
246
|
+
return { mockups: e, isRendering: t, error: n };
|
|
188
247
|
}
|
|
189
|
-
|
|
248
|
+
J();
|
|
190
249
|
export {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
250
|
+
z as CanvasServicesProvider,
|
|
251
|
+
Me as DesignBuilder,
|
|
252
|
+
Ie as RealtimeCanvas,
|
|
253
|
+
Ee as RealtimeEmbed,
|
|
254
|
+
$e as RealtimeMockup,
|
|
255
|
+
Ae as TEMPLATE_FIELDS_KEY,
|
|
256
|
+
Re as createProxyGenerate,
|
|
257
|
+
Te as createProxyImageSearch,
|
|
258
|
+
Ce as design,
|
|
259
|
+
Ge as readTemplateFields,
|
|
260
|
+
xe as useCanvasServices,
|
|
261
|
+
Ne as useColorBinding,
|
|
262
|
+
Be as useElementByName,
|
|
263
|
+
Pe as useFontBinding,
|
|
264
|
+
_e as useImageBinding,
|
|
265
|
+
we as useRealtimeMockups,
|
|
266
|
+
Oe as useTextBinding,
|
|
267
|
+
ce as validateEmbed,
|
|
268
|
+
qe as withTemplateFields
|
|
209
269
|
};
|
|
210
270
|
//# sourceMappingURL=embed.mjs.map
|