@snowcone-app/canvas 0.17.0 → 0.17.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.
@@ -2,7 +2,7 @@ import { jsx as x, jsxs as B, Fragment as h } from "react/jsx-runtime";
2
2
  import { forwardRef as T, useMemo as I, useRef as E, useContext as R, useLayoutEffect as $ } from "react";
3
3
  import { S as j } from "./SnowconeCanvas-C3eZ9PP8.js";
4
4
  import { s as w } from "./template-fields-GOM4MNfq.js";
5
- import { u as A, E as F } from "./embed-Bdj4PKUA.js";
5
+ import { u as A, E as F } from "./embed-B5kewSQY.js";
6
6
  import { c as G, b as M } from "./EditorContext-CyanYzo2.js";
7
7
  import { T as N } from "./HybridHistoryManager-Bht98XRv.js";
8
8
  function U() {
@@ -65,4 +65,4 @@ const P = T(
65
65
  export {
66
66
  P as EditorCanvasImpl
67
67
  };
68
- //# sourceMappingURL=EditorCanvasImpl-DkgE5-C2.js.map
68
+ //# sourceMappingURL=EditorCanvasImpl-C8SsT3C2.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EditorCanvasImpl-DkgE5-C2.js","sources":["../src/components/editor/EditorCanvasImpl.tsx"],"sourcesContent":["'use client';\n\n/**\n * The heavy half of `Editor.Canvas` (and of the legacy `<RealtimeCanvas>`),\n * extracted from RealtimeCanvas's body. This module statically imports\n * `SnowconeCanvas` — i.e. the full rendering engine — and is therefore ONLY\n * ever reached through a dynamic `import()` (D9): the embed entry's static\n * import graph stays renderer-free, mechanically enforced by the\n * import-graph CI check.\n *\n * Beyond the original wiring (seed → SnowconeCanvas, edit →\n * `serializeStateForServer` → `pushRender`), this adds the ADR-0085 §3 store\n * wiring: every canvas change lands in the Root's {@link DesignStateStore}\n * (the ONE live design state), and a {@link CanvasBridge} is registered so\n * `Editor.TextField` writes route through the editor command path (undo/redo,\n * repaint) while a canvas is mounted — the editor document stays the single\n * write authority.\n */\n\nimport React, {\n forwardRef,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from 'react';\nimport { SnowconeCanvas } from '../embed/SnowconeCanvas.js';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useElementsContext } from '../../contexts/ElementsContext.js';\nimport { useCommandContext } from '../../contexts/CommandContext.js';\nimport { TextElement } from '../../core/TextElement.js';\nimport { EditorRootInternalsContext } from './RootInternals.js';\n\nexport interface EditorCanvasImplProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /** Editor chrome preset. `Editor.Canvas` pins the chrome-less `'embed-only'`;\n * the legacy `<RealtimeCanvas kit>` prop passes richer presets through. */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /** Privileged-service wiring override (usually inherited from Root). */\n services?: CanvasServices;\n /** Observe the live design state (the same {@link CanvasState} the Root's\n * state store tracks). Safe to pass inline — read through a ref. */\n onChange?: (state: CanvasState) => void;\n /** Whether the wrapping div self-applies `.sc-root`. The legacy\n * `<RealtimeCanvas>` always did (it could be the only Snowcone DOM on the\n * page); under `Editor.Root` the Root applies it once and parts never\n * self-apply (ADR-0085). Re-applying is harmless (same variables), so the\n * legacy wrapper keeps `true` for bit-identical back-compat. */\n selfScope?: boolean;\n /** `data-sc-part` value for the wrapping div (the parts contract). */\n partAttr?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Runs INSIDE the canvas's editor context (the overlay slot) and registers\n * the imperative bridge sibling parts use to edit by layer name through the\n * command path. Generalizes `useTextBinding`'s write mechanics to a dynamic\n * name (a hook can't take names at call time).\n */\nfunction CanvasBindingBridge(): null {\n const { elementStore } = useElementsContext();\n const { executeElementUpdate } = useCommandContext();\n // Tolerant on purpose: the legacy <RealtimeCanvas> is supported inside a\n // bare EmbedContext (advanced consumers provide their own); only under an\n // <Editor.Root> is there a registry to bridge into.\n const internals = useContext(EditorRootInternalsContext);\n\n const latest = useRef({ elementStore, executeElementUpdate });\n latest.current = { elementStore, executeElementUpdate };\n\n const registry = internals?.registry ?? null;\n useLayoutEffect(() => {\n if (!registry) return;\n return registry.registerCanvasBridge({\n setTextByName(name: string, text: string): boolean {\n const { elementStore: store, executeElementUpdate: execute } = latest.current;\n const matches = store.getAllByName(name).filter((el): el is TextElement => el instanceof TextElement);\n if (matches.length === 0) return false;\n for (const el of matches) {\n const cloned = el.clone() as TextElement;\n cloned.setText(text);\n execute(el, cloned);\n }\n return true;\n },\n });\n }, [registry]);\n\n return null;\n}\n\nexport const EditorCanvasImpl = forwardRef<SnowconeCanvasHandle, EditorCanvasImplProps>(\n function EditorCanvasImpl(\n {\n children,\n kit = 'embed-only',\n inheritTheme = true,\n maxHeight,\n services,\n onChange,\n selfScope = false,\n partAttr,\n className,\n style,\n }: EditorCanvasImplProps,\n ref,\n ): React.ReactElement {\n const { placement, throttleMs, pieceGuides, pushRender, stateStore } = useEmbedContext();\n\n // Seed from the LIVE store, not the original design (ADR-0085 §3): the\n // store starts as design.toJSON(), so a fresh mount is identical to the\n // old behavior — but edits made while this chunk was loading (e.g. a\n // TextField keystroke in the first second) survive instead of being\n // clobbered by a stale seed. Captured once per store identity; later\n // store changes flow through the editor document, not re-seeding.\n const seed = useMemo(() => stateStore.getState(), [stateStore]);\n\n // Latest-ref so a host's inline `onChange` identity never matters here\n // (SnowconeCanvas already refs ITS callback; this keeps ours symmetric).\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const rootClass = selfScope ? 'sc-root' : 'sc-canvas-frame';\n\n return (\n <div className={`${rootClass}${className ? ` ${className}` : ''}`} style={style} data-sc-part={partAttr}>\n <SnowconeCanvas\n ref={ref}\n kit={kit}\n inheritTheme={inheritTheme}\n services={services}\n artboards={seed.artboards}\n activeArtboard={placement}\n initialElements={seed.elements}\n layoutConfig={maxHeight ? { maxHeight } : undefined}\n overlay={\n <>\n <CanvasBindingBridge />\n {children}\n </>\n }\n // #566: the product's printable-area / dead-zone overlay, fetched and\n // dims-gated by the Root — same overlay snowcone.app's editor\n // shows, so a buyer can't unknowingly edit under a camera cutout.\n pieceGuides={pieceGuides ?? undefined}\n onChange={(state) => {\n // ONE store, last-write-wins (ADR-0085 §3): the editor document is\n // the write authority while mounted; the Root store derives from\n // its onChange, then the render follows the store.\n stateStore.setState(state);\n pushRender(serializeStateForServer(state), throttleMs);\n onChangeRef.current?.(state);\n }}\n />\n </div>\n );\n },\n);\n\nexport type { CanvasState, SnowconeCanvasHandle };\n"],"names":["CanvasBindingBridge","elementStore","useElementsContext","executeElementUpdate","useCommandContext","internals","useContext","EditorRootInternalsContext","latest","useRef","registry","useLayoutEffect","name","text","store","execute","matches","el","TextElement","cloned","EditorCanvasImpl","forwardRef","children","kit","inheritTheme","maxHeight","services","onChange","selfScope","partAttr","className","style","ref","placement","throttleMs","pieceGuides","pushRender","stateStore","useEmbedContext","seed","useMemo","onChangeRef","jsx","SnowconeCanvas","jsxs","Fragment","state","serializeStateForServer","_a"],"mappings":";;;;;;;AAyEA,SAASA,IAA4B;AACnC,QAAM,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GACnB,EAAE,sBAAAC,EAAA,IAAyBC,EAAA,GAI3BC,IAAYC,EAAWC,CAA0B,GAEjDC,IAASC,EAAO,EAAE,cAAAR,GAAc,sBAAAE,GAAsB;AAC5D,EAAAK,EAAO,UAAU,EAAE,cAAAP,GAAc,sBAAAE,EAAA;AAEjC,QAAMO,KAAWL,KAAA,gBAAAA,EAAW,aAAY;AACxC,SAAAM,EAAgB,MAAM;AACpB,QAAKD;AACL,aAAOA,EAAS,qBAAqB;AAAA,QACnC,cAAcE,GAAcC,GAAuB;AACjD,gBAAM,EAAE,cAAcC,GAAO,sBAAsBC,EAAA,IAAYP,EAAO,SAChEQ,IAAUF,EAAM,aAAaF,CAAI,EAAE,OAAO,CAACK,MAA0BA,aAAcC,CAAW;AACpG,cAAIF,EAAQ,WAAW,EAAG,QAAO;AACjC,qBAAWC,KAAMD,GAAS;AACxB,kBAAMG,IAASF,EAAG,MAAA;AAClB,YAAAE,EAAO,QAAQN,CAAI,GACnBE,EAAQE,GAAIE,CAAM;AAAA,UACpB;AACA,iBAAO;AAAA,QACT;AAAA,MAAA,CACD;AAAA,EACH,GAAG,CAACT,CAAQ,CAAC,GAEN;AACT;AAEO,MAAMU,IAAmBC;AAAA,EAC9B,SACE;AAAA,IACE,UAAAC;AAAA,IACA,KAAAC,IAAM;AAAA,IACN,cAAAC,IAAe;AAAA,IACf,WAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,UAAAC;AAAA,IACA,WAAAC;AAAA,IACA,OAAAC;AAAA,EAAA,GAEFC,GACoB;AACpB,UAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,aAAAC,GAAa,YAAAC,GAAY,YAAAC,EAAA,IAAeC,EAAA,GAQjEC,IAAOC,EAAQ,MAAMH,EAAW,YAAY,CAACA,CAAU,CAAC,GAIxDI,IAAchC,EAAOkB,CAAQ;AACnC,WAAAc,EAAY,UAAUd,GAKpB,gBAAAe,EAAC,OAAA,EAAI,WAAW,GAHAd,IAAY,YAAY,iBAGZ,GAAGE,IAAY,IAAIA,CAAS,KAAK,EAAE,IAAI,OAAAC,GAAc,gBAAcF,GAC7F,UAAA,gBAAAa;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,KAAAX;AAAA,QACA,KAAAT;AAAA,QACA,cAAAC;AAAA,QACA,UAAAE;AAAA,QACA,WAAWa,EAAK;AAAA,QAChB,gBAAgBN;AAAA,QAChB,iBAAiBM,EAAK;AAAA,QACtB,cAAcd,IAAY,EAAE,WAAAA,EAAA,IAAc;AAAA,QAC1C,SACE,gBAAAmB,EAAAC,GAAA,EACE,UAAA;AAAA,UAAA,gBAAAH,EAAC1C,GAAA,EAAoB;AAAA,UACpBsB;AAAA,QAAA,GACH;AAAA,QAKF,aAAaa,KAAe;AAAA,QAC5B,UAAU,CAACW,MAAU;;AAInB,UAAAT,EAAW,SAASS,CAAK,GACzBV,EAAWW,EAAwBD,CAAK,GAAGZ,CAAU,IACrDc,IAAAP,EAAY,YAAZ,QAAAO,EAAA,KAAAP,GAAsBK;AAAA,QACxB;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,EAEJ;AACF;"}
1
+ {"version":3,"file":"EditorCanvasImpl-C8SsT3C2.js","sources":["../src/components/editor/EditorCanvasImpl.tsx"],"sourcesContent":["'use client';\n\n/**\n * The heavy half of `Editor.Canvas` (and of the legacy `<RealtimeCanvas>`),\n * extracted from RealtimeCanvas's body. This module statically imports\n * `SnowconeCanvas` — i.e. the full rendering engine — and is therefore ONLY\n * ever reached through a dynamic `import()` (D9): the embed entry's static\n * import graph stays renderer-free, mechanically enforced by the\n * import-graph CI check.\n *\n * Beyond the original wiring (seed → SnowconeCanvas, edit →\n * `serializeStateForServer` → `pushRender`), this adds the ADR-0085 §3 store\n * wiring: every canvas change lands in the Root's {@link DesignStateStore}\n * (the ONE live design state), and a {@link CanvasBridge} is registered so\n * `Editor.TextField` writes route through the editor command path (undo/redo,\n * repaint) while a canvas is mounted — the editor document stays the single\n * write authority.\n */\n\nimport React, {\n forwardRef,\n useContext,\n useLayoutEffect,\n useMemo,\n useRef,\n type CSSProperties,\n type ReactNode,\n} from 'react';\nimport { SnowconeCanvas } from '../embed/SnowconeCanvas.js';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useElementsContext } from '../../contexts/ElementsContext.js';\nimport { useCommandContext } from '../../contexts/CommandContext.js';\nimport { TextElement } from '../../core/TextElement.js';\nimport { EditorRootInternalsContext } from './RootInternals.js';\n\nexport interface EditorCanvasImplProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /** Editor chrome preset. `Editor.Canvas` pins the chrome-less `'embed-only'`;\n * the legacy `<RealtimeCanvas kit>` prop passes richer presets through. */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /** Privileged-service wiring override (usually inherited from Root). */\n services?: CanvasServices;\n /** Observe the live design state (the same {@link CanvasState} the Root's\n * state store tracks). Safe to pass inline — read through a ref. */\n onChange?: (state: CanvasState) => void;\n /** Whether the wrapping div self-applies `.sc-root`. The legacy\n * `<RealtimeCanvas>` always did (it could be the only Snowcone DOM on the\n * page); under `Editor.Root` the Root applies it once and parts never\n * self-apply (ADR-0085). Re-applying is harmless (same variables), so the\n * legacy wrapper keeps `true` for bit-identical back-compat. */\n selfScope?: boolean;\n /** `data-sc-part` value for the wrapping div (the parts contract). */\n partAttr?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * Runs INSIDE the canvas's editor context (the overlay slot) and registers\n * the imperative bridge sibling parts use to edit by layer name through the\n * command path. Generalizes `useTextBinding`'s write mechanics to a dynamic\n * name (a hook can't take names at call time).\n */\nfunction CanvasBindingBridge(): null {\n const { elementStore } = useElementsContext();\n const { executeElementUpdate } = useCommandContext();\n // Tolerant on purpose: the legacy <RealtimeCanvas> is supported inside a\n // bare EmbedContext (advanced consumers provide their own); only under an\n // <Editor.Root> is there a registry to bridge into.\n const internals = useContext(EditorRootInternalsContext);\n\n const latest = useRef({ elementStore, executeElementUpdate });\n latest.current = { elementStore, executeElementUpdate };\n\n const registry = internals?.registry ?? null;\n useLayoutEffect(() => {\n if (!registry) return;\n return registry.registerCanvasBridge({\n setTextByName(name: string, text: string): boolean {\n const { elementStore: store, executeElementUpdate: execute } = latest.current;\n const matches = store.getAllByName(name).filter((el): el is TextElement => el instanceof TextElement);\n if (matches.length === 0) return false;\n for (const el of matches) {\n const cloned = el.clone() as TextElement;\n cloned.setText(text);\n execute(el, cloned);\n }\n return true;\n },\n });\n }, [registry]);\n\n return null;\n}\n\nexport const EditorCanvasImpl = forwardRef<SnowconeCanvasHandle, EditorCanvasImplProps>(\n function EditorCanvasImpl(\n {\n children,\n kit = 'embed-only',\n inheritTheme = true,\n maxHeight,\n services,\n onChange,\n selfScope = false,\n partAttr,\n className,\n style,\n }: EditorCanvasImplProps,\n ref,\n ): React.ReactElement {\n const { placement, throttleMs, pieceGuides, pushRender, stateStore } = useEmbedContext();\n\n // Seed from the LIVE store, not the original design (ADR-0085 §3): the\n // store starts as design.toJSON(), so a fresh mount is identical to the\n // old behavior — but edits made while this chunk was loading (e.g. a\n // TextField keystroke in the first second) survive instead of being\n // clobbered by a stale seed. Captured once per store identity; later\n // store changes flow through the editor document, not re-seeding.\n const seed = useMemo(() => stateStore.getState(), [stateStore]);\n\n // Latest-ref so a host's inline `onChange` identity never matters here\n // (SnowconeCanvas already refs ITS callback; this keeps ours symmetric).\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n const rootClass = selfScope ? 'sc-root' : 'sc-canvas-frame';\n\n return (\n <div className={`${rootClass}${className ? ` ${className}` : ''}`} style={style} data-sc-part={partAttr}>\n <SnowconeCanvas\n ref={ref}\n kit={kit}\n inheritTheme={inheritTheme}\n services={services}\n artboards={seed.artboards}\n activeArtboard={placement}\n initialElements={seed.elements}\n layoutConfig={maxHeight ? { maxHeight } : undefined}\n overlay={\n <>\n <CanvasBindingBridge />\n {children}\n </>\n }\n // #566: the product's printable-area / dead-zone overlay, fetched and\n // dims-gated by the Root — same overlay snowcone.app's editor\n // shows, so a buyer can't unknowingly edit under a camera cutout.\n pieceGuides={pieceGuides ?? undefined}\n onChange={(state) => {\n // ONE store, last-write-wins (ADR-0085 §3): the editor document is\n // the write authority while mounted; the Root store derives from\n // its onChange, then the render follows the store.\n stateStore.setState(state);\n pushRender(serializeStateForServer(state), throttleMs);\n onChangeRef.current?.(state);\n }}\n />\n </div>\n );\n },\n);\n\nexport type { CanvasState, SnowconeCanvasHandle };\n"],"names":["CanvasBindingBridge","elementStore","useElementsContext","executeElementUpdate","useCommandContext","internals","useContext","EditorRootInternalsContext","latest","useRef","registry","useLayoutEffect","name","text","store","execute","matches","el","TextElement","cloned","EditorCanvasImpl","forwardRef","children","kit","inheritTheme","maxHeight","services","onChange","selfScope","partAttr","className","style","ref","placement","throttleMs","pieceGuides","pushRender","stateStore","useEmbedContext","seed","useMemo","onChangeRef","jsx","SnowconeCanvas","jsxs","Fragment","state","serializeStateForServer","_a"],"mappings":";;;;;;;AAyEA,SAASA,IAA4B;AACnC,QAAM,EAAE,cAAAC,EAAA,IAAiBC,EAAA,GACnB,EAAE,sBAAAC,EAAA,IAAyBC,EAAA,GAI3BC,IAAYC,EAAWC,CAA0B,GAEjDC,IAASC,EAAO,EAAE,cAAAR,GAAc,sBAAAE,GAAsB;AAC5D,EAAAK,EAAO,UAAU,EAAE,cAAAP,GAAc,sBAAAE,EAAA;AAEjC,QAAMO,KAAWL,KAAA,gBAAAA,EAAW,aAAY;AACxC,SAAAM,EAAgB,MAAM;AACpB,QAAKD;AACL,aAAOA,EAAS,qBAAqB;AAAA,QACnC,cAAcE,GAAcC,GAAuB;AACjD,gBAAM,EAAE,cAAcC,GAAO,sBAAsBC,EAAA,IAAYP,EAAO,SAChEQ,IAAUF,EAAM,aAAaF,CAAI,EAAE,OAAO,CAACK,MAA0BA,aAAcC,CAAW;AACpG,cAAIF,EAAQ,WAAW,EAAG,QAAO;AACjC,qBAAWC,KAAMD,GAAS;AACxB,kBAAMG,IAASF,EAAG,MAAA;AAClB,YAAAE,EAAO,QAAQN,CAAI,GACnBE,EAAQE,GAAIE,CAAM;AAAA,UACpB;AACA,iBAAO;AAAA,QACT;AAAA,MAAA,CACD;AAAA,EACH,GAAG,CAACT,CAAQ,CAAC,GAEN;AACT;AAEO,MAAMU,IAAmBC;AAAA,EAC9B,SACE;AAAA,IACE,UAAAC;AAAA,IACA,KAAAC,IAAM;AAAA,IACN,cAAAC,IAAe;AAAA,IACf,WAAAC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,UAAAC;AAAA,IACA,WAAAC;AAAA,IACA,OAAAC;AAAA,EAAA,GAEFC,GACoB;AACpB,UAAM,EAAE,WAAAC,GAAW,YAAAC,GAAY,aAAAC,GAAa,YAAAC,GAAY,YAAAC,EAAA,IAAeC,EAAA,GAQjEC,IAAOC,EAAQ,MAAMH,EAAW,YAAY,CAACA,CAAU,CAAC,GAIxDI,IAAchC,EAAOkB,CAAQ;AACnC,WAAAc,EAAY,UAAUd,GAKpB,gBAAAe,EAAC,OAAA,EAAI,WAAW,GAHAd,IAAY,YAAY,iBAGZ,GAAGE,IAAY,IAAIA,CAAS,KAAK,EAAE,IAAI,OAAAC,GAAc,gBAAcF,GAC7F,UAAA,gBAAAa;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,KAAAX;AAAA,QACA,KAAAT;AAAA,QACA,cAAAC;AAAA,QACA,UAAAE;AAAA,QACA,WAAWa,EAAK;AAAA,QAChB,gBAAgBN;AAAA,QAChB,iBAAiBM,EAAK;AAAA,QACtB,cAAcd,IAAY,EAAE,WAAAA,EAAA,IAAc;AAAA,QAC1C,SACE,gBAAAmB,EAAAC,GAAA,EACE,UAAA;AAAA,UAAA,gBAAAH,EAAC1C,GAAA,EAAoB;AAAA,UACpBsB;AAAA,QAAA,GACH;AAAA,QAKF,aAAaa,KAAe;AAAA,QAC5B,UAAU,CAACW,MAAU;;AAInB,UAAAT,EAAW,SAASS,CAAK,GACzBV,EAAWW,EAAwBD,CAAK,GAAGZ,CAAU,IACrDc,IAAAP,EAAY,YAAZ,QAAAO,EAAA,KAAAP,GAAsBK;AAAA,QACxB;AAAA,MAAA;AAAA,IAAA,GAEJ;AAAA,EAEJ;AACF;"}
@@ -39,7 +39,7 @@ export declare class DesignStateStore {
39
39
  */
40
40
  updateTextLayer(name: string, text: string): void;
41
41
  /** ≥1 element with visible content (completeness rule C4): non-empty text,
42
- * an image with a URL, or a shape. */
42
+ * an image with a URL, or a shape. Hidden elements don't count. */
43
43
  hasRenderableElement(): boolean;
44
44
  private emit;
45
45
  }
@@ -130,9 +130,10 @@ class Be {
130
130
  this.setState({ ...this.state, elements: s });
131
131
  }
132
132
  /** ≥1 element with visible content (completeness rule C4): non-empty text,
133
- * an image with a URL, or a shape. */
133
+ * an image with a URL, or a shape. Hidden elements don't count. */
134
134
  hasRenderableElement() {
135
135
  return this.state.elements.some((e) => {
136
+ if (e.visible === !1) return !1;
136
137
  const n = e.transformType;
137
138
  if (n === "image") return !!e.imageUrl;
138
139
  if (n === "shape" || n === "group" || n === "path") return !0;
@@ -431,7 +432,7 @@ function he(t) {
431
432
  /* @__PURE__ */ f("div", { className: "sc-root", style: { display: "contents" }, "data-sc-part": "root", children: /* @__PURE__ */ f(qe, { reportedError: r, onRetry: () => s(null), children: /* @__PURE__ */ f(Me, { ...t, internals: a }) }) })
432
433
  );
433
434
  }
434
- let Ve = () => import("./EditorCanvasImpl-DkgE5-C2.js").then((t) => t.EditorCanvasImpl);
435
+ let Ve = () => import("./EditorCanvasImpl-C8SsT3C2.js").then((t) => t.EditorCanvasImpl);
435
436
  function ge() {
436
437
  return Ve();
437
438
  }
@@ -734,4 +735,4 @@ export {
734
735
  L as u,
735
736
  $e as v
736
737
  };
737
- //# sourceMappingURL=embed-Bdj4PKUA.js.map
738
+ //# sourceMappingURL=embed-B5kewSQY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed-B5kewSQY.js","sources":["../src/components/embed-realtime/context.ts","../src/components/embed-realtime/validateEmbed.ts","../src/components/editor/designStateStore.ts","../src/components/editor/RootInternals.ts","../src/components/editor/EditorRoot.tsx","../src/components/editor/EditorCanvas.tsx","../src/components/editor/EditorPreview.tsx","../src/components/editor/EditorTextField.tsx","../src/components/editor/EditorBuy.tsx","../src/components/editor/index.ts","../src/components/embed-realtime/RealtimeEmbed.tsx","../src/components/embed-realtime/RealtimeCanvas.tsx","../src/components/embed-realtime/RealtimeMockup.tsx","../src/components/embed-realtime/useRealtimeMockups.ts","../src/api/embed.ts"],"sourcesContent":["'use client';\n\n/**\n * Shared context for the realtime embed primitives. `<RealtimeEmbed>` owns the\n * single {@link RenderSession} and the live mockup state; `<RealtimeCanvas>` and\n * `<RealtimeMockup>` read it from here so the editor and the preview can be laid\n * out freely yet can never desync (they share one session, one design, one\n * placement).\n */\n\nimport { createContext, useContext } from 'react';\nimport type { RenderSession, RenderProduct, RenderState, MockupResult } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport type { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';\nimport type { DesignStateStore } from '../editor/designStateStore.js';\n\nexport interface EmbedContextValue {\n /** The single session the editor pushes renders to. `null` if the session\n * failed to construct (a config fail-fast, surfaced via `error`). Escape\n * hatch for advanced use. */\n session: RenderSession | null;\n /** The design the embed was seeded with — single source of truth for both the\n * canvas seed and the seed render. */\n design: AnyDesign;\n /** The placement name (= the design's artboard name). Both the canvas artboard\n * and every `renderState` call use this; derived once so it can't drift. */\n placement: string;\n /** The product being rendered against. */\n product: RenderProduct;\n /** Latest mockups from the session. Reactive — updates re-render consumers. */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render error message, or null. */\n error: string | null;\n /** Default edit→render throttle (ms). */\n throttleMs: number;\n /**\n * The product's printable-area guides (dead zones, safe areas) — fetched by\n * `<RealtimeEmbed>` and already gated on the design's artboard matching the\n * print-file frame they were authored in. `null` when the product has none,\n * the fetch failed, or the dims don't line up. `<RealtimeCanvas>` forwards\n * this to the editor so embedders get the same overlay snowcone.app shows.\n */\n pieceGuides: PieceGuidesConfig | null;\n /** Dispatch a server render for the embed's placement. Sets `isRendering`. */\n pushRender: (state: RenderState, throttleMs?: number) => void;\n /**\n * The ONE live design state under this Root (ADR-0085 §3 / T2): seeded from\n * `design`, updated by every canvas change and every `Editor.TextField`\n * write, last-write-wins. Commerce parts read THIS, never the seed. Stable\n * identity; subscribe for updates (`useSyncExternalStore`-shaped).\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\n stateStore: DesignStateStore;\n}\n\nexport const EmbedContext = createContext<EmbedContextValue | undefined>(undefined);\n\n/**\n * Read the embed context. Throws a clear error when called outside\n * `<RealtimeEmbed>` — the most common wiring mistake.\n */\nexport function useEmbedContext(): EmbedContextValue {\n const ctx = useContext(EmbedContext);\n if (!ctx) {\n throw new Error(\n 'useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered ' +\n 'inside <RealtimeEmbed>. Wrap them: ' +\n '<RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>'\n );\n }\n return ctx;\n}\n","'use client';\n\n/**\n * Mount-time assertions for the realtime embed. Catches the silent-break wiring\n * mistakes that otherwise produce a blank canvas or a mockup that never renders:\n *\n * - no grant source (the session can't authorize → silent hang)\n * - a variant product with no `variantId` (→ ~30s render hang), AND the\n * can't-even-tell case: neither `variantId` nor `options` passed\n * - empty `mockupIds` (nothing to render)\n * - the design's placement isn't one of the product's placements (renderState\n * targets an artboard the product doesn't have → silent blank mockup)\n * - a multi-placement product (the embed renders ONE placement, so the server\n * waits on the rest and the render times out ~15s in — needs the eject path)\n * - duplicate layer names (binding hooks resolve to the wrong element)\n *\n * Two consumption modes (ADR-0085 / F3):\n * - `validateEmbed` — the legacy advisory API: logs `console.warn` /\n * `console.error` and never throws, so a partly-wired `<RealtimeEmbed>`\n * still mounts and renders what it can. Dev-only at the call site.\n * - `collectEmbedIssues` — the structured list; `Editor.Root` THROWS on the\n * error-severity issues (console.error is invisible to headless agents).\n */\n\nimport { assertVariantSelected, type RenderProduct } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\n\nexport interface ValidateEmbedInput {\n shop: string;\n product: RenderProduct;\n design: AnyDesign;\n hasGrant: boolean;\n}\n\n/** One wiring problem found at mount. `error`-severity issues break the embed\n * (no render will ever arrive / it targets the wrong thing); `warn`-severity\n * issues are advisory. */\nexport interface EmbedIssue {\n severity: 'error' | 'warn';\n /** Stable issue key, carried into `EditorError.data.issue` in throw mode. */\n issue:\n | 'missing-shop'\n | 'missing-grant'\n | 'empty-mockup-ids'\n | 'variant-required'\n | 'multi-placement'\n | 'placement-mismatch'\n | 'duplicate-layer-names';\n message: string;\n}\n\nconst TAG = '[RealtimeEmbed]';\n\n/**\n * The placement labels this product demands a canvas_state for. Prefers the\n * catalog's `requiredPlacements` contract; variant-auto-filled (color)\n * placements don't count — `variantId` satisfies them (the missing-variantId\n * case has its own guard above). Falls back to the bare `placements` label\n * list ONLY when the product has no variant in play: a label list can't say\n * which entries are auto-filled colors, but without a variant none are.\n */\nfunction requiredPlacementLabels(product: RenderProduct): string[] {\n if (product?.requiredPlacements?.length) {\n return product.requiredPlacements.filter((p) => !p.autoFilledByVariant).map((p) => p.label);\n }\n const variantIds = new Set(\n (product?.options?.combinations ?? [])\n .map((c) => c.variantId)\n .filter((id): id is string => typeof id === 'string' && id !== '')\n );\n const hasVariantAxis = Boolean(product?.variantId) || variantIds.size > 1;\n return hasVariantAxis ? [] : (product?.placements ?? []);\n}\n\n/** Find every wiring problem. Pure — no logging, no throwing. */\nexport function collectEmbedIssues({ shop, product, design, hasGrant }: ValidateEmbedInput): EmbedIssue[] {\n const issues: EmbedIssue[] = [];\n\n if (!shop) {\n issues.push({\n severity: 'error',\n issue: 'missing-shop',\n message: '`shop` is required (your publishable shop id).',\n });\n }\n\n if (!hasGrant) {\n issues.push({\n severity: 'error',\n issue: 'missing-grant',\n message:\n 'no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) ' +\n 'or `grant`. Without it the session can never authorize and no mockup renders.',\n });\n }\n\n if (!product?.mockupIds?.length) {\n issues.push({\n severity: 'error',\n issue: 'empty-mockup-ids',\n message:\n 'product.mockupIds is empty — pass the catalog scene codes ' +\n '(product.mockups[].id) you want rendered, e.g. [\"FV1qjO\"].',\n });\n }\n\n // Variant axis: a product with a color/size option REQUIRES a variantId or the\n // render hangs ~30s waiting for a color blob that never comes. When `options`\n // (the catalog combinations) is passed we can detect the axis and fail fast\n // before the session's constructor throws. When `options` is NOT passed we\n // can't see the axis — so we DON'T warn here (a no-`options` product might\n // genuinely have no variants; warning would false-fire on every valid\n // single-variant embed). That stall is instead caught at runtime by\n // the embed's slow-render backstop (`slowRenderHint`), which fires only\n // when a render actually hangs — no false positives, and it covers every\n // silent-hang cause, not just this one.\n if (product?.options) {\n try {\n assertVariantSelected(product);\n } catch (err) {\n issues.push({\n severity: 'error',\n issue: 'variant-required',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const json = design.toJSON();\n const placement = json.activeArtboard;\n\n // The embed renders exactly ONE placement — the design's artboard. A\n // product that requires several can never complete through it: the canvas\n // mounts perfectly, then the server waits on the missing canvas_states until\n // the ~15s \"Timed out waiting for all placements\" error. Fully knowable at\n // mount from the catalog data already on the product, so say so now.\n const required = requiredPlacementLabels(product);\n if (required.length > 1) {\n issues.push({\n severity: 'error',\n issue: 'multi-placement',\n message:\n `product ${product.productId} requires placements ` +\n `[${required.join(', ')}] but this embed renders a single ` +\n `placement (\"${placement}\"). The render will time out waiting for the ` +\n 'others. This product needs the eject path — see ' +\n 'https://developers.snowcone.app/embed-mode#eject.',\n });\n }\n\n if (product?.placements?.length && !product.placements.includes(placement)) {\n issues.push({\n severity: 'error',\n issue: 'placement-mismatch',\n message:\n `the design's placement \"${placement}\" is not in ` +\n `product.placements [${product.placements.join(', ')}]. The canvas ` +\n 'artboard name and renderState placement must equal a real product ' +\n 'placement label, or the server renders a blank mockup. Fix the ' +\n '`name` passed to design({ name }).',\n });\n }\n\n const names = json.elements.map((el) => (el as { name?: string }).name).filter((n): n is string => Boolean(n));\n const dupes = names.filter((n, i) => names.indexOf(n) !== i);\n if (dupes.length) {\n issues.push({\n severity: 'warn',\n issue: 'duplicate-layer-names',\n message:\n `duplicate layer name(s) [${[...new Set(dupes)].join(', ')}] — ` +\n 'useTextBinding(name) / useImageBinding(name) bind to the FIRST match, ' +\n 'so a duplicate name makes a control edit the wrong layer. Keep names unique.',\n });\n }\n\n return issues;\n}\n\n/** Legacy advisory API: log everything, never throw. (`placement-mismatch`\n * keeps its historical `console.warn` level here; in `Editor.Root`'s throw\n * mode it is error-severity per F3.) */\nexport function validateEmbed(input: ValidateEmbedInput): void {\n for (const issue of collectEmbedIssues(input)) {\n const log =\n issue.severity === 'error' && issue.issue !== 'placement-mismatch' ? console.error : console.warn;\n log(`${TAG} ${issue.message}`);\n }\n}\n","/**\n * The ONE live design-state value under an `Editor.Root` (ADR-0085 §3 / T2).\n *\n * Today's turnkey flow is two stores, one-way, one-shot: the design seeds the\n * canvas once and edits never flow back, so the seed goes stale after the\n * first edit. This store fixes that by construction — seeded from the design\n * at Root mount, updated by every canvas change AND every TextField write,\n * last-write-wins. `Editor.Buy` (and `assertRenders`, P2) read THIS, never\n * the seed, so design staleness can't corrupt an order.\n *\n * TextField ─┐\n * ├─→ DesignStateStore ─→ pushRender ─→ session ─→ Preview(s)\n * Canvas ───┘\n *\n * (With a mounted Canvas the editor document is the write authority and this\n * store derives from its `onChange`; without one, this store IS the\n * authority. The routing lives in the parts — see EditorTextField.)\n *\n * Deliberately a tiny hand-rolled external store (subscribe + snapshot for\n * `useSyncExternalStore`) — narrow subscriptions without re-rendering the\n * whole Root tree per keystroke. Alternate state libraries were considered\n * and rejected (plan decision D3-C).\n */\n\nimport type { AnyElementConfig } from '../../types/index.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { layerKindOfConfig } from '../../design/design-builder.js';\n\n/** Editor-shape design state — the same shape `design.toJSON()` produces and\n * `<SnowconeCanvas onChange>` emits (and `serializeStateForServer` accepts). */\nexport interface DesignState {\n elements: AnyElementConfig[];\n artboards: Array<{\n name: string;\n width: number;\n height: number;\n backgroundColor?: string;\n exportBackground?: boolean;\n }>;\n activeArtboard: string;\n}\n\nfunction textOf(el: AnyElementConfig): string | undefined {\n return (el as { text?: string }).text;\n}\n\nfunction nameOf(el: AnyElementConfig): string | undefined {\n return (el as { name?: string }).name;\n}\n\nexport class DesignStateStore {\n private state: DesignState;\n /** Frozen snapshot of the values the design was seeded with — Buy's\n * \"differs from seed\" completeness rule (C3) compares against this. */\n private readonly seedTextByName: ReadonlyMap<string, string>;\n private readonly listeners = new Set<() => void>();\n\n constructor(seed: DesignState) {\n this.state = seed;\n const seedTexts = new Map<string, string>();\n for (const el of seed.elements) {\n const name = nameOf(el);\n const text = textOf(el);\n if (name && typeof text === 'string') seedTexts.set(name, text);\n }\n this.seedTextByName = seedTexts;\n }\n\n // Arrow on purpose: handed bare to `useSyncExternalStore` as the snapshot.\n getState = (): DesignState => {\n return this.state;\n };\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n /** Replace the whole state (the canvas `onChange` path). */\n setState(next: DesignState): void {\n this.state = next;\n this.emit();\n }\n\n /** The seed value of a named text layer (for completeness rule C3). */\n seedTextOf(name: string): string | undefined {\n return this.seedTextByName.get(name);\n }\n\n /** Current text of a named text layer, or undefined when absent. */\n textOf(name: string): string | undefined {\n const el = this.state.elements.find((e) => nameOf(e) === name);\n return el ? textOf(el) : undefined;\n }\n\n /** Kind of the named layer in the CURRENT state ('text' | 'image' | null\n * for unbindable), or undefined when no layer has the name. */\n layerKindOf(name: string): 'text' | 'image' | null | undefined {\n const el = this.state.elements.find((e) => nameOf(e) === name);\n return el ? layerKindOfConfig(el) : undefined;\n }\n\n /** Names of bindable layers in the current state, for error messages. */\n bindableLayerNames(): string[] {\n return this.state.elements\n .filter((e) => layerKindOfConfig(e) !== null)\n .map(nameOf)\n .filter((n): n is string => Boolean(n));\n }\n\n /**\n * Direct write path for `Editor.TextField` when NO canvas is mounted (with\n * one, writes route through the editor command path and arrive back here\n * via `setState`). Immutable update; last-write-wins.\n */\n updateTextLayer(name: string, text: string): void {\n let found = false;\n const elements = this.state.elements.map((el) => {\n if (nameOf(el) !== name) return el;\n found = true;\n return { ...el, text } as AnyElementConfig;\n });\n if (!found) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${name}\" in the current design state. Bindable layers: ` +\n `${JSON.stringify(this.bindableLayerNames())}.`,\n { layerName: name, validNames: this.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n this.setState({ ...this.state, elements });\n }\n\n /** ≥1 element with visible content (completeness rule C4): non-empty text,\n * an image with a URL, or a shape. Hidden elements don't count. */\n hasRenderableElement(): boolean {\n return this.state.elements.some((el) => {\n if ((el as { visible?: boolean }).visible === false) return false;\n const t = (el as { transformType?: string }).transformType;\n if (t === 'image') return Boolean((el as { imageUrl?: string }).imageUrl);\n if (t === 'shape') return true;\n if (t === 'group' || t === 'path') return true;\n const text = textOf(el);\n return typeof text === 'string' && text.trim().length > 0;\n });\n }\n\n private emit(): void {\n for (const l of [...this.listeners]) l();\n }\n}\n","'use client';\n\n/**\n * Internal plumbing every `Editor.*` part shares: the part registry, the\n * invariant/error reporting channel into Root's error state, and the\n * outside-Root guard.\n *\n * Registry mechanics (ADR-0085 §4): parts register in layout effects; React\n * runs parent effects after children, so `Editor.Root`'s own layout effect\n * sees the complete registry once per commit and is the single validation\n * point — no per-part polling, no false throws while the Canvas chunk\n * lazy-loads (registration is by the `Editor.Canvas` COMPONENT mount, not the\n * chunk's arrival). The registry exists for exactly three jobs: the\n * duplicate-Canvas throw, the TextField required-layer list for Buy, and\n * requires-canvas validation.\n */\n\nimport { createContext, useContext, useId, useLayoutEffect } from 'react';\nimport { EditorError, isDevOrTest } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport type { DesignStateStore } from './designStateStore.js';\n\n/** Imperative ops a mounted `Editor.Canvas` offers sibling parts. Routes\n * TextField writes through the editor command path (undo/redo, repaint) so\n * the editor document stays the single write authority while a canvas is\n * mounted (ADR-0085 §3). */\nexport interface CanvasBridge {\n /** Set a named text layer's content via editor commands. Returns false when\n * no live element carries the name. */\n setTextByName(name: string, text: string): boolean;\n}\n\nexport interface TextFieldRegistration {\n name: string;\n optional: boolean;\n}\n\nexport class EditorPartsRegistry {\n private canvasIds = new Set<string>();\n private requirements = new Map<string, string>(); // instanceId → part name\n private textFields = new Map<string, TextFieldRegistration>(); // instanceId → reg\n private bridge: CanvasBridge | null = null;\n private listeners = new Set<() => void>();\n private version = 0;\n\n /** Monotonic snapshot for `useSyncExternalStore`. */\n getVersion = (): number => this.version;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n registerCanvas(instanceId: string): () => void {\n // Registration only RECORDS — violations throw from `validate()`, which\n // Root runs render-side (a layout-effect throw is not reliably contained\n // by a boundary across React 18 + DOM test environments).\n this.canvasIds.add(instanceId);\n this.bump();\n return () => {\n this.canvasIds.delete(instanceId);\n this.bump();\n };\n }\n\n hasCanvas(): boolean {\n return this.canvasIds.size > 0;\n }\n\n /** Declare that a part is meaningless without a mounted Canvas (ADR-0085 §4\n * table). Validated by Root once per commit. */\n requireCanvas(instanceId: string, partName: string): () => void {\n this.requirements.set(instanceId, partName);\n this.bump();\n return () => {\n this.requirements.delete(instanceId);\n this.bump();\n };\n }\n\n /** Run by Root during RENDER, re-triggered by every registry change — by\n * then the whole commit's registrations are in, so there is no race\n * against the lazy chunk (ADR-0085 §4). Throws land in Root's boundary. */\n validate(): void {\n if (this.canvasIds.size > 1) {\n throw new EditorError(\n 'E_DUPLICATE_CANVAS',\n 'two <Editor.Canvas> parts are mounted under one <Editor.Root>. A Root owns ' +\n 'exactly one editable artboard — remove one Canvas, or mount a second ' +\n '<Editor.Root> for a second editor. (Multiple <Editor.Preview> parts ARE valid.)',\n { docSlug: 'embed-mode' },\n );\n }\n if (this.requirements.size > 0 && !this.hasCanvas()) {\n const parts = [...new Set(this.requirements.values())];\n throw new EditorError(\n 'E_REQUIRES_CANVAS',\n `${parts.join(', ')} require${parts.length === 1 ? 's' : ''} an <Editor.Canvas> under the same ` +\n '<Editor.Root> — they operate on the editable artboard (selection, editor ' +\n 'commands). Mount <Editor.Canvas/>, or remove the part. Canvas-free parts: ' +\n 'Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.',\n { parts, docSlug: 'embed-mode' },\n );\n }\n }\n\n registerTextField(instanceId: string, reg: TextFieldRegistration): () => void {\n this.textFields.set(instanceId, reg);\n this.bump();\n return () => {\n this.textFields.delete(instanceId);\n this.bump();\n };\n }\n\n /** Mounted TextField registrations — Buy's required-layer list (C2/C3).\n * Unmounted (incl. conditionally hidden) fields are absent by construction. */\n getTextFields(): TextFieldRegistration[] {\n return [...this.textFields.values()];\n }\n\n registerCanvasBridge(bridge: CanvasBridge): () => void {\n this.bridge = bridge;\n this.bump();\n return () => {\n if (this.bridge === bridge) this.bridge = null;\n this.bump();\n };\n }\n\n getCanvasBridge(): CanvasBridge | null {\n return this.bridge;\n }\n\n private bump(): void {\n this.version++;\n for (const l of [...this.listeners]) l();\n }\n}\n\nexport interface EditorRootInternals {\n /** The one live design state under this Root (ADR-0085 §3 / T2). */\n store: DesignStateStore;\n registry: EditorPartsRegistry;\n /**\n * Handler/async-time invariant channel (ADR-0085, D11 containment): React\n * error boundaries only catch render/lifecycle throws, so handlers report\n * here — throws in dev AND test (an agent's test must fail loud), routes to\n * Root's error state (same visible card) in prod.\n */\n reportInvariant(error: EditorError): void;\n /**\n * Runtime-failure channel (NOT a composition mistake — e.g. the lazy\n * renderer chunk failing to load): routes to Root's error card in every\n * env, with a retry affordance. Never throws.\n */\n reportRuntimeError(error: EditorError): void;\n}\n\nexport const EditorRootInternalsContext = createContext<EditorRootInternals | null>(null);\n\n/**\n * Read the Root internals. Throws `E_OUTSIDE_ROOT` (dev AND prod) when the\n * part is mounted outside `<Editor.Root>` — the most common wiring mistake.\n */\nexport function useEditorRootInternals(partName: string): EditorRootInternals {\n const ctx = useContext(EditorRootInternalsContext);\n if (!ctx) {\n throw new EditorError(\n 'E_OUTSIDE_ROOT',\n `<${partName}> must be rendered inside <Editor.Root>. Wrap it: ` +\n `<Editor.Root shop={…} product={…} design={…} grantUrl={…}><${partName}/></Editor.Root>`,\n { part: partName, docSlug: 'embed-mode' },\n );\n }\n return ctx;\n}\n\n/**\n * Declare that the calling part requires a mounted `Editor.Canvas` under the\n * same Root (ADR-0085 §4 — Controls/Add/History/Menu in P3; the throw is\n * `E_REQUIRES_CANVAS`, validated race-free by Root once per commit).\n */\nexport function useRequiresCanvas(partName: string): void {\n const internals = useEditorRootInternals(partName);\n const instanceId = useId();\n useLayoutEffect(\n () => internals.registry.requireCanvas(instanceId, partName),\n [internals.registry, instanceId, partName],\n );\n}\n\n/** Shared impl of the invariant channel. @internal */\nexport function makeInvariantReporter(routeToErrorState: (error: EditorError) => void): {\n reportInvariant: (error: EditorError) => void;\n reportRuntimeError: (error: EditorError) => void;\n} {\n return {\n reportInvariant(error: EditorError): void {\n if (isDevOrTest()) throw error;\n routeToErrorState(error);\n },\n reportRuntimeError(error: EditorError): void {\n // Containment is silent by design (the card is the signal) — except in\n // tests, where a contained error must be detectable: see\n // `expectNoEditorErrors()` in `@snowcone-app/canvas/testing`.\n recordContainedEditorError(error);\n routeToErrorState(error);\n },\n };\n}\n","'use client';\n\n/**\n * `<Editor.Root>` — the one provider boundary of the composable editor\n * primitives (ADR-0085). Owns the realtime {@link RenderSession}, the design,\n * the live mockups, the ONE design-state store, the part registry, and the\n * built-in error boundary. Parts (`Editor.Canvas/Preview/TextField/Buy/…`)\n * carry behavior + state subscription only; the HOST owns all layout.\n *\n * STATE MODEL (D9 — state always, renderer lazy):\n *\n * Editor.Root (one provider boundary · error boundary · applies .sc-root once)\n * │\n * ├── STATE — always mounted, renderer-free\n * │ └── EmbedContext design · product · render session · mockups ·\n * │ pushRender · stateStore (the ONE live design state)\n * │ (EditorProvider joins here in P1's inversion — until then the\n * │ editor document still mounts inside Editor.Canvas's chunk)\n * │\n * ├── <Editor.Canvas/> dynamic import ──→ [HEAVY RENDERER CHUNK]\n * ├── <Editor.Preview/> ←─ mockups (×N under one Root is VALID)\n * ├── <Editor.TextField/> ─→ stateStore (by layer token) ─→ pushRender\n * └── <Editor.Buy/> ←─ stateStore + required-TextField registry\n *\n * This file is the EXTRACTION of `<RealtimeEmbed>`'s internals (D5 — not a\n * copy): `RealtimeEmbed` is now `<EditorRoot>` plus the legacy advisory\n * validation mode, so the existing realtime tests exercise this Root.\n *\n * The legacy embed had no DOM of its own; Root must apply `.sc-root` once\n * (parts never self-apply, ADR-0085). `display: contents` squares the two —\n * the scope div generates no box, so host grid/flex layouts see the children\n * directly and the legacy wrapper stays layout-identical.\n */\n\nimport React, {\n Component,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n RenderSession,\n type RenderProduct,\n type RenderState,\n type MockupResult,\n type RealtimeGrant,\n} from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { CanvasServicesProvider, type CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { EmbedContext, type EmbedContextValue } from '../embed-realtime/context.js';\nimport { usePieceGuideBundle, pieceGuidesForArtboard } from '../embed-realtime/usePieceGuideBundle.js';\nimport { collectEmbedIssues, validateEmbed } from '../embed-realtime/validateEmbed.js';\nimport { EditorError, isEditorError } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport { DesignStateStore } from './designStateStore.js';\nimport {\n EditorPartsRegistry,\n EditorRootInternalsContext,\n makeInvariantReporter,\n type EditorRootInternals,\n} from './RootInternals.js';\n\n/**\n * How the session authorizes. Provide exactly one — the discriminated union makes\n * \"I forgot the grant\" a compile error rather than a silent runtime hang.\n *\n * Member order is load-bearing: when NEITHER prop is supplied (the common\n * mistake) TS reports the missing property of the LAST union member, so the\n * `grantUrl` arm is kept last on purpose — the error then reads \"Property\n * 'grantUrl' is missing\", pointing at the recommended prop instead of `grant`.\n * Don't reorder these.\n */\nexport type GrantSource =\n | {\n /** Full control over fetching the grant: a token or a token factory. */\n grant: RealtimeGrant | (() => Promise<RealtimeGrant>);\n grantUrl?: never;\n }\n | {\n /** Your endpoint returning `{ token, expiresAt }` for `POST { shop }` —\n * a same-origin proxy to `mintRealtimeGrant`. Recommended. */\n grantUrl: string;\n grant?: never;\n };\n\nexport type EditorRootBaseProps = {\n /** Publishable shop id (= shop.id, like a Stripe pk_). Billing target. */\n shop: string;\n /** Product to render against (catalog ids). `mockupIds` are scene codes\n * (product.mockups[].id), NOT placement names. Pass `placements`, `options`\n * + `requiredPlacements` so wiring mistakes (including a multi-placement\n * product, which the embed can't render) fail loud at mount instead of\n * hanging. */\n product: RenderProduct;\n /** Single source of truth — seeds the canvas AND the first render. Build it\n * with `design({ name, width, height })…`. Its artboard `name` is the\n * placement every render targets. */\n design: AnyDesign;\n /** Edit→render throttle in ms (default 200). */\n throttleMs?: number;\n /** Called whenever new mockups arrive. */\n onMockups?: (results: MockupResult[]) => void;\n /** Called on a render/timeout error. */\n onRenderError?: (message: string) => void;\n /** Override the realtime WS endpoint (defaults to the SDK's prod URL). */\n wsUrl?: string;\n /**\n * Privileged-service wiring for the editor chrome (the Image Browser's\n * stock-image search and AI generation tabs). Same pattern as `grantUrl`:\n * host these URLs on your server; your vendor keys live there.\n */\n services?: CanvasServices;\n children?: ReactNode;\n /**\n * Wiring-validation mode. `Editor.Root` defaults to `'throw'` (F3:\n * console.error is invisible to headless agents — error-severity wiring\n * issues throw `EditorError E_EMBED_CONFIG` into Root's boundary). The\n * legacy `<RealtimeEmbed>` wrapper passes `'warn'` for back-compat\n * (dev-only console diagnostics, never throws).\n * @internal\n */\n __validation?: 'throw' | 'warn';\n};\n\nexport type EditorRootProps = GrantSource & EditorRootBaseProps;\n\n/**\n * How long a render may be in flight before the embed assumes something is wrong\n * and surfaces a diagnostic. A healthy render returns in ~2s; the session's own\n * watchdog is ~30s. 8s sits in between — long enough not to false-fire on a\n * genuinely slow render, short enough to spare a first-timer the full 30s of\n * silence.\n */\nexport const SLOW_RENDER_HINT_MS = 8000;\n\n/**\n * The dev-console message shown when a render hasn't produced a mockup in\n * {@link SLOW_RENDER_HINT_MS}. A general backstop for the whole silent-hang\n * class — not just the missing-`variantId` trap — so a stuck embed always says\n * *something* actionable instead of hanging quietly.\n */\nexport function slowRenderHint(placement: string): string {\n return (\n `[RealtimeEmbed] No mockup after ${Math.round(SLOW_RENDER_HINT_MS / 1000)}s. ` +\n `Common causes: a variant product missing \\`variantId\\` (pass \\`product.options\\` ` +\n `so the embed can flag it up front), a multi-placement product (the server waits ` +\n `for every required placement but <RealtimeEmbed> sends only \"${placement}\" — pass ` +\n `\\`product.requiredPlacements\\` so this is flagged at mount; such products need ` +\n `the eject path), an unreachable or non-public asset URL in the design, or the ` +\n `placement \"${placement}\" not existing on the product. ` +\n `The render may still arrive — this is a heads-up, not a failure.`\n );\n}\n\nfunction toGetToken(props: EditorRootProps): { grantUrl: string } | { getToken: () => Promise<RealtimeGrant> } {\n if ('grantUrl' in props && props.grantUrl) {\n return { grantUrl: props.grantUrl };\n }\n const grant = (props as { grant: RealtimeGrant | (() => Promise<RealtimeGrant>) }).grant;\n if (typeof grant === 'function') return { getToken: grant };\n return { getToken: () => Promise.resolve(grant) };\n}\n\n// ── The error card (D11): contained, loud, in the widget slot ───────────────\n\nfunction ErrorCard({ error, onRetry }: { error: Error; onRetry?: () => void }): React.ReactElement {\n const code = isEditorError(error) ? error.code : 'EDITOR_ERROR';\n return (\n <div\n data-sc-part=\"error\"\n role=\"alert\"\n style={{\n padding: '16px',\n borderRadius: '12px',\n border: '1px solid var(--sc-color-destructive, #b91c1c)',\n background: 'var(--sc-color-surface, #fef2f2)',\n color: 'var(--sc-color-foreground, #7f1d1d)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '13px',\n lineHeight: 1.5,\n }}\n >\n <p style={{ margin: 0, fontWeight: 700 }}>Editor failed: {code}</p>\n <p style={{ margin: '4px 0 0' }}>{error.message}</p>\n {onRetry ? (\n <button\n type=\"button\"\n data-sc-part=\"error-retry\"\n onClick={onRetry}\n style={{\n marginTop: '10px',\n padding: '6px 14px',\n borderRadius: '9999px',\n border: '1px solid currentColor',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n ) : null}\n </div>\n );\n}\n\ninterface BoundaryProps {\n /** Imperatively-reported error (handler/async path) — same card. */\n reportedError: EditorError | null;\n onRetry: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n caught: Error | null;\n}\n\n/**\n * The catching half of Root's boundary (D11): render/lifecycle/effect throws\n * from the parts show an error card in the widget slot while the host page\n * survives.\n *\n * Test containment-bypass (the D11 review concern — \"an agent's mounts-\n * without-crashing test passes green on a broken composition\"): under\n * NODE_ENV=test/dev every contained error is RECORDED, and\n * `expectNoEditorErrors()` from `@snowcone-app/canvas/testing` fails the\n * test. (A literal rethrow-from-the-boundary was tried and rejected: an\n * uncaught throw from a layout effect corrupts React 18's work loop and\n * poisons every later render in the test file — \"Should not already be\n * working\".)\n */\nclass CatchingBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { caught: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { caught: error };\n }\n\n componentDidCatch(error: Error): void {\n recordContainedEditorError(error);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.error('[Editor.Root] contained a composition error:', error);\n }\n }\n\n render(): ReactNode {\n if (this.state.caught) {\n // Composition mistakes need a code change; a retry would just re-throw.\n return <ErrorCard error={this.state.caught} />;\n }\n return this.props.children;\n }\n}\n\n/**\n * Root's built-in boundary (D11): the imperatively-REPORTED channel\n * (handler/async failures like the lazy chunk failing to load) renders the\n * card directly, with retry when the failure is retryable; everything else\n * goes through the catching class boundary above.\n */\nfunction EditorBoundary({ reportedError, onRetry, children }: BoundaryProps): React.ReactElement {\n if (reportedError) {\n const retryable = isEditorError(reportedError) && reportedError.code === 'E_CHUNK_LOAD_FAILED';\n return <ErrorCard error={reportedError} onRetry={retryable ? onRetry : undefined} />;\n }\n return <CatchingBoundary reportedError={null} onRetry={onRetry}>{children}</CatchingBoundary>;\n}\n\n// ── The state-owning inner (everything here is INSIDE the boundary) ─────────\n\nfunction EditorRootInner(props: EditorRootProps & { internals: EditorRootInternals }): React.ReactElement {\n const {\n shop,\n product,\n design,\n throttleMs = 200,\n onMockups,\n onRenderError,\n wsUrl,\n services,\n children,\n internals,\n __validation = 'throw',\n } = props;\n\n const placement = useMemo(() => design.toJSON().activeArtboard, [design]);\n\n // #566: fetch the product's printable-area guides (camera cutouts, safe\n // areas) so the editor shows them automatically — without this, a buyer can\n // edit artwork that sits under hardware and the mockup never changes, with\n // no signal anywhere. variantId IS a gvid; fall back to the catalog's\n // default variant. Gated below on the design's artboard matching the\n // print-file frame the guides were authored in (same gate as snowcone.app).\n const guideBundle = usePieceGuideBundle(product.variantId ?? product.defaultGvid);\n const pieceGuides = useMemo(() => {\n if (!guideBundle) return null;\n const artboard = design.toJSON().artboards[0];\n return pieceGuidesForArtboard(guideBundle, artboard) ?? null;\n }, [guideBundle, design]);\n\n // Keep the latest callbacks reachable without re-creating the session.\n const onMockupsRef = useRef(onMockups);\n const onRenderErrorRef = useRef(onRenderError);\n onMockupsRef.current = onMockups;\n onRenderErrorRef.current = onRenderError;\n\n const [mockups, setMockups] = useState<MockupResult[]>([]);\n const [isRendering, setIsRendering] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const hasGrant = Boolean(('grantUrl' in props && props.grantUrl) || ('grant' in props && props.grant));\n\n // One session per (shop, product, placement, auth). Key it on the product's\n // identity-BEARING fields, not the object reference — so an embedder passing\n // an inline `product={{…}}` (the natural way to write it) doesn't rebuild the\n // session and reconnect on every render. A real change (different product,\n // mockups, or variant) still re-keys it. `options`/`placements` are advisory\n // (fail-fast validation) so they don't need to force a rebuild.\n const auth = toGetToken(props);\n const authKey = 'grantUrl' in auth ? auth.grantUrl : 'getToken';\n const productKey = `${product.productId}|${product.mockupIds.join(',')}|${product.variantId ?? ''}`;\n\n // Wiring validation. Editor.Root throws (F3 — fails loud into the boundary,\n // visible to headless agents); the legacy <RealtimeEmbed> wrapper keeps the\n // advisory dev-only console diagnostics. The ref-based dedup survives\n // StrictMode's deliberate unmount/remount cycle.\n const validationKey = `${shop}|${productKey}|${placement}|${hasGrant}`;\n // Render-time on purpose: in throw mode a wiring mistake must throw into\n // Root's boundary, not log (F3 — console.error is invisible to headless\n // agents). Memoized so it runs once per meaningful change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => {\n if (__validation !== 'throw') return;\n const issues = collectEmbedIssues({ shop, product, design, hasGrant });\n const fatal = issues.find((i) => i.severity === 'error');\n if (fatal) {\n throw new EditorError('E_EMBED_CONFIG', fatal.message, {\n issue: fatal.issue,\n docSlug: 'embed-mode',\n });\n }\n for (const issue of issues) {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(`[Editor.Root] ${issue.message}`);\n }\n }\n }, [validationKey, __validation]);\n const validatedKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (__validation !== 'warn') return;\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n if (validatedKeyRef.current === validationKey) return;\n validatedKeyRef.current = validationKey;\n validateEmbed({ shop, product, design, hasGrant });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [validationKey, __validation]);\n\n // RenderSession's constructor fail-fasts (e.g. a variant product with no\n // variantId) by THROWING. Catch it here so a config mistake surfaces through\n // `onRenderError` + the error state instead of throwing during render and\n // white-screening the whole host page.\n const sessionResult = useMemo<{ session: RenderSession } | { error: string }>(\n () => {\n try {\n return { session: new RenderSession({ shop, product, wsUrl, ...auth }) };\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [shop, productKey, placement, wsUrl, authKey]\n );\n const session = 'session' in sessionResult ? sessionResult.session : null;\n const constructError = 'error' in sessionResult ? sessionResult.error : null;\n\n const pushRender = useMemo(() => {\n return (state: RenderState, throttle = throttleMs) => {\n if (!session) return;\n setError(null);\n setIsRendering(true);\n void session.renderState(placement, state, throttle).catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n };\n }, [session, placement, throttleMs]);\n\n useEffect(() => {\n // Construction fail-fast (caught above) — surface it instead of rendering.\n if (constructError) {\n setError(constructError);\n setIsRendering(false);\n onRenderErrorRef.current?.(constructError);\n return;\n }\n if (!session) return;\n\n session.onMockups((results) => {\n setMockups(results);\n setIsRendering(false);\n onMockupsRef.current?.(results);\n });\n session.onError((message) => {\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n\n // Seed the first mockup from the design before any edit, so a freshly\n // mounted embed shows a real mockup immediately (no duplicate seed state —\n // the design is the single source).\n pushRender(design.toServerRequest());\n\n return () => session.close();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, constructError]);\n\n // Runtime silent-hang backstop. While a render is in flight, arm a timer; if no\n // mockup (or error) lands within SLOW_RENDER_HINT_MS, log an actionable hint.\n // Unlike the mount-time wiring guard this fires ONLY on an actual stall, so it\n // never nags a working embed — and it covers every silent-hang cause, not just\n // missing variantId. Dev-only (the `process` ref is typeof-guarded on the same\n // line); cleared the moment `isRendering` flips false.\n useEffect(() => {\n if (!isRendering) return;\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n const timer = setTimeout(() => console.warn(slowRenderHint(placement)), SLOW_RENDER_HINT_MS);\n return () => clearTimeout(timer);\n }, [isRendering, placement]);\n\n const value = useMemo<EmbedContextValue>(\n () => ({\n session,\n design,\n placement,\n product,\n mockups,\n isRendering,\n error,\n throttleMs,\n pieceGuides,\n pushRender,\n stateStore: internals.store,\n }),\n [session, design, placement, product, mockups, isRendering, error, throttleMs, pieceGuides, pushRender, internals.store]\n );\n\n // Single validation point for the part registry (ADR-0085 §4). Parts\n // register in their layout effects (so a whole commit's registrations\n // arrive together — no race against the lazy canvas chunk); each change\n // re-renders this component, and validation throws RENDER-side, where\n // Root's boundary reliably contains it (layout-effect throws are not\n // dependably boundary-caught across React 18 + DOM test environments).\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => internals.registry.validate(), [internals.registry, registryVersion]);\n\n const body = (\n <EditorRootInternalsContext.Provider value={internals}>\n <EmbedContext.Provider value={value}>{children}</EmbedContext.Provider>\n </EditorRootInternalsContext.Provider>\n );\n\n // Only mount a services provider when configured — `<Editor.Canvas>`'s\n // inner SnowconeCanvas inherits it through context.\n if (services) {\n return <CanvasServicesProvider services={services}>{body}</CanvasServicesProvider>;\n }\n return body;\n}\n\n/**\n * The root of an `Editor.*` composition. See the module doc for the state\n * model; see `RealtimeEmbed` for the legacy turnkey wrapper this was\n * extracted from.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorRoot(props: EditorRootProps): React.ReactElement {\n const { design } = props;\n\n // One store + registry per (design) — remounting with a new design reseeds.\n const internalsRef = useRef<{ design: AnyDesign; internals: Omit<EditorRootInternals, 'reportInvariant' | 'reportRuntimeError'> } | null>(null);\n const [reportedError, setReportedError] = useState<EditorError | null>(null);\n if (internalsRef.current === null || internalsRef.current.design !== design) {\n internalsRef.current = {\n design,\n internals: {\n store: new DesignStateStore(design.toJSON()),\n registry: new EditorPartsRegistry(),\n },\n };\n }\n\n const internals = useMemo<EditorRootInternals>(\n () => ({\n ...internalsRef.current!.internals,\n ...makeInvariantReporter(setReportedError),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [internalsRef.current.internals]\n );\n\n return (\n // `display: contents` — the .sc-root scope without a layout box, so the\n // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed\n // wrapper, which had no DOM at all, stays layout-identical).\n <div className=\"sc-root\" style={{ display: 'contents' }} data-sc-part=\"root\">\n <EditorBoundary reportedError={reportedError} onRetry={() => setReportedError(null)}>\n <EditorRootInner {...props} internals={internals} />\n </EditorBoundary>\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Canvas>` — the editable artboard, and the ONE lazy boundary of the\n * primitives (D9): all state mounts with `Editor.Root`; the heavy rendering\n * engine lives in {@link EditorCanvasImpl}'s chunk and loads only when this\n * part mounts. A no-canvas composition (Preview + TextField + Buy) never\n * fetches it — CI-asserted by the import-graph check.\n *\n * A failed chunk load (network/CDN) is a RUNTIME failure, not a composition\n * mistake: it routes to Root's error card with a retry affordance\n * (`E_CHUNK_LOAD_FAILED`) in every env. Retry clears the card, which remounts\n * this part and re-attempts the import.\n */\n\nimport React, { forwardRef, useEffect, useId, useLayoutEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals } from './RootInternals.js';\nimport type { EditorCanvasImplProps } from './EditorCanvasImpl.js';\nimport type { SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\n\ntype ImplComponent = (typeof import('./EditorCanvasImpl.js'))['EditorCanvasImpl'];\n\nlet implLoader: () => Promise<ImplComponent> = () =>\n import('./EditorCanvasImpl.js').then((m) => m.EditorCanvasImpl);\n\n/** Load the heavy impl chunk. Exposed for the legacy `<RealtimeCanvas>`\n * wrapper so both share ONE lazy boundary (one chunk). @internal */\nexport function loadCanvasImpl(): Promise<ImplComponent> {\n return implLoader();\n}\n\n/** Swap the chunk loader — TEST-ONLY seam for the chunk-load-failure → error\n * card → retry contract (a real `import()` can't be made to fail once and\n * then succeed under the module cache). Returns a restore function.\n * @internal */\nexport function __setCanvasImplLoaderForTests(loader: () => Promise<ImplComponent>): () => void {\n const previous = implLoader;\n implLoader = loader;\n return () => {\n implLoader = previous;\n };\n}\n\nexport interface EditorCanvasProps {\n /** Your overlay controls — rendered inside the editor context, so the\n * binding hooks (`useTextBinding` …) resolve against live elements. */\n children?: ReactNode;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The editable artboard. Mount at most one under a Root\n * (`E_DUPLICATE_CANVAS`); mount none for the no-canvas personalization\n * composition.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport const EditorCanvas = forwardRef<SnowconeCanvasHandle, EditorCanvasProps>(function EditorCanvas(\n { children, maxHeight, className, style }: EditorCanvasProps,\n ref,\n): React.ReactElement {\n const internals = useEditorRootInternals('Editor.Canvas');\n const instanceId = useId();\n\n // Registration is by THIS component's mount, not the chunk's arrival — so\n // duplicate detection and requires-canvas validation never race the lazy\n // load (ADR-0085 §4).\n useLayoutEffect(() => {\n return internals.registry.registerCanvas(instanceId);\n }, [internals.registry, instanceId]);\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's rendering chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [internals]);\n\n if (!Impl) {\n // Lightweight placeholder while the chunk loads — keeps the host layout\n // stable; themed via .sc-root tokens like every part.\n return (\n <div\n data-sc-part=\"canvas\"\n data-sc-state=\"loading\"\n className={className}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} kit=\"embed-only\" partAttr=\"canvas\" maxHeight={maxHeight} className={className} style={style}>\n {children}\n </Impl>\n );\n});\n\nexport type { EditorCanvasImplProps };\n","'use client';\n\n/**\n * `<Editor.Preview>` — the live product mockup (the buyable thing), extracted\n * from the legacy `<RealtimeMockup>` (which now wraps this).\n *\n * Reads the shared session's mockups from context and renders the rendered\n * image, updating as the shopper edits. Because every Preview shares one\n * session with the rest of the composition, it can never desync — and\n * MULTIPLE Previews under one Root are explicitly VALID (front/back; mockup\n * scenes via `mockupId`). Canvas-free by design: the no-canvas\n * personalization widget is Preview + TextField + Buy.\n */\n\nimport React, { useRef, type CSSProperties, type ReactNode, type SyntheticEvent } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\n\nexport interface EditorPreviewProps {\n /** Which mockup scene to show (a `product.mockupIds` entry). Defaults to the\n * first mockup that has rendered. */\n mockupId?: string;\n /** Shown before the first mockup arrives / while a render is in flight with no\n * prior image. Defaults to nothing. */\n fallback?: ReactNode;\n /** Alt text for the rendered image. */\n alt?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * How far the displayed device-pixel width may exceed the delivered mockup's\n * natural width before {@link resolutionMismatchHint} fires. Renders default to\n * 1000px wide, so a 1000px image inside a ~1100 device-px slot is fine (browser\n * downscale slack), but stretched across 2000 device px it looks soft and the\n * developer deserves to hear why.\n */\nexport const RESOLUTION_MISMATCH_RATIO = 1.2;\n\n/**\n * The render-width ladder a mismatch suggestion rounds UP to. Mirrors the\n * `product.width` guidance (\"bump to ~2000 for a crisp preview\") with sensible\n * steps — suggesting the exact device-px count would invite over-precise\n * configs that re-trigger on the next viewport.\n */\nconst SUGGESTED_WIDTHS = [1200, 1400, 1600, 1800, 2000, 2500, 3000, 4000] as const;\n\n/** Rounds a device-pixel width up to the next {@link SUGGESTED_WIDTHS} step\n * (capped at the top step). */\nexport function suggestRenderWidth(devicePx: number): number {\n for (const step of SUGGESTED_WIDTHS) {\n if (step >= devicePx) return step;\n }\n return SUGGESTED_WIDTHS[SUGGESTED_WIDTHS.length - 1];\n}\n\n/**\n * Builds the dev-console warning shown when a delivered mockup's natural width\n * is meaningfully below the width it's displayed at in DEVICE pixels (CSS width\n * × `devicePixelRatio`) — the \"my preview looks soft and nothing says why\"\n * trap: renders default to 1000px wide, which blurs on a large or high-density\n * display. Returns `null` when the resolution is adequate (within\n * {@link RESOLUTION_MISMATCH_RATIO}) or either measurement is unusable.\n */\nexport function resolutionMismatchHint(naturalWidth: number, devicePx: number): string | null {\n if (!(naturalWidth > 0) || !(devicePx > 0)) return null;\n if (devicePx <= naturalWidth * RESOLUTION_MISMATCH_RATIO) return null;\n const suggestion = suggestRenderWidth(devicePx);\n return (\n `[RealtimeMockup] mockup rendered at ${naturalWidth}px but displayed at ` +\n `~${devicePx} device px — the preview will look soft. Pass ` +\n `\\`product.width\\` (e.g. ${suggestion}) on the embed for a crisp preview.`\n );\n}\n\n/**\n * The live product mockup. Mount as many as you need under one Root.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorPreview({\n mockupId,\n fallback = null,\n alt = 'Live product mockup',\n className,\n style,\n}: EditorPreviewProps): React.ReactElement {\n const { mockups } = useEmbedContext();\n\n // Mockup ids already warned about this mount — re-renders and repeated loads\n // of the same scene stay quiet; a different scene gets its own one warning.\n const warnedMockupIdsRef = useRef<Set<string>>(new Set());\n\n const result = mockupId\n ? mockups.find((m) => m.mockupId === mockupId && m.imageUrl)\n : mockups.find((m) => m.imageUrl);\n\n if (!result?.imageUrl) {\n return <>{fallback}</>;\n }\n\n // Dev-only resolution check (the `process` reference is typeof-guarded on the\n // same line — non-Node bundlers don't define it). Runs on load because only a\n // decoded image knows its natural width; skips SSR (no `window`) and\n // unmeasurable (zero-width) elements.\n const handleLoad = (event: SyntheticEvent<HTMLImageElement>) => {\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n if (typeof window === 'undefined') return;\n if (warnedMockupIdsRef.current.has(result.mockupId)) return;\n const img = event.currentTarget;\n const cssWidth = img.getBoundingClientRect().width;\n if (cssWidth <= 0) return;\n const devicePx = Math.round(cssWidth * (window.devicePixelRatio || 1));\n const hint = resolutionMismatchHint(img.naturalWidth, devicePx);\n if (hint) {\n warnedMockupIdsRef.current.add(result.mockupId);\n console.warn(hint);\n }\n };\n\n return (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n data-sc-part=\"preview\"\n src={result.imageUrl}\n alt={alt}\n className={className}\n style={style}\n onLoad={handleLoad}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.TextField>` — a form input bound to a design text layer by TYPED\n * TOKEN (ADR-0085 §1 / T1). Canvas-free by design: in the no-canvas\n * personalization widget it writes the Root's design state directly and the\n * preview re-renders live; with a mounted `Editor.Canvas` the same writes\n * route through the editor command path (undo/redo, repaint) via the canvas\n * bridge — the editor document stays the single write authority (§3). The\n * routing is internal; the API is identical in both compositions.\n *\n * Contract (D10):\n * - `layer` accepts ONLY a `design.layer(\"name\")` token — a bare string\n * throws `E_LAYER_TOKEN_REQUIRED` (today's silent no-op binding became a\n * throw when entering `Editor.*`).\n * - Mount-time revalidation is the authority: the token's name is re-resolved\n * against the mounted Root's CURRENT design state — a token minted from a\n * different design throws `E_LAYER_NOT_FOUND` (dev AND prod).\n * - Mounted + non-`optional` ⇒ required for `Editor.Buy` completeness\n * (non-empty after trim AND differs from seed — C2/C3); unmounted (incl.\n * conditionally hidden) ⇒ not required. Registration lives in Root context.\n * - Reconciliation with canvas edits of the same layer is by construction:\n * one store, last-write-wins; this is a controlled input subscribed to the\n * store, so a canvas edit updates the field.\n */\n\nimport React, { useCallback, useId, useLayoutEffect, useRef, useSyncExternalStore, type CSSProperties } from 'react';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { isLayerToken, type LayerToken } from '../../design/design-builder.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\nexport interface EditorTextFieldProps {\n /** The text layer this input edits — mint with `design.layer(\"name\")`.\n * Type-checked against the design's TEXT-layer names when the design is\n * statically built; runtime-validated always. */\n layer: LayerToken<'text'>;\n /** Marked optional ⇒ Buy completeness does not require it (C2/C3). */\n optional?: boolean;\n placeholder?: string;\n /** Accessible label. Defaults to the layer name. */\n 'aria-label'?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A text input bound to a design layer. Works with or without a mounted\n * `Editor.Canvas`.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorTextField(props: EditorTextFieldProps): React.ReactElement {\n const { layer, optional = false, placeholder, className, style } = props;\n const internals = useEditorRootInternals('Editor.TextField');\n const { pushRender, throttleMs, stateStore } = useEmbedContext();\n const instanceId = useId();\n\n // ── Token + MOUNT-time revalidation (render-time on purpose: a bad layer\n // prop is a composition mistake → Root's boundary, dev AND prod). Validated\n // once per layer name, against the state AT MOUNT — later state churn (the\n // user emptying the canvas, teardown ordering) is user state, not a\n // composition mistake; the write path reports it if a write ever misses. ──\n const validatedNameRef = useRef<string | null>(null);\n if (!isLayerToken(layer)) {\n throw new EditorError(\n 'E_LAYER_TOKEN_REQUIRED',\n `the \\`layer\\` prop must be a token minted by the design — pass ` +\n `layer={design.layer(\"name\")}, not ${typeof layer === 'string' ? `the bare string \"${layer}\"` : 'a plain value'}. ` +\n `Tokens validate the name against the design's layers at mint time.`,\n { received: typeof layer === 'string' ? layer : typeof layer, docSlug: 'embed-mode' },\n );\n }\n if (validatedNameRef.current !== layer.name) {\n const kindNow = stateStore.layerKindOf(layer.name);\n if (kindNow === undefined) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${layer.name}\" in this Root's design — the token was minted from a ` +\n `different design than the one passed to <Editor.Root design={…}>. Bindable layers ` +\n `here: ${JSON.stringify(stateStore.bindableLayerNames())}.`,\n { layerName: layer.name, validNames: stateStore.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n if (kindNow !== 'text') {\n throw new EditorError(\n 'E_LAYER_WRONG_KIND',\n `layer \"${layer.name}\" is ${kindNow === null ? 'not a bindable kind' : `an ${kindNow} layer`} — ` +\n `<Editor.TextField> binds text layers only.`,\n { layerName: layer.name, actualKind: kindNow, docSlug: 'embed-mode' },\n );\n }\n validatedNameRef.current = layer.name;\n }\n\n // ── Required-layer registration for Buy completeness (C2/C3) ─────────────\n useLayoutEffect(() => {\n return internals.registry.registerTextField(instanceId, { name: layer.name, optional });\n }, [internals.registry, instanceId, layer.name, optional]);\n\n // ── Controlled value from the ONE store (a canvas edit updates the field) ─\n const value = useSyncExternalStore(\n stateStore.subscribe,\n () => stateStore.textOf(layer.name) ?? '',\n () => stateStore.textOf(layer.name) ?? '',\n );\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) {\n // Canvas mounted: the editor document is the write authority — route\n // through commands; the canvas onChange lands the new state back in\n // the store and pushes the render.\n if (!bridge.setTextByName(layer.name, next)) {\n internals.reportInvariant(\n new EditorError(\n 'E_LAYER_NOT_FOUND',\n `layer \"${layer.name}\" no longer exists in the mounted canvas — it was removed ` +\n `or renamed after this <Editor.TextField> bound to it. Bound layers must not be ` +\n `renamed or deleted while a field is mounted (ADR-0085 §3).`,\n { layerName: layer.name, docSlug: 'embed-mode' },\n ),\n );\n }\n return;\n }\n // No canvas: the store IS the authority. Trailing-edge throttle in the\n // session keeps the last keystroke always rendering.\n stateStore.updateTextLayer(layer.name, next);\n pushRender(serializeStateForServer(stateStore.getState()), throttleMs);\n },\n [internals, layer.name, stateStore, pushRender, throttleMs],\n );\n\n return (\n <input\n data-sc-part=\"textfield\"\n data-sc-layer={layer.name}\n type=\"text\"\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n aria-label={props['aria-label'] ?? layer.name}\n className={className}\n style={style}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.Buy>` — the SMART commerce part (ADR-0085 §2; plan decision: thin\n * callback-Buy was rejected). Owns quantity, design-completeness validation,\n * and cart-payload assembly; only the final submit is the host's callback —\n * their one line.\n *\n * Completeness rules (v1, C1–C5):\n * - C1 variant resolution — when the product has a COLOR axis (the one kind\n * of variant the renderer gates on), a valid `variantId` must be present\n * (the SDK's `assertVariantSelected`).\n * - C2 every MOUNTED non-`optional` `Editor.TextField` layer non-empty\n * after trim.\n * - C3 those layers must DIFFER from their seed value (F4 — placeholder\n * text like 'YOUR NAME' must not pass).\n * - C4 the design has ≥1 renderable element.\n * - C5 quantity is an integer ≥ 1.\n *\n * Incompleteness is USER state, not a composition error — the button renders\n * disabled with machine-readable `data-sc-buy-state` / `data-sc-buy-missing`\n * reason codes; it never throws. Throws are reserved for composition\n * violations (`E_BUY_NO_PRODUCT`, outside-Root).\n *\n * The payload is assembled from DESIGN STATE (the Root's live store — never\n * the seed, never rendered pixels), so render staleness cannot corrupt an\n * order; the preview is just preview (D10).\n */\n\nimport React, { useCallback, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactNode } from 'react';\nimport {\n assertVariantSelected,\n createCartDetail,\n type CartDetail,\n type RenderProduct,\n} from '@snowcone-app/sdk';\nimport { serializeStateForServer, type ServerRenderRequest } from '../../rendering/serialize-for-server.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport type { DesignState } from './designStateStore.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\n/** A structured incompleteness reason — also serialized (comma-joined) into\n * the button's `data-sc-buy-missing` attribute for agents and styling. */\nexport type BuyMissingReason =\n | 'variant'\n | `layer:${string}`\n | `layer-seed:${string}`\n | 'empty-design'\n | 'quantity';\n\nexport interface EditorBuyPayload {\n productId: string;\n variantId?: string;\n quantity: number;\n /** SDK cart detail (variant resolution + price) when the product carries\n * catalog `options`; `null` for option-less products. */\n cartDetail: CartDetail | null;\n /** The DESIGN STATE at click time (editor shape) — persist this; it is the\n * re-renderable source of truth for the purchased design. */\n designState: DesignState;\n /** The same state serialized for the server render path. */\n serverRequest: ServerRenderRequest;\n}\n\nexport interface EditorBuyProps {\n /** The final submit — the host's one line. Everything before it (variant,\n * quantity, completeness, payload assembly) is this part's job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /** Initial quantity (integer ≥ 1; default 1). */\n quantity?: number;\n /** Button label. Defaults to \"Add to cart\". */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/** Pure completeness evaluation — exported for tests. @internal */\nexport function evaluateBuyCompleteness(input: {\n product: RenderProduct;\n quantity: number;\n textFields: Array<{ name: string; optional: boolean }>;\n textOf: (name: string) => string | undefined;\n seedTextOf: (name: string) => string | undefined;\n hasRenderableElement: boolean;\n}): BuyMissingReason[] {\n const missing: BuyMissingReason[] = [];\n\n // C1 — color-axis variant resolution, via the SDK's existing gate (only\n // hex/color axes gate rendering; size-style axes render on the default).\n if (input.product.options) {\n try {\n assertVariantSelected(input.product);\n } catch {\n missing.push('variant');\n }\n }\n\n // C2 + C3 — mounted required TextField layers.\n for (const field of input.textFields) {\n if (field.optional) continue;\n const value = (input.textOf(field.name) ?? '').trim();\n if (value.length === 0) {\n missing.push(`layer:${field.name}`);\n continue;\n }\n const seed = (input.seedTextOf(field.name) ?? '').trim();\n if (seed.length > 0 && value === seed) {\n missing.push(`layer-seed:${field.name}`);\n }\n }\n\n // C4 — something to print.\n if (!input.hasRenderableElement) {\n missing.push('empty-design');\n }\n\n // C5 — sane quantity.\n if (!Number.isInteger(input.quantity) || input.quantity < 1) {\n missing.push('quantity');\n }\n\n return missing;\n}\n\n/** Map the embed product's catalog `options` onto the SDK cart helpers'\n * shapes. Derives the selection from the chosen variant's combination. */\nfunction buildCartDetail(product: RenderProduct, quantity: number): CartDetail | null {\n const options = product.options;\n const combinations = options?.combinations;\n if (!options || !combinations?.length) return null;\n\n const combination =\n combinations.find((c) => c.variantId && c.variantId === product.variantId) ?? combinations[0];\n if (!combination) return null;\n\n const selection: Record<string, string> = {};\n for (const [key, value] of Object.entries(combination)) {\n if (key === 'variantId' || key === 'price') continue;\n if (typeof value === 'string') selection[key] = value;\n else if (typeof value === 'number') selection[key] = String(value);\n }\n\n const attributes = Object.fromEntries(\n Object.keys(selection).map((key) => [\n key,\n { key, affectsCombinations: true, choices: [...new Set(combinations.map((c) => String(c[key] ?? '')))] },\n ]),\n );\n\n return createCartDetail({\n productId: product.productId,\n quantity,\n selection,\n combinations: combinations as Parameters<typeof createCartDetail>[0]['combinations'],\n attributes,\n });\n}\n\n/**\n * The add-to-cart button, completeness-gated and payload-assembling.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorBuy(props: EditorBuyProps): React.ReactElement {\n const { onAddToCart, quantity = 1, children, className, style } = props;\n const internals = useEditorRootInternals('Editor.Buy');\n const { product, stateStore } = useEmbedContext();\n\n // Composition violation — not user state: throw into Root's boundary.\n if (!product?.productId) {\n throw new EditorError(\n 'E_BUY_NO_PRODUCT',\n '<Editor.Buy> has no product context — pass `product` (with `productId`) on ' +\n '<Editor.Root product={…}>. Buy assembles its cart payload from the Root product ' +\n 'and the live design state.',\n { docSlug: 'embed-mode' },\n );\n }\n\n // Subscribe narrowly: design state + part registry (TextField mounts).\n const stateVersion = useSyncExternalStore(stateStore.subscribe, stateStore.getState, stateStore.getState);\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n\n const missing = useMemo(\n () =>\n evaluateBuyCompleteness({\n product,\n quantity,\n textFields: internals.registry.getTextFields(),\n textOf: (name) => stateStore.textOf(name),\n seedTextOf: (name) => stateStore.seedTextOf(name),\n hasRenderableElement: stateStore.hasRenderableElement(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [product, quantity, stateVersion, registryVersion],\n );\n const complete = missing.length === 0;\n\n // Double-click inert: the callback fires exactly once per click while\n // assembling/submitting (P2 test contract).\n const [busy, setBusy] = useState(false);\n const busyRef = useRef(false);\n\n const handleClick = useCallback(() => {\n if (busyRef.current || !complete) return;\n busyRef.current = true;\n setBusy(true);\n\n const designState = stateStore.getState();\n const payload: EditorBuyPayload = {\n productId: product.productId,\n ...(product.variantId ? { variantId: product.variantId } : {}),\n quantity,\n cartDetail: buildCartDetail(product, quantity),\n designState,\n serverRequest: serializeStateForServer(designState),\n };\n\n // Invoke synchronously (predictable for hosts and tests); only the\n // SETTLING of an async callback is awaited for the busy window.\n let result: void | Promise<void>;\n try {\n result = onAddToCart(payload);\n } catch (err) {\n busyRef.current = false;\n setBusy(false);\n throw err;\n }\n void Promise.resolve(result).finally(() => {\n busyRef.current = false;\n setBusy(false);\n });\n }, [complete, product, quantity, stateStore, onAddToCart]);\n\n return (\n <button\n type=\"button\"\n data-sc-part=\"buy\"\n data-sc-buy-state={busy ? 'busy' : complete ? 'ready' : 'incomplete'}\n data-sc-buy-missing={missing.join(',') || undefined}\n disabled={!complete || busy}\n aria-busy={busy || undefined}\n onClick={handleClick}\n className={className}\n style={style}\n >\n {children ?? 'Add to cart'}\n </button>\n );\n}\n","'use client';\n\n/**\n * `Editor.*` — composable editor primitives over one `Editor.Root`\n * (ADR-0085). Parts carry behavior + state subscription; the HOST owns all\n * layout (with the documented exception of the canvas's selection-anchored\n * overlays — anchoring contract, ADR-0085 §5).\n *\n * ```tsx\n * import { Editor, design } from '@snowcone-app/canvas/embed';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * // No-canvas personalization widget — the rendering engine never loads:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Preview />\n * <Editor.TextField layer={d.layer('headline')} placeholder=\"Your name\" />\n * <Editor.Buy onAddToCart={({ designState }) => persist(designState)} />\n * </Editor.Root>\n *\n * // Full editor — same surface, plus the lazy canvas:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Canvas />\n * <Editor.Preview />\n * <Editor.Buy onAddToCart={…} />\n * </Editor.Root>\n * ```\n *\n * All parts are `@experimental` until the P4 gate (the default editor rebuilt\n * from these public parts) passes — the API may change in minors until then.\n */\n\nimport { EditorRoot } from './EditorRoot.js';\nimport { EditorCanvas } from './EditorCanvas.js';\nimport { EditorPreview } from './EditorPreview.js';\nimport { EditorTextField } from './EditorTextField.js';\nimport { EditorBuy } from './EditorBuy.js';\n\nexport const Editor = {\n /** The one provider boundary — session, design, live state, error boundary. */\n Root: EditorRoot,\n /** The editable artboard (the ONE lazy renderer boundary — D9). */\n Canvas: EditorCanvas,\n /** Live product mockup. ×N under one Root is valid. */\n Preview: EditorPreview,\n /** Form input bound to a design text layer by typed token (T1). */\n TextField: EditorTextField,\n /** Smart commerce part: completeness + payload assembly; submit = host callback. */\n Buy: EditorBuy,\n} as const;\n\nexport type { EditorRootProps, EditorRootBaseProps, GrantSource } from './EditorRoot.js';\nexport type { EditorCanvasProps } from './EditorCanvas.js';\nexport type { EditorPreviewProps } from './EditorPreview.js';\nexport type { EditorTextFieldProps } from './EditorTextField.js';\nexport type { EditorBuyProps, EditorBuyPayload, BuyMissingReason } from './EditorBuy.js';\nexport type { DesignState } from './designStateStore.js';\nexport { DesignStateStore } from './designStateStore.js';\n","'use client';\n\n/**\n * `<RealtimeEmbed>` — the legacy turnkey wrapper around `<Editor.Root>`.\n *\n * Everything it used to own (the single RenderSession, the design seed, the\n * live mockups, the context) was EXTRACTED into `EditorRoot` (ADR-0085 / D5 —\n * extraction, not copy): this component is `<EditorRoot>` plus the legacy\n * advisory validation mode (dev-only `console.error` diagnostics instead of\n * `Editor.Root`'s throw-on-misconfiguration, F3). The existing realtime\n * surface — `<RealtimeCanvas>`, `<RealtimeMockup>`, `useRealtimeMockups` —\n * reads the same context `EditorRoot` provides, so nothing existing changes\n * meaning, and the existing realtime tests exercise the new Root.\n *\n * @example\n * ```tsx\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED for a product with a color/variant axis (BEEB77 has\n * // a Frame color) — omit it and the render hangs. Pass `options` too so a\n * // wrong/missing variantId fails fast instead of timing out. Read both from\n * // getProduct(productId) (its options.combinations[].variantId).\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>\n * <RealtimeCanvas /> {/* editor *\\/}\n * <RealtimeMockup /> {/* live preview *\\/}\n * </div>\n * </RealtimeEmbed>\n * ```\n */\n\nimport React from 'react';\nimport {\n EditorRoot,\n type EditorRootBaseProps,\n type EditorRootProps,\n type GrantSource,\n} from '../editor/EditorRoot.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport { SLOW_RENDER_HINT_MS, slowRenderHint } from '../editor/EditorRoot.js';\nexport type { GrantSource };\n\n// Omit only from the non-union half — Omit over the GrantSource union would\n// collapse the exactly-one-of grant/grantUrl discrimination.\nexport type RealtimeEmbedProps = GrantSource & Omit<EditorRootBaseProps, '__validation'>;\n\nexport function RealtimeEmbed(props: RealtimeEmbedProps): React.ReactElement {\n return <EditorRoot {...(props as EditorRootProps)} __validation=\"warn\" />;\n}\n","'use client';\n\n/**\n * `<RealtimeCanvas>` — the interactive editor half of a realtime embed\n * (legacy turnkey API; `Editor.Canvas` is the primitives-era equivalent).\n *\n * Mounts a `<SnowconeCanvas>` seeded from the embed's `design`, and forwards\n * every edit to the shared RenderSession as a server render. All the\n * load-bearing wiring an embedder used to copy by hand is internal: the\n * `sc-root` class, `inheritTheme`, edit→`serializeStateForServer`→\n * `renderState`, and the artboard/placement match.\n *\n * Since ADR-0085 (D9) the implementation lives in the shared lazy renderer\n * chunk ({@link EditorCanvasImpl}) behind a dynamic import — the embed\n * entry's static import graph stays renderer-free, so a no-canvas\n * composition never downloads the rendering engine. The canvas therefore\n * mounts one micro-beat after first paint (a chunk fetch on cold cache); the\n * forwarded ref attaches when it does.\n *\n * Defaults to the chrome-less `kit=\"embed-only\"` — bring your own controls as\n * `children` (they render as an overlay INSIDE the canvas's editor context, so\n * `useTextBinding(name)` / `useImageBinding(name)` resolve against the live\n * elements). For a full in-canvas editor pass `kit=\"compact-customizer\"` or\n * `kit=\"pro-studio\"`.\n *\n * Must be rendered inside `<RealtimeEmbed>` (or any `EmbedContext` provider).\n */\n\nimport React, { forwardRef, useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { loadCanvasImpl } from '../editor/EditorCanvas.js';\n\nexport interface RealtimeCanvasProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /**\n * Editor chrome to mount. The default `'embed-only'` is a chrome-less canvas —\n * the host supplies every control as `children` (text inputs, image swap)\n * through `useTextBinding` / `useImageBinding`. That's the right call for a\n * fill-in-the-blanks personalizer, but it gives the shopper NO way to select a\n * layer and change its font size, add an element, or reorder layers.\n *\n * To ship a real editor through the turnkey realtime path, pass a richer\n * preset — `'compact-customizer'` (a trimmed toolbar) or `'pro-studio'` (full\n * panels). Every edit still flows to the shared RenderSession as a\n * server render automatically; you get add-element / font-size / layers for\n * free without ejecting to a raw `SnowconeCanvas` + `RenderSession`.\n *\n * Pair a chrome'd kit with `children` only when your overlay adds to — not\n * duplicates — the kit's controls, or you'll get double chrome.\n *\n * @default 'embed-only'\n */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * Privileged-service wiring for the editor chrome (Image Browser search /\n * AI tabs). Usually set once on `<RealtimeEmbed services={…}>` and inherited;\n * pass it here only to override for this canvas. Host the URLs on your\n * server — your vendor keys live there.\n */\n services?: CanvasServices;\n /**\n * Observe the live design state. Fires with the full {@link CanvasState}\n * (elements stamped with their artboard name) whenever the canvas content\n * changes — including once after the initial seed loads — in addition to the\n * embed's internal edit→server-render flow, which is unaffected. This is the\n * state you persist at add-to-cart / checkout so the purchased design can be\n * re-rendered server-side later.\n *\n * Safe to pass inline: the underlying canvas reads the callback from a ref,\n * so a new identity each render never re-fires or loops.\n */\n onChange?: (state: CanvasState) => void;\n className?: string;\n style?: CSSProperties;\n}\n\ntype ImplComponent = Awaited<ReturnType<typeof loadCanvasImpl>>;\n\n/**\n * Note the export naming wart, kept for backwards compatibility:\n * - The ref handle's {@link SnowconeCanvasHandle.exportArtboards} resolves a\n * record keyed by artboard **name** (e.g. `'Front'`) — names match the\n * `placements` you configured on the embed.\n * - The lower-level `useExport().exportArtboard(id)` hook takes an artboard\n * **ID** (get one from `useArtboards()`).\n * For print-res exports at checkout, the ref handle is the intended path:\n * `ref.current.exportArtboards({ all: true, scale: 4, format: 'blob' })`.\n */\nexport const RealtimeCanvas = forwardRef<SnowconeCanvasHandle, RealtimeCanvasProps>(\n function RealtimeCanvas(props: RealtimeCanvasProps, ref): React.ReactElement {\n const { children, className, style, maxHeight, ...rest } = props;\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n // Legacy surface keeps the advisory console contract (no Root\n // boundary is guaranteed to exist here).\n console.error('[RealtimeCanvas] failed to load the rendering chunk:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, []);\n\n if (!Impl) {\n return (\n <div\n className={`sc-root${className ? ` ${className}` : ''}`}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} selfScope maxHeight={maxHeight} className={className} style={style} {...rest}>\n {children}\n </Impl>\n );\n },\n);\n","'use client';\n\n/**\n * `<RealtimeMockup>` — the live preview half of a realtime embed (legacy\n * turnkey API). The implementation was EXTRACTED to `Editor.Preview`\n * (ADR-0085 / D5); this wrapper keeps the original name and props. (The\n * rendered `<img>` now carries `data-sc-part=\"preview\"` — additive only.)\n *\n * Because it shares one session with the rest of the embed, the preview can\n * never desync from the editor and needs no wiring of its own. Place it\n * anywhere inside `<RealtimeEmbed>`.\n */\n\nimport React from 'react';\nimport { EditorPreview, type EditorPreviewProps } from '../editor/EditorPreview.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport {\n RESOLUTION_MISMATCH_RATIO,\n resolutionMismatchHint,\n suggestRenderWidth,\n} from '../editor/EditorPreview.js';\n\nexport type RealtimeMockupProps = EditorPreviewProps;\n\nexport function RealtimeMockup(props: RealtimeMockupProps): React.ReactElement {\n return <EditorPreview {...props} />;\n}\n","'use client';\n\nimport type { MockupResult } from '@snowcone-app/sdk';\nimport { useEmbedContext } from './context.js';\n\nexport interface UseRealtimeMockupsResult {\n /** All mockups from the latest render (one per requested mockupId). */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render/timeout error message, or null. */\n error: string | null;\n}\n\n/**\n * Read the live mockups for a custom preview UI. Reactive: re-renders when new\n * mockups arrive. Must be called inside `<RealtimeEmbed>`.\n *\n * For the common case (just show the rendered image) use `<RealtimeMockup>`\n * instead — this hook is for building your own gallery / loading treatment.\n */\nexport function useRealtimeMockups(): UseRealtimeMockupsResult {\n const { mockups, isRendering, error } = useEmbedContext();\n return { mockups, isRendering, error };\n}\n","/**\n * @snowcone-app/canvas/embed — Realtime embed primitives (Tier 2)\n *\n * The turnkey way to drop a live, server-rendered product editor into your app.\n * Three components that share one session so the editor and the preview can't\n * desync, plus the `design()` builder that seeds both:\n *\n * ```tsx\n * import { RealtimeEmbed, RealtimeCanvas, RealtimeMockup, design }\n * from '@snowcone-app/canvas/embed';\n * import '@snowcone-app/canvas/style.css';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED when the product has a color/variant axis (BEEB77\n * // does) — omit it and the render hangs. Read it + options from getProduct().\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <RealtimeCanvas />\n * <RealtimeMockup />\n * </RealtimeEmbed>\n * ```\n *\n * Everything an embed needs is REQUIRED on `<RealtimeEmbed>` — there's no\n * silently-optional prop to forget. For full manual control (your own session,\n * custom layout, multi-placement, color variants) drop to `<SnowconeCanvas>` +\n * `RenderSession` directly; see the docs' \"eject\" section.\n *\n * @packageDocumentation\n */\n\n// Register icons on module load (the editor + overlay controls use them).\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// === Editor.* composable primitives (ADR-0085) ===\n// @experimental until the P4 default-rebuilt-from-parts gate passes — the API\n// may change in minors. The turnkey Realtime* components below are stable.\nexport { Editor, DesignStateStore } from '../components/editor/index.js';\nexport type {\n EditorRootProps,\n EditorRootBaseProps,\n EditorCanvasProps,\n EditorPreviewProps,\n EditorTextFieldProps,\n EditorBuyProps,\n EditorBuyPayload,\n BuyMissingReason,\n DesignState,\n} from '../components/editor/index.js';\nexport { EditorError, isEditorError } from '../errors/editorError.js';\nexport type { EditorErrorCode, EditorErrorData } from '../errors/editorError.js';\n\n// === Embed primitives ===\nexport { RealtimeEmbed } from '../components/embed-realtime/RealtimeEmbed.js';\nexport type { RealtimeEmbedProps, GrantSource } from '../components/embed-realtime/RealtimeEmbed.js';\n\nexport { RealtimeCanvas } from '../components/embed-realtime/RealtimeCanvas.js';\nexport type { RealtimeCanvasProps } from '../components/embed-realtime/RealtimeCanvas.js';\n// `<RealtimeCanvas ref>` exposes the underlying canvas handle (print-res\n// `exportArtboards`, keyed by artboard NAME); `onChange` hands you the same\n// CanvasState shape — persist it at checkout, re-render it server-side later.\nexport type { SnowconeCanvasHandle, CanvasState } from '../components/embed/SnowconeCanvas.js';\n\nexport { RealtimeMockup } from '../components/embed-realtime/RealtimeMockup.js';\nexport type { RealtimeMockupProps } from '../components/embed-realtime/RealtimeMockup.js';\n\nexport { useRealtimeMockups } from '../components/embed-realtime/useRealtimeMockups.js';\nexport type { UseRealtimeMockupsResult } from '../components/embed-realtime/useRealtimeMockups.js';\n\nexport { validateEmbed, collectEmbedIssues } from '../components/embed-realtime/validateEmbed.js';\nexport type { ValidateEmbedInput, EmbedIssue } from '../components/embed-realtime/validateEmbed.js';\n\n// === Design builder — the single source of truth for an embed ===\nexport { design, DesignBuilder, isLayerToken } from '../design/design-builder.js';\nexport type {\n Anchor,\n ShapeKind,\n DesignArtboard,\n AnyDesign,\n LayerKind,\n LayerToken,\n} from '../design/design-builder.js';\n\n// === Chrome-building hooks (build your own editor chrome inside <RealtimeCanvas>) ===\n// These run inside the canvas's editor context — render the component that\n// calls them as `children` of <RealtimeCanvas> (the overlay slot). Same\n// exports as the stable entry, so chrome built against `@snowcone-app/canvas`\n// ports to the embed entry unchanged.\n\nexport { useEditor } from '../contexts/EditorContext.js';\nexport type { EditorContextValue, EditorProviderProps } from '../contexts/EditorContext.js';\n\nexport { useLayers } from '../hooks/useLayers.js';\nexport type { LayerInfo, UseLayersOptions, UseLayersReturn } from '../hooks/useLayers.js';\n\nexport { useCommands } from '../hooks/useCommands.js';\nexport type { UseCommandsReturn } from '../hooks/useCommands.js';\n\nexport { useArtboards } from '../hooks/useArtboards.js';\nexport type { ArtboardInfo, UseArtboardsReturn } from '../hooks/useArtboards.js';\n\n// NOTE the naming wart: `useExport().exportArtboard(id)` takes an artboard ID\n// (from `useArtboards()`), while the <RealtimeCanvas ref> handle's\n// `exportArtboards()` resolves a record keyed by artboard NAME.\nexport { useExport } from '../hooks/useExport.js';\nexport type { ExportProgress, ContinuousExportOptions, UseExportReturn } from '../hooks/useExport.js';\n\nexport { useSelectedElement } from '../hooks/useSelectedElement.js';\n\n// === State serialization (CanvasStateV1 — persist a design at checkout) ===\nexport { serializeState } from '../state/index.js';\nexport type {\n CanvasStateV1,\n SerializedArtboard,\n SerializedElement,\n} from '../state/index.js';\n\n// === Binding hooks (build your own controls inside <RealtimeCanvas>) ===\nexport { useTextBinding } from '../hooks/useTextBinding.js';\nexport { useImageBinding } from '../hooks/useImageBinding.js';\nexport { useColorBinding } from '../hooks/useColorBinding.js';\nexport type { ColorBindingResult } from '../hooks/useColorBinding.js';\nexport { useFontBinding } from '../hooks/useFontBinding.js';\nexport type { FontBindingResult } from '../hooks/useFontBinding.js';\nexport { useElementByName } from '../hooks/useElementByName.js';\n\n// === Editable templates (saved state + buyer-editable field manifest) ===\nexport {\n readTemplateFields,\n withTemplateFields,\n TEMPLATE_FIELDS_KEY,\n} from '../design/template-fields.js';\nexport type {\n TemplateField,\n TemplateTextField,\n TemplateImageField,\n TemplateColorField,\n TemplateSelectField,\n} from '../design/template-fields.js';\n\n// === Privileged services (Image Browser search / AI generation) ===\n// Same pattern as `grantUrl`: host the proxy routes on your server, your\n// vendor keys live there. Wire via `services` on <RealtimeEmbed>.\nexport { CanvasServicesProvider, useCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport type { CanvasServices, ResolvedCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport { createProxyImageSearch, createProxyGenerate } from '../services/imageSearch.js';\nexport type {\n ImageSearchProvider,\n ImageSearchResult,\n ImageSearchResponse,\n ImageSearchParams,\n GenerateProvider,\n GenerateParams,\n GenerateResponse,\n} from '../services/imageSearch.js';\n\n// === Re-exported SDK types embedders touch ===\nexport type {\n RenderProduct,\n RenderProductOptions,\n RenderProductCombination,\n RenderProductRequiredPlacement,\n MockupResult,\n RealtimeGrant,\n} from '@snowcone-app/sdk';\n"],"names":["EmbedContext","createContext","useEmbedContext","ctx","useContext","TAG","requiredPlacementLabels","product","_a","p","variantIds","_b","c","id","collectEmbedIssues","shop","design","hasGrant","issues","assertVariantSelected","err","json","placement","required","names","el","n","dupes","i","validateEmbed","input","issue","textOf","nameOf","DesignStateStore","seed","listener","seedTexts","name","text","next","e","layerKindOfConfig","found","elements","EditorError","t","l","EditorPartsRegistry","instanceId","partName","parts","reg","bridge","EditorRootInternalsContext","useEditorRootInternals","makeInvariantReporter","routeToErrorState","error","isDevOrTest","recordContainedEditorError","SLOW_RENDER_HINT_MS","slowRenderHint","toGetToken","props","grant","ErrorCard","onRetry","code","isEditorError","jsxs","jsx","CatchingBoundary","Component","process","EditorBoundary","reportedError","children","retryable","EditorRootInner","throttleMs","onMockups","onRenderError","wsUrl","services","internals","__validation","useMemo","guideBundle","usePieceGuideBundle","pieceGuides","artboard","pieceGuidesForArtboard","onMockupsRef","useRef","onRenderErrorRef","mockups","setMockups","useState","isRendering","setIsRendering","setError","auth","authKey","productKey","validationKey","fatal","validatedKeyRef","useEffect","sessionResult","RenderSession","session","constructError","pushRender","state","throttle","message","results","timer","value","registryVersion","useSyncExternalStore","body","CanvasServicesProvider","EditorRoot","internalsRef","setReportedError","implLoader","m","loadCanvasImpl","EditorCanvas","forwardRef","maxHeight","className","style","ref","useId","useLayoutEffect","Impl","setImpl","cancelled","component","RESOLUTION_MISMATCH_RATIO","SUGGESTED_WIDTHS","suggestRenderWidth","devicePx","step","resolutionMismatchHint","naturalWidth","suggestion","EditorPreview","mockupId","fallback","alt","warnedMockupIdsRef","result","handleLoad","event","img","cssWidth","hint","EditorTextField","layer","optional","placeholder","stateStore","validatedNameRef","isLayerToken","kindNow","handleChange","useCallback","serializeStateForServer","evaluateBuyCompleteness","missing","field","buildCartDetail","quantity","options","combinations","combination","selection","key","attributes","createCartDetail","EditorBuy","onAddToCart","stateVersion","complete","busy","setBusy","busyRef","handleClick","designState","payload","Editor","RealtimeEmbed","RealtimeCanvas","rest","RealtimeMockup","useRealtimeMockups","ensureIconsRegistered"],"mappings":"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"}
package/dist/embed.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { C as a, a as r, b as t, u as i, d as o, f as d, g as m } from "./UnifiedFontService-BAtqqkU4.js";
2
- import { D as u, a as l, R as E, b as c, c as g, d as p, e as x, v as f } from "./embed-Bdj4PKUA.js";
2
+ import { D as u, a as l, R as E, b as c, c as g, d as p, e as x, v as f } from "./embed-B5kewSQY.js";
3
3
  import { E as S, a as b } from "./editorError-DMENTZ-3.js";
4
4
  import { D as B, T as C, d as y, i as D, r as R, u as F, a as I, b as L, c as P, e as k, f as M, g as h, w } from "./template-fields-GOM4MNfq.js";
5
5
  import { u as _ } from "./EditorContext-CyanYzo2.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowcone-app/canvas",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Self-contained canvas editor component for e-commerce product customization",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -44,7 +44,10 @@
44
44
  "README.md"
45
45
  ],
46
46
  "sideEffects": [
47
- "**/*.css"
47
+ "**/*.css",
48
+ "./src/api/*.ts",
49
+ "./src/components/embed/index.ts",
50
+ "./dist/*.mjs"
48
51
  ],
49
52
  "publishConfig": {
50
53
  "access": "public"
@@ -104,7 +107,7 @@
104
107
  "react-colorful": "^5.6.1",
105
108
  "tailwind-merge": "^3.0.0",
106
109
  "tailwind-variants": "^3.1.1",
107
- "@snowcone-app/sdk": "0.12.1"
110
+ "@snowcone-app/sdk": "0.13.0"
108
111
  },
109
112
  "devDependencies": {
110
113
  "@axe-core/playwright": "^4.11.0",
@@ -166,7 +169,7 @@
166
169
  "vite-plugin-node-polyfills": "^0.24.0",
167
170
  "vitest": "^3.2.4",
168
171
  "zod": "^4.1.12",
169
- "@snowcone-app/ui": "0.2.2"
172
+ "@snowcone-app/ui": "0.2.3"
170
173
  },
171
174
  "scripts": {
172
175
  "dev": "vite",
@@ -1 +0,0 @@
1
- {"version":3,"file":"embed-Bdj4PKUA.js","sources":["../src/components/embed-realtime/context.ts","../src/components/embed-realtime/validateEmbed.ts","../src/components/editor/designStateStore.ts","../src/components/editor/RootInternals.ts","../src/components/editor/EditorRoot.tsx","../src/components/editor/EditorCanvas.tsx","../src/components/editor/EditorPreview.tsx","../src/components/editor/EditorTextField.tsx","../src/components/editor/EditorBuy.tsx","../src/components/editor/index.ts","../src/components/embed-realtime/RealtimeEmbed.tsx","../src/components/embed-realtime/RealtimeCanvas.tsx","../src/components/embed-realtime/RealtimeMockup.tsx","../src/components/embed-realtime/useRealtimeMockups.ts","../src/api/embed.ts"],"sourcesContent":["'use client';\n\n/**\n * Shared context for the realtime embed primitives. `<RealtimeEmbed>` owns the\n * single {@link RenderSession} and the live mockup state; `<RealtimeCanvas>` and\n * `<RealtimeMockup>` read it from here so the editor and the preview can be laid\n * out freely yet can never desync (they share one session, one design, one\n * placement).\n */\n\nimport { createContext, useContext } from 'react';\nimport type { RenderSession, RenderProduct, RenderState, MockupResult } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport type { PieceGuidesConfig } from '../embed/SnowconeCanvas.js';\nimport type { DesignStateStore } from '../editor/designStateStore.js';\n\nexport interface EmbedContextValue {\n /** The single session the editor pushes renders to. `null` if the session\n * failed to construct (a config fail-fast, surfaced via `error`). Escape\n * hatch for advanced use. */\n session: RenderSession | null;\n /** The design the embed was seeded with — single source of truth for both the\n * canvas seed and the seed render. */\n design: AnyDesign;\n /** The placement name (= the design's artboard name). Both the canvas artboard\n * and every `renderState` call use this; derived once so it can't drift. */\n placement: string;\n /** The product being rendered against. */\n product: RenderProduct;\n /** Latest mockups from the session. Reactive — updates re-render consumers. */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render error message, or null. */\n error: string | null;\n /** Default edit→render throttle (ms). */\n throttleMs: number;\n /**\n * The product's printable-area guides (dead zones, safe areas) — fetched by\n * `<RealtimeEmbed>` and already gated on the design's artboard matching the\n * print-file frame they were authored in. `null` when the product has none,\n * the fetch failed, or the dims don't line up. `<RealtimeCanvas>` forwards\n * this to the editor so embedders get the same overlay snowcone.app shows.\n */\n pieceGuides: PieceGuidesConfig | null;\n /** Dispatch a server render for the embed's placement. Sets `isRendering`. */\n pushRender: (state: RenderState, throttleMs?: number) => void;\n /**\n * The ONE live design state under this Root (ADR-0085 §3 / T2): seeded from\n * `design`, updated by every canvas change and every `Editor.TextField`\n * write, last-write-wins. Commerce parts read THIS, never the seed. Stable\n * identity; subscribe for updates (`useSyncExternalStore`-shaped).\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\n stateStore: DesignStateStore;\n}\n\nexport const EmbedContext = createContext<EmbedContextValue | undefined>(undefined);\n\n/**\n * Read the embed context. Throws a clear error when called outside\n * `<RealtimeEmbed>` — the most common wiring mistake.\n */\nexport function useEmbedContext(): EmbedContextValue {\n const ctx = useContext(EmbedContext);\n if (!ctx) {\n throw new Error(\n 'useRealtimeMockups / <RealtimeCanvas> / <RealtimeMockup> must be rendered ' +\n 'inside <RealtimeEmbed>. Wrap them: ' +\n '<RealtimeEmbed shop=… product=… design=… grantUrl=…>…</RealtimeEmbed>'\n );\n }\n return ctx;\n}\n","'use client';\n\n/**\n * Mount-time assertions for the realtime embed. Catches the silent-break wiring\n * mistakes that otherwise produce a blank canvas or a mockup that never renders:\n *\n * - no grant source (the session can't authorize → silent hang)\n * - a variant product with no `variantId` (→ ~30s render hang), AND the\n * can't-even-tell case: neither `variantId` nor `options` passed\n * - empty `mockupIds` (nothing to render)\n * - the design's placement isn't one of the product's placements (renderState\n * targets an artboard the product doesn't have → silent blank mockup)\n * - a multi-placement product (the embed renders ONE placement, so the server\n * waits on the rest and the render times out ~15s in — needs the eject path)\n * - duplicate layer names (binding hooks resolve to the wrong element)\n *\n * Two consumption modes (ADR-0085 / F3):\n * - `validateEmbed` — the legacy advisory API: logs `console.warn` /\n * `console.error` and never throws, so a partly-wired `<RealtimeEmbed>`\n * still mounts and renders what it can. Dev-only at the call site.\n * - `collectEmbedIssues` — the structured list; `Editor.Root` THROWS on the\n * error-severity issues (console.error is invisible to headless agents).\n */\n\nimport { assertVariantSelected, type RenderProduct } from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\n\nexport interface ValidateEmbedInput {\n shop: string;\n product: RenderProduct;\n design: AnyDesign;\n hasGrant: boolean;\n}\n\n/** One wiring problem found at mount. `error`-severity issues break the embed\n * (no render will ever arrive / it targets the wrong thing); `warn`-severity\n * issues are advisory. */\nexport interface EmbedIssue {\n severity: 'error' | 'warn';\n /** Stable issue key, carried into `EditorError.data.issue` in throw mode. */\n issue:\n | 'missing-shop'\n | 'missing-grant'\n | 'empty-mockup-ids'\n | 'variant-required'\n | 'multi-placement'\n | 'placement-mismatch'\n | 'duplicate-layer-names';\n message: string;\n}\n\nconst TAG = '[RealtimeEmbed]';\n\n/**\n * The placement labels this product demands a canvas_state for. Prefers the\n * catalog's `requiredPlacements` contract; variant-auto-filled (color)\n * placements don't count — `variantId` satisfies them (the missing-variantId\n * case has its own guard above). Falls back to the bare `placements` label\n * list ONLY when the product has no variant in play: a label list can't say\n * which entries are auto-filled colors, but without a variant none are.\n */\nfunction requiredPlacementLabels(product: RenderProduct): string[] {\n if (product?.requiredPlacements?.length) {\n return product.requiredPlacements.filter((p) => !p.autoFilledByVariant).map((p) => p.label);\n }\n const variantIds = new Set(\n (product?.options?.combinations ?? [])\n .map((c) => c.variantId)\n .filter((id): id is string => typeof id === 'string' && id !== '')\n );\n const hasVariantAxis = Boolean(product?.variantId) || variantIds.size > 1;\n return hasVariantAxis ? [] : (product?.placements ?? []);\n}\n\n/** Find every wiring problem. Pure — no logging, no throwing. */\nexport function collectEmbedIssues({ shop, product, design, hasGrant }: ValidateEmbedInput): EmbedIssue[] {\n const issues: EmbedIssue[] = [];\n\n if (!shop) {\n issues.push({\n severity: 'error',\n issue: 'missing-shop',\n message: '`shop` is required (your publishable shop id).',\n });\n }\n\n if (!hasGrant) {\n issues.push({\n severity: 'error',\n issue: 'missing-grant',\n message:\n 'no grant source — pass `grantUrl` (a proxy to mintRealtimeGrant) ' +\n 'or `grant`. Without it the session can never authorize and no mockup renders.',\n });\n }\n\n if (!product?.mockupIds?.length) {\n issues.push({\n severity: 'error',\n issue: 'empty-mockup-ids',\n message:\n 'product.mockupIds is empty — pass the catalog scene codes ' +\n '(product.mockups[].id) you want rendered, e.g. [\"FV1qjO\"].',\n });\n }\n\n // Variant axis: a product with a color/size option REQUIRES a variantId or the\n // render hangs ~30s waiting for a color blob that never comes. When `options`\n // (the catalog combinations) is passed we can detect the axis and fail fast\n // before the session's constructor throws. When `options` is NOT passed we\n // can't see the axis — so we DON'T warn here (a no-`options` product might\n // genuinely have no variants; warning would false-fire on every valid\n // single-variant embed). That stall is instead caught at runtime by\n // the embed's slow-render backstop (`slowRenderHint`), which fires only\n // when a render actually hangs — no false positives, and it covers every\n // silent-hang cause, not just this one.\n if (product?.options) {\n try {\n assertVariantSelected(product);\n } catch (err) {\n issues.push({\n severity: 'error',\n issue: 'variant-required',\n message: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n const json = design.toJSON();\n const placement = json.activeArtboard;\n\n // The embed renders exactly ONE placement — the design's artboard. A\n // product that requires several can never complete through it: the canvas\n // mounts perfectly, then the server waits on the missing canvas_states until\n // the ~15s \"Timed out waiting for all placements\" error. Fully knowable at\n // mount from the catalog data already on the product, so say so now.\n const required = requiredPlacementLabels(product);\n if (required.length > 1) {\n issues.push({\n severity: 'error',\n issue: 'multi-placement',\n message:\n `product ${product.productId} requires placements ` +\n `[${required.join(', ')}] but this embed renders a single ` +\n `placement (\"${placement}\"). The render will time out waiting for the ` +\n 'others. This product needs the eject path — see ' +\n 'https://developers.snowcone.app/embed-mode#eject.',\n });\n }\n\n if (product?.placements?.length && !product.placements.includes(placement)) {\n issues.push({\n severity: 'error',\n issue: 'placement-mismatch',\n message:\n `the design's placement \"${placement}\" is not in ` +\n `product.placements [${product.placements.join(', ')}]. The canvas ` +\n 'artboard name and renderState placement must equal a real product ' +\n 'placement label, or the server renders a blank mockup. Fix the ' +\n '`name` passed to design({ name }).',\n });\n }\n\n const names = json.elements.map((el) => (el as { name?: string }).name).filter((n): n is string => Boolean(n));\n const dupes = names.filter((n, i) => names.indexOf(n) !== i);\n if (dupes.length) {\n issues.push({\n severity: 'warn',\n issue: 'duplicate-layer-names',\n message:\n `duplicate layer name(s) [${[...new Set(dupes)].join(', ')}] — ` +\n 'useTextBinding(name) / useImageBinding(name) bind to the FIRST match, ' +\n 'so a duplicate name makes a control edit the wrong layer. Keep names unique.',\n });\n }\n\n return issues;\n}\n\n/** Legacy advisory API: log everything, never throw. (`placement-mismatch`\n * keeps its historical `console.warn` level here; in `Editor.Root`'s throw\n * mode it is error-severity per F3.) */\nexport function validateEmbed(input: ValidateEmbedInput): void {\n for (const issue of collectEmbedIssues(input)) {\n const log =\n issue.severity === 'error' && issue.issue !== 'placement-mismatch' ? console.error : console.warn;\n log(`${TAG} ${issue.message}`);\n }\n}\n","/**\n * The ONE live design-state value under an `Editor.Root` (ADR-0085 §3 / T2).\n *\n * Today's turnkey flow is two stores, one-way, one-shot: the design seeds the\n * canvas once and edits never flow back, so the seed goes stale after the\n * first edit. This store fixes that by construction — seeded from the design\n * at Root mount, updated by every canvas change AND every TextField write,\n * last-write-wins. `Editor.Buy` (and `assertRenders`, P2) read THIS, never\n * the seed, so design staleness can't corrupt an order.\n *\n * TextField ─┐\n * ├─→ DesignStateStore ─→ pushRender ─→ session ─→ Preview(s)\n * Canvas ───┘\n *\n * (With a mounted Canvas the editor document is the write authority and this\n * store derives from its `onChange`; without one, this store IS the\n * authority. The routing lives in the parts — see EditorTextField.)\n *\n * Deliberately a tiny hand-rolled external store (subscribe + snapshot for\n * `useSyncExternalStore`) — narrow subscriptions without re-rendering the\n * whole Root tree per keystroke. Alternate state libraries were considered\n * and rejected (plan decision D3-C).\n */\n\nimport type { AnyElementConfig } from '../../types/index.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { layerKindOfConfig } from '../../design/design-builder.js';\n\n/** Editor-shape design state — the same shape `design.toJSON()` produces and\n * `<SnowconeCanvas onChange>` emits (and `serializeStateForServer` accepts). */\nexport interface DesignState {\n elements: AnyElementConfig[];\n artboards: Array<{\n name: string;\n width: number;\n height: number;\n backgroundColor?: string;\n exportBackground?: boolean;\n }>;\n activeArtboard: string;\n}\n\nfunction textOf(el: AnyElementConfig): string | undefined {\n return (el as { text?: string }).text;\n}\n\nfunction nameOf(el: AnyElementConfig): string | undefined {\n return (el as { name?: string }).name;\n}\n\nexport class DesignStateStore {\n private state: DesignState;\n /** Frozen snapshot of the values the design was seeded with — Buy's\n * \"differs from seed\" completeness rule (C3) compares against this. */\n private readonly seedTextByName: ReadonlyMap<string, string>;\n private readonly listeners = new Set<() => void>();\n\n constructor(seed: DesignState) {\n this.state = seed;\n const seedTexts = new Map<string, string>();\n for (const el of seed.elements) {\n const name = nameOf(el);\n const text = textOf(el);\n if (name && typeof text === 'string') seedTexts.set(name, text);\n }\n this.seedTextByName = seedTexts;\n }\n\n // Arrow on purpose: handed bare to `useSyncExternalStore` as the snapshot.\n getState = (): DesignState => {\n return this.state;\n };\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n /** Replace the whole state (the canvas `onChange` path). */\n setState(next: DesignState): void {\n this.state = next;\n this.emit();\n }\n\n /** The seed value of a named text layer (for completeness rule C3). */\n seedTextOf(name: string): string | undefined {\n return this.seedTextByName.get(name);\n }\n\n /** Current text of a named text layer, or undefined when absent. */\n textOf(name: string): string | undefined {\n const el = this.state.elements.find((e) => nameOf(e) === name);\n return el ? textOf(el) : undefined;\n }\n\n /** Kind of the named layer in the CURRENT state ('text' | 'image' | null\n * for unbindable), or undefined when no layer has the name. */\n layerKindOf(name: string): 'text' | 'image' | null | undefined {\n const el = this.state.elements.find((e) => nameOf(e) === name);\n return el ? layerKindOfConfig(el) : undefined;\n }\n\n /** Names of bindable layers in the current state, for error messages. */\n bindableLayerNames(): string[] {\n return this.state.elements\n .filter((e) => layerKindOfConfig(e) !== null)\n .map(nameOf)\n .filter((n): n is string => Boolean(n));\n }\n\n /**\n * Direct write path for `Editor.TextField` when NO canvas is mounted (with\n * one, writes route through the editor command path and arrive back here\n * via `setState`). Immutable update; last-write-wins.\n */\n updateTextLayer(name: string, text: string): void {\n let found = false;\n const elements = this.state.elements.map((el) => {\n if (nameOf(el) !== name) return el;\n found = true;\n return { ...el, text } as AnyElementConfig;\n });\n if (!found) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${name}\" in the current design state. Bindable layers: ` +\n `${JSON.stringify(this.bindableLayerNames())}.`,\n { layerName: name, validNames: this.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n this.setState({ ...this.state, elements });\n }\n\n /** ≥1 element with visible content (completeness rule C4): non-empty text,\n * an image with a URL, or a shape. */\n hasRenderableElement(): boolean {\n return this.state.elements.some((el) => {\n const t = (el as { transformType?: string }).transformType;\n if (t === 'image') return Boolean((el as { imageUrl?: string }).imageUrl);\n if (t === 'shape') return true;\n if (t === 'group' || t === 'path') return true;\n const text = textOf(el);\n return typeof text === 'string' && text.trim().length > 0;\n });\n }\n\n private emit(): void {\n for (const l of [...this.listeners]) l();\n }\n}\n","'use client';\n\n/**\n * Internal plumbing every `Editor.*` part shares: the part registry, the\n * invariant/error reporting channel into Root's error state, and the\n * outside-Root guard.\n *\n * Registry mechanics (ADR-0085 §4): parts register in layout effects; React\n * runs parent effects after children, so `Editor.Root`'s own layout effect\n * sees the complete registry once per commit and is the single validation\n * point — no per-part polling, no false throws while the Canvas chunk\n * lazy-loads (registration is by the `Editor.Canvas` COMPONENT mount, not the\n * chunk's arrival). The registry exists for exactly three jobs: the\n * duplicate-Canvas throw, the TextField required-layer list for Buy, and\n * requires-canvas validation.\n */\n\nimport { createContext, useContext, useId, useLayoutEffect } from 'react';\nimport { EditorError, isDevOrTest } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport type { DesignStateStore } from './designStateStore.js';\n\n/** Imperative ops a mounted `Editor.Canvas` offers sibling parts. Routes\n * TextField writes through the editor command path (undo/redo, repaint) so\n * the editor document stays the single write authority while a canvas is\n * mounted (ADR-0085 §3). */\nexport interface CanvasBridge {\n /** Set a named text layer's content via editor commands. Returns false when\n * no live element carries the name. */\n setTextByName(name: string, text: string): boolean;\n}\n\nexport interface TextFieldRegistration {\n name: string;\n optional: boolean;\n}\n\nexport class EditorPartsRegistry {\n private canvasIds = new Set<string>();\n private requirements = new Map<string, string>(); // instanceId → part name\n private textFields = new Map<string, TextFieldRegistration>(); // instanceId → reg\n private bridge: CanvasBridge | null = null;\n private listeners = new Set<() => void>();\n private version = 0;\n\n /** Monotonic snapshot for `useSyncExternalStore`. */\n getVersion = (): number => this.version;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n };\n\n registerCanvas(instanceId: string): () => void {\n // Registration only RECORDS — violations throw from `validate()`, which\n // Root runs render-side (a layout-effect throw is not reliably contained\n // by a boundary across React 18 + DOM test environments).\n this.canvasIds.add(instanceId);\n this.bump();\n return () => {\n this.canvasIds.delete(instanceId);\n this.bump();\n };\n }\n\n hasCanvas(): boolean {\n return this.canvasIds.size > 0;\n }\n\n /** Declare that a part is meaningless without a mounted Canvas (ADR-0085 §4\n * table). Validated by Root once per commit. */\n requireCanvas(instanceId: string, partName: string): () => void {\n this.requirements.set(instanceId, partName);\n this.bump();\n return () => {\n this.requirements.delete(instanceId);\n this.bump();\n };\n }\n\n /** Run by Root during RENDER, re-triggered by every registry change — by\n * then the whole commit's registrations are in, so there is no race\n * against the lazy chunk (ADR-0085 §4). Throws land in Root's boundary. */\n validate(): void {\n if (this.canvasIds.size > 1) {\n throw new EditorError(\n 'E_DUPLICATE_CANVAS',\n 'two <Editor.Canvas> parts are mounted under one <Editor.Root>. A Root owns ' +\n 'exactly one editable artboard — remove one Canvas, or mount a second ' +\n '<Editor.Root> for a second editor. (Multiple <Editor.Preview> parts ARE valid.)',\n { docSlug: 'embed-mode' },\n );\n }\n if (this.requirements.size > 0 && !this.hasCanvas()) {\n const parts = [...new Set(this.requirements.values())];\n throw new EditorError(\n 'E_REQUIRES_CANVAS',\n `${parts.join(', ')} require${parts.length === 1 ? 's' : ''} an <Editor.Canvas> under the same ` +\n '<Editor.Root> — they operate on the editable artboard (selection, editor ' +\n 'commands). Mount <Editor.Canvas/>, or remove the part. Canvas-free parts: ' +\n 'Editor.Preview, Editor.Buy, Editor.TextField, Editor.Layers.',\n { parts, docSlug: 'embed-mode' },\n );\n }\n }\n\n registerTextField(instanceId: string, reg: TextFieldRegistration): () => void {\n this.textFields.set(instanceId, reg);\n this.bump();\n return () => {\n this.textFields.delete(instanceId);\n this.bump();\n };\n }\n\n /** Mounted TextField registrations — Buy's required-layer list (C2/C3).\n * Unmounted (incl. conditionally hidden) fields are absent by construction. */\n getTextFields(): TextFieldRegistration[] {\n return [...this.textFields.values()];\n }\n\n registerCanvasBridge(bridge: CanvasBridge): () => void {\n this.bridge = bridge;\n this.bump();\n return () => {\n if (this.bridge === bridge) this.bridge = null;\n this.bump();\n };\n }\n\n getCanvasBridge(): CanvasBridge | null {\n return this.bridge;\n }\n\n private bump(): void {\n this.version++;\n for (const l of [...this.listeners]) l();\n }\n}\n\nexport interface EditorRootInternals {\n /** The one live design state under this Root (ADR-0085 §3 / T2). */\n store: DesignStateStore;\n registry: EditorPartsRegistry;\n /**\n * Handler/async-time invariant channel (ADR-0085, D11 containment): React\n * error boundaries only catch render/lifecycle throws, so handlers report\n * here — throws in dev AND test (an agent's test must fail loud), routes to\n * Root's error state (same visible card) in prod.\n */\n reportInvariant(error: EditorError): void;\n /**\n * Runtime-failure channel (NOT a composition mistake — e.g. the lazy\n * renderer chunk failing to load): routes to Root's error card in every\n * env, with a retry affordance. Never throws.\n */\n reportRuntimeError(error: EditorError): void;\n}\n\nexport const EditorRootInternalsContext = createContext<EditorRootInternals | null>(null);\n\n/**\n * Read the Root internals. Throws `E_OUTSIDE_ROOT` (dev AND prod) when the\n * part is mounted outside `<Editor.Root>` — the most common wiring mistake.\n */\nexport function useEditorRootInternals(partName: string): EditorRootInternals {\n const ctx = useContext(EditorRootInternalsContext);\n if (!ctx) {\n throw new EditorError(\n 'E_OUTSIDE_ROOT',\n `<${partName}> must be rendered inside <Editor.Root>. Wrap it: ` +\n `<Editor.Root shop={…} product={…} design={…} grantUrl={…}><${partName}/></Editor.Root>`,\n { part: partName, docSlug: 'embed-mode' },\n );\n }\n return ctx;\n}\n\n/**\n * Declare that the calling part requires a mounted `Editor.Canvas` under the\n * same Root (ADR-0085 §4 — Controls/Add/History/Menu in P3; the throw is\n * `E_REQUIRES_CANVAS`, validated race-free by Root once per commit).\n */\nexport function useRequiresCanvas(partName: string): void {\n const internals = useEditorRootInternals(partName);\n const instanceId = useId();\n useLayoutEffect(\n () => internals.registry.requireCanvas(instanceId, partName),\n [internals.registry, instanceId, partName],\n );\n}\n\n/** Shared impl of the invariant channel. @internal */\nexport function makeInvariantReporter(routeToErrorState: (error: EditorError) => void): {\n reportInvariant: (error: EditorError) => void;\n reportRuntimeError: (error: EditorError) => void;\n} {\n return {\n reportInvariant(error: EditorError): void {\n if (isDevOrTest()) throw error;\n routeToErrorState(error);\n },\n reportRuntimeError(error: EditorError): void {\n // Containment is silent by design (the card is the signal) — except in\n // tests, where a contained error must be detectable: see\n // `expectNoEditorErrors()` in `@snowcone-app/canvas/testing`.\n recordContainedEditorError(error);\n routeToErrorState(error);\n },\n };\n}\n","'use client';\n\n/**\n * `<Editor.Root>` — the one provider boundary of the composable editor\n * primitives (ADR-0085). Owns the realtime {@link RenderSession}, the design,\n * the live mockups, the ONE design-state store, the part registry, and the\n * built-in error boundary. Parts (`Editor.Canvas/Preview/TextField/Buy/…`)\n * carry behavior + state subscription only; the HOST owns all layout.\n *\n * STATE MODEL (D9 — state always, renderer lazy):\n *\n * Editor.Root (one provider boundary · error boundary · applies .sc-root once)\n * │\n * ├── STATE — always mounted, renderer-free\n * │ └── EmbedContext design · product · render session · mockups ·\n * │ pushRender · stateStore (the ONE live design state)\n * │ (EditorProvider joins here in P1's inversion — until then the\n * │ editor document still mounts inside Editor.Canvas's chunk)\n * │\n * ├── <Editor.Canvas/> dynamic import ──→ [HEAVY RENDERER CHUNK]\n * ├── <Editor.Preview/> ←─ mockups (×N under one Root is VALID)\n * ├── <Editor.TextField/> ─→ stateStore (by layer token) ─→ pushRender\n * └── <Editor.Buy/> ←─ stateStore + required-TextField registry\n *\n * This file is the EXTRACTION of `<RealtimeEmbed>`'s internals (D5 — not a\n * copy): `RealtimeEmbed` is now `<EditorRoot>` plus the legacy advisory\n * validation mode, so the existing realtime tests exercise this Root.\n *\n * The legacy embed had no DOM of its own; Root must apply `.sc-root` once\n * (parts never self-apply, ADR-0085). `display: contents` squares the two —\n * the scope div generates no box, so host grid/flex layouts see the children\n * directly and the legacy wrapper stays layout-identical.\n */\n\nimport React, {\n Component,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport {\n RenderSession,\n type RenderProduct,\n type RenderState,\n type MockupResult,\n type RealtimeGrant,\n} from '@snowcone-app/sdk';\nimport type { AnyDesign } from '../../design/design-builder.js';\nimport { CanvasServicesProvider, type CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { EmbedContext, type EmbedContextValue } from '../embed-realtime/context.js';\nimport { usePieceGuideBundle, pieceGuidesForArtboard } from '../embed-realtime/usePieceGuideBundle.js';\nimport { collectEmbedIssues, validateEmbed } from '../embed-realtime/validateEmbed.js';\nimport { EditorError, isEditorError } from '../../errors/editorError.js';\nimport { recordContainedEditorError } from '../../testing/editorErrors.js';\nimport { DesignStateStore } from './designStateStore.js';\nimport {\n EditorPartsRegistry,\n EditorRootInternalsContext,\n makeInvariantReporter,\n type EditorRootInternals,\n} from './RootInternals.js';\n\n/**\n * How the session authorizes. Provide exactly one — the discriminated union makes\n * \"I forgot the grant\" a compile error rather than a silent runtime hang.\n *\n * Member order is load-bearing: when NEITHER prop is supplied (the common\n * mistake) TS reports the missing property of the LAST union member, so the\n * `grantUrl` arm is kept last on purpose — the error then reads \"Property\n * 'grantUrl' is missing\", pointing at the recommended prop instead of `grant`.\n * Don't reorder these.\n */\nexport type GrantSource =\n | {\n /** Full control over fetching the grant: a token or a token factory. */\n grant: RealtimeGrant | (() => Promise<RealtimeGrant>);\n grantUrl?: never;\n }\n | {\n /** Your endpoint returning `{ token, expiresAt }` for `POST { shop }` —\n * a same-origin proxy to `mintRealtimeGrant`. Recommended. */\n grantUrl: string;\n grant?: never;\n };\n\nexport type EditorRootBaseProps = {\n /** Publishable shop id (= shop.id, like a Stripe pk_). Billing target. */\n shop: string;\n /** Product to render against (catalog ids). `mockupIds` are scene codes\n * (product.mockups[].id), NOT placement names. Pass `placements`, `options`\n * + `requiredPlacements` so wiring mistakes (including a multi-placement\n * product, which the embed can't render) fail loud at mount instead of\n * hanging. */\n product: RenderProduct;\n /** Single source of truth — seeds the canvas AND the first render. Build it\n * with `design({ name, width, height })…`. Its artboard `name` is the\n * placement every render targets. */\n design: AnyDesign;\n /** Edit→render throttle in ms (default 200). */\n throttleMs?: number;\n /** Called whenever new mockups arrive. */\n onMockups?: (results: MockupResult[]) => void;\n /** Called on a render/timeout error. */\n onRenderError?: (message: string) => void;\n /** Override the realtime WS endpoint (defaults to the SDK's prod URL). */\n wsUrl?: string;\n /**\n * Privileged-service wiring for the editor chrome (the Image Browser's\n * stock-image search and AI generation tabs). Same pattern as `grantUrl`:\n * host these URLs on your server; your vendor keys live there.\n */\n services?: CanvasServices;\n children?: ReactNode;\n /**\n * Wiring-validation mode. `Editor.Root` defaults to `'throw'` (F3:\n * console.error is invisible to headless agents — error-severity wiring\n * issues throw `EditorError E_EMBED_CONFIG` into Root's boundary). The\n * legacy `<RealtimeEmbed>` wrapper passes `'warn'` for back-compat\n * (dev-only console diagnostics, never throws).\n * @internal\n */\n __validation?: 'throw' | 'warn';\n};\n\nexport type EditorRootProps = GrantSource & EditorRootBaseProps;\n\n/**\n * How long a render may be in flight before the embed assumes something is wrong\n * and surfaces a diagnostic. A healthy render returns in ~2s; the session's own\n * watchdog is ~30s. 8s sits in between — long enough not to false-fire on a\n * genuinely slow render, short enough to spare a first-timer the full 30s of\n * silence.\n */\nexport const SLOW_RENDER_HINT_MS = 8000;\n\n/**\n * The dev-console message shown when a render hasn't produced a mockup in\n * {@link SLOW_RENDER_HINT_MS}. A general backstop for the whole silent-hang\n * class — not just the missing-`variantId` trap — so a stuck embed always says\n * *something* actionable instead of hanging quietly.\n */\nexport function slowRenderHint(placement: string): string {\n return (\n `[RealtimeEmbed] No mockup after ${Math.round(SLOW_RENDER_HINT_MS / 1000)}s. ` +\n `Common causes: a variant product missing \\`variantId\\` (pass \\`product.options\\` ` +\n `so the embed can flag it up front), a multi-placement product (the server waits ` +\n `for every required placement but <RealtimeEmbed> sends only \"${placement}\" — pass ` +\n `\\`product.requiredPlacements\\` so this is flagged at mount; such products need ` +\n `the eject path), an unreachable or non-public asset URL in the design, or the ` +\n `placement \"${placement}\" not existing on the product. ` +\n `The render may still arrive — this is a heads-up, not a failure.`\n );\n}\n\nfunction toGetToken(props: EditorRootProps): { grantUrl: string } | { getToken: () => Promise<RealtimeGrant> } {\n if ('grantUrl' in props && props.grantUrl) {\n return { grantUrl: props.grantUrl };\n }\n const grant = (props as { grant: RealtimeGrant | (() => Promise<RealtimeGrant>) }).grant;\n if (typeof grant === 'function') return { getToken: grant };\n return { getToken: () => Promise.resolve(grant) };\n}\n\n// ── The error card (D11): contained, loud, in the widget slot ───────────────\n\nfunction ErrorCard({ error, onRetry }: { error: Error; onRetry?: () => void }): React.ReactElement {\n const code = isEditorError(error) ? error.code : 'EDITOR_ERROR';\n return (\n <div\n data-sc-part=\"error\"\n role=\"alert\"\n style={{\n padding: '16px',\n borderRadius: '12px',\n border: '1px solid var(--sc-color-destructive, #b91c1c)',\n background: 'var(--sc-color-surface, #fef2f2)',\n color: 'var(--sc-color-foreground, #7f1d1d)',\n fontFamily: 'ui-sans-serif, system-ui, sans-serif',\n fontSize: '13px',\n lineHeight: 1.5,\n }}\n >\n <p style={{ margin: 0, fontWeight: 700 }}>Editor failed: {code}</p>\n <p style={{ margin: '4px 0 0' }}>{error.message}</p>\n {onRetry ? (\n <button\n type=\"button\"\n data-sc-part=\"error-retry\"\n onClick={onRetry}\n style={{\n marginTop: '10px',\n padding: '6px 14px',\n borderRadius: '9999px',\n border: '1px solid currentColor',\n background: 'transparent',\n color: 'inherit',\n font: 'inherit',\n fontWeight: 600,\n cursor: 'pointer',\n }}\n >\n Retry\n </button>\n ) : null}\n </div>\n );\n}\n\ninterface BoundaryProps {\n /** Imperatively-reported error (handler/async path) — same card. */\n reportedError: EditorError | null;\n onRetry: () => void;\n children: ReactNode;\n}\n\ninterface BoundaryState {\n caught: Error | null;\n}\n\n/**\n * The catching half of Root's boundary (D11): render/lifecycle/effect throws\n * from the parts show an error card in the widget slot while the host page\n * survives.\n *\n * Test containment-bypass (the D11 review concern — \"an agent's mounts-\n * without-crashing test passes green on a broken composition\"): under\n * NODE_ENV=test/dev every contained error is RECORDED, and\n * `expectNoEditorErrors()` from `@snowcone-app/canvas/testing` fails the\n * test. (A literal rethrow-from-the-boundary was tried and rejected: an\n * uncaught throw from a layout effect corrupts React 18's work loop and\n * poisons every later render in the test file — \"Should not already be\n * working\".)\n */\nclass CatchingBoundary extends Component<BoundaryProps, BoundaryState> {\n state: BoundaryState = { caught: null };\n\n static getDerivedStateFromError(error: Error): BoundaryState {\n return { caught: error };\n }\n\n componentDidCatch(error: Error): void {\n recordContainedEditorError(error);\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.error('[Editor.Root] contained a composition error:', error);\n }\n }\n\n render(): ReactNode {\n if (this.state.caught) {\n // Composition mistakes need a code change; a retry would just re-throw.\n return <ErrorCard error={this.state.caught} />;\n }\n return this.props.children;\n }\n}\n\n/**\n * Root's built-in boundary (D11): the imperatively-REPORTED channel\n * (handler/async failures like the lazy chunk failing to load) renders the\n * card directly, with retry when the failure is retryable; everything else\n * goes through the catching class boundary above.\n */\nfunction EditorBoundary({ reportedError, onRetry, children }: BoundaryProps): React.ReactElement {\n if (reportedError) {\n const retryable = isEditorError(reportedError) && reportedError.code === 'E_CHUNK_LOAD_FAILED';\n return <ErrorCard error={reportedError} onRetry={retryable ? onRetry : undefined} />;\n }\n return <CatchingBoundary reportedError={null} onRetry={onRetry}>{children}</CatchingBoundary>;\n}\n\n// ── The state-owning inner (everything here is INSIDE the boundary) ─────────\n\nfunction EditorRootInner(props: EditorRootProps & { internals: EditorRootInternals }): React.ReactElement {\n const {\n shop,\n product,\n design,\n throttleMs = 200,\n onMockups,\n onRenderError,\n wsUrl,\n services,\n children,\n internals,\n __validation = 'throw',\n } = props;\n\n const placement = useMemo(() => design.toJSON().activeArtboard, [design]);\n\n // #566: fetch the product's printable-area guides (camera cutouts, safe\n // areas) so the editor shows them automatically — without this, a buyer can\n // edit artwork that sits under hardware and the mockup never changes, with\n // no signal anywhere. variantId IS a gvid; fall back to the catalog's\n // default variant. Gated below on the design's artboard matching the\n // print-file frame the guides were authored in (same gate as snowcone.app).\n const guideBundle = usePieceGuideBundle(product.variantId ?? product.defaultGvid);\n const pieceGuides = useMemo(() => {\n if (!guideBundle) return null;\n const artboard = design.toJSON().artboards[0];\n return pieceGuidesForArtboard(guideBundle, artboard) ?? null;\n }, [guideBundle, design]);\n\n // Keep the latest callbacks reachable without re-creating the session.\n const onMockupsRef = useRef(onMockups);\n const onRenderErrorRef = useRef(onRenderError);\n onMockupsRef.current = onMockups;\n onRenderErrorRef.current = onRenderError;\n\n const [mockups, setMockups] = useState<MockupResult[]>([]);\n const [isRendering, setIsRendering] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const hasGrant = Boolean(('grantUrl' in props && props.grantUrl) || ('grant' in props && props.grant));\n\n // One session per (shop, product, placement, auth). Key it on the product's\n // identity-BEARING fields, not the object reference — so an embedder passing\n // an inline `product={{…}}` (the natural way to write it) doesn't rebuild the\n // session and reconnect on every render. A real change (different product,\n // mockups, or variant) still re-keys it. `options`/`placements` are advisory\n // (fail-fast validation) so they don't need to force a rebuild.\n const auth = toGetToken(props);\n const authKey = 'grantUrl' in auth ? auth.grantUrl : 'getToken';\n const productKey = `${product.productId}|${product.mockupIds.join(',')}|${product.variantId ?? ''}`;\n\n // Wiring validation. Editor.Root throws (F3 — fails loud into the boundary,\n // visible to headless agents); the legacy <RealtimeEmbed> wrapper keeps the\n // advisory dev-only console diagnostics. The ref-based dedup survives\n // StrictMode's deliberate unmount/remount cycle.\n const validationKey = `${shop}|${productKey}|${placement}|${hasGrant}`;\n // Render-time on purpose: in throw mode a wiring mistake must throw into\n // Root's boundary, not log (F3 — console.error is invisible to headless\n // agents). Memoized so it runs once per meaningful change.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => {\n if (__validation !== 'throw') return;\n const issues = collectEmbedIssues({ shop, product, design, hasGrant });\n const fatal = issues.find((i) => i.severity === 'error');\n if (fatal) {\n throw new EditorError('E_EMBED_CONFIG', fatal.message, {\n issue: fatal.issue,\n docSlug: 'embed-mode',\n });\n }\n for (const issue of issues) {\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n console.warn(`[Editor.Root] ${issue.message}`);\n }\n }\n }, [validationKey, __validation]);\n const validatedKeyRef = useRef<string | null>(null);\n useEffect(() => {\n if (__validation !== 'warn') return;\n if (typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production') {\n if (validatedKeyRef.current === validationKey) return;\n validatedKeyRef.current = validationKey;\n validateEmbed({ shop, product, design, hasGrant });\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [validationKey, __validation]);\n\n // RenderSession's constructor fail-fasts (e.g. a variant product with no\n // variantId) by THROWING. Catch it here so a config mistake surfaces through\n // `onRenderError` + the error state instead of throwing during render and\n // white-screening the whole host page.\n const sessionResult = useMemo<{ session: RenderSession } | { error: string }>(\n () => {\n try {\n return { session: new RenderSession({ shop, product, wsUrl, ...auth }) };\n } catch (err) {\n return { error: err instanceof Error ? err.message : String(err) };\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [shop, productKey, placement, wsUrl, authKey]\n );\n const session = 'session' in sessionResult ? sessionResult.session : null;\n const constructError = 'error' in sessionResult ? sessionResult.error : null;\n\n const pushRender = useMemo(() => {\n return (state: RenderState, throttle = throttleMs) => {\n if (!session) return;\n setError(null);\n setIsRendering(true);\n void session.renderState(placement, state, throttle).catch((err) => {\n const message = err instanceof Error ? err.message : String(err);\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n };\n }, [session, placement, throttleMs]);\n\n useEffect(() => {\n // Construction fail-fast (caught above) — surface it instead of rendering.\n if (constructError) {\n setError(constructError);\n setIsRendering(false);\n onRenderErrorRef.current?.(constructError);\n return;\n }\n if (!session) return;\n\n session.onMockups((results) => {\n setMockups(results);\n setIsRendering(false);\n onMockupsRef.current?.(results);\n });\n session.onError((message) => {\n setError(message);\n setIsRendering(false);\n onRenderErrorRef.current?.(message);\n });\n\n // Seed the first mockup from the design before any edit, so a freshly\n // mounted embed shows a real mockup immediately (no duplicate seed state —\n // the design is the single source).\n pushRender(design.toServerRequest());\n\n return () => session.close();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [session, constructError]);\n\n // Runtime silent-hang backstop. While a render is in flight, arm a timer; if no\n // mockup (or error) lands within SLOW_RENDER_HINT_MS, log an actionable hint.\n // Unlike the mount-time wiring guard this fires ONLY on an actual stall, so it\n // never nags a working embed — and it covers every silent-hang cause, not just\n // missing variantId. Dev-only (the `process` ref is typeof-guarded on the same\n // line); cleared the moment `isRendering` flips false.\n useEffect(() => {\n if (!isRendering) return;\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n const timer = setTimeout(() => console.warn(slowRenderHint(placement)), SLOW_RENDER_HINT_MS);\n return () => clearTimeout(timer);\n }, [isRendering, placement]);\n\n const value = useMemo<EmbedContextValue>(\n () => ({\n session,\n design,\n placement,\n product,\n mockups,\n isRendering,\n error,\n throttleMs,\n pieceGuides,\n pushRender,\n stateStore: internals.store,\n }),\n [session, design, placement, product, mockups, isRendering, error, throttleMs, pieceGuides, pushRender, internals.store]\n );\n\n // Single validation point for the part registry (ADR-0085 §4). Parts\n // register in their layout effects (so a whole commit's registrations\n // arrive together — no race against the lazy canvas chunk); each change\n // re-renders this component, and validation throws RENDER-side, where\n // Root's boundary reliably contains it (layout-effect throws are not\n // dependably boundary-caught across React 18 + DOM test environments).\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useMemo(() => internals.registry.validate(), [internals.registry, registryVersion]);\n\n const body = (\n <EditorRootInternalsContext.Provider value={internals}>\n <EmbedContext.Provider value={value}>{children}</EmbedContext.Provider>\n </EditorRootInternalsContext.Provider>\n );\n\n // Only mount a services provider when configured — `<Editor.Canvas>`'s\n // inner SnowconeCanvas inherits it through context.\n if (services) {\n return <CanvasServicesProvider services={services}>{body}</CanvasServicesProvider>;\n }\n return body;\n}\n\n/**\n * The root of an `Editor.*` composition. See the module doc for the state\n * model; see `RealtimeEmbed` for the legacy turnkey wrapper this was\n * extracted from.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorRoot(props: EditorRootProps): React.ReactElement {\n const { design } = props;\n\n // One store + registry per (design) — remounting with a new design reseeds.\n const internalsRef = useRef<{ design: AnyDesign; internals: Omit<EditorRootInternals, 'reportInvariant' | 'reportRuntimeError'> } | null>(null);\n const [reportedError, setReportedError] = useState<EditorError | null>(null);\n if (internalsRef.current === null || internalsRef.current.design !== design) {\n internalsRef.current = {\n design,\n internals: {\n store: new DesignStateStore(design.toJSON()),\n registry: new EditorPartsRegistry(),\n },\n };\n }\n\n const internals = useMemo<EditorRootInternals>(\n () => ({\n ...internalsRef.current!.internals,\n ...makeInvariantReporter(setReportedError),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [internalsRef.current.internals]\n );\n\n return (\n // `display: contents` — the .sc-root scope without a layout box, so the\n // host's grid/flex sees the parts directly (and the legacy RealtimeEmbed\n // wrapper, which had no DOM at all, stays layout-identical).\n <div className=\"sc-root\" style={{ display: 'contents' }} data-sc-part=\"root\">\n <EditorBoundary reportedError={reportedError} onRetry={() => setReportedError(null)}>\n <EditorRootInner {...props} internals={internals} />\n </EditorBoundary>\n </div>\n );\n}\n","'use client';\n\n/**\n * `<Editor.Canvas>` — the editable artboard, and the ONE lazy boundary of the\n * primitives (D9): all state mounts with `Editor.Root`; the heavy rendering\n * engine lives in {@link EditorCanvasImpl}'s chunk and loads only when this\n * part mounts. A no-canvas composition (Preview + TextField + Buy) never\n * fetches it — CI-asserted by the import-graph check.\n *\n * A failed chunk load (network/CDN) is a RUNTIME failure, not a composition\n * mistake: it routes to Root's error card with a retry affordance\n * (`E_CHUNK_LOAD_FAILED`) in every env. Retry clears the card, which remounts\n * this part and re-attempts the import.\n */\n\nimport React, { forwardRef, useEffect, useId, useLayoutEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEditorRootInternals } from './RootInternals.js';\nimport type { EditorCanvasImplProps } from './EditorCanvasImpl.js';\nimport type { SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\n\ntype ImplComponent = (typeof import('./EditorCanvasImpl.js'))['EditorCanvasImpl'];\n\nlet implLoader: () => Promise<ImplComponent> = () =>\n import('./EditorCanvasImpl.js').then((m) => m.EditorCanvasImpl);\n\n/** Load the heavy impl chunk. Exposed for the legacy `<RealtimeCanvas>`\n * wrapper so both share ONE lazy boundary (one chunk). @internal */\nexport function loadCanvasImpl(): Promise<ImplComponent> {\n return implLoader();\n}\n\n/** Swap the chunk loader — TEST-ONLY seam for the chunk-load-failure → error\n * card → retry contract (a real `import()` can't be made to fail once and\n * then succeed under the module cache). Returns a restore function.\n * @internal */\nexport function __setCanvasImplLoaderForTests(loader: () => Promise<ImplComponent>): () => void {\n const previous = implLoader;\n implLoader = loader;\n return () => {\n implLoader = previous;\n };\n}\n\nexport interface EditorCanvasProps {\n /** Your overlay controls — rendered inside the editor context, so the\n * binding hooks (`useTextBinding` …) resolve against live elements. */\n children?: ReactNode;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * The editable artboard. Mount at most one under a Root\n * (`E_DUPLICATE_CANVAS`); mount none for the no-canvas personalization\n * composition.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport const EditorCanvas = forwardRef<SnowconeCanvasHandle, EditorCanvasProps>(function EditorCanvas(\n { children, maxHeight, className, style }: EditorCanvasProps,\n ref,\n): React.ReactElement {\n const internals = useEditorRootInternals('Editor.Canvas');\n const instanceId = useId();\n\n // Registration is by THIS component's mount, not the chunk's arrival — so\n // duplicate detection and requires-canvas validation never race the lazy\n // load (ADR-0085 §4).\n useLayoutEffect(() => {\n return internals.registry.registerCanvas(instanceId);\n }, [internals.registry, instanceId]);\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n if (cancelled) return;\n internals.reportRuntimeError(\n new EditorError(\n 'E_CHUNK_LOAD_FAILED',\n `the editor's rendering chunk failed to load (${err instanceof Error ? err.message : String(err)}). ` +\n 'This is a network/CDN failure, not a composition mistake — retry, or check the deployment ' +\n 'serves the @snowcone-app/canvas lazy chunks.',\n { cause: err instanceof Error ? err.message : String(err), docSlug: 'embed-mode' },\n ),\n );\n },\n );\n return () => {\n cancelled = true;\n };\n }, [internals]);\n\n if (!Impl) {\n // Lightweight placeholder while the chunk loads — keeps the host layout\n // stable; themed via .sc-root tokens like every part.\n return (\n <div\n data-sc-part=\"canvas\"\n data-sc-state=\"loading\"\n className={className}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} kit=\"embed-only\" partAttr=\"canvas\" maxHeight={maxHeight} className={className} style={style}>\n {children}\n </Impl>\n );\n});\n\nexport type { EditorCanvasImplProps };\n","'use client';\n\n/**\n * `<Editor.Preview>` — the live product mockup (the buyable thing), extracted\n * from the legacy `<RealtimeMockup>` (which now wraps this).\n *\n * Reads the shared session's mockups from context and renders the rendered\n * image, updating as the shopper edits. Because every Preview shares one\n * session with the rest of the composition, it can never desync — and\n * MULTIPLE Previews under one Root are explicitly VALID (front/back; mockup\n * scenes via `mockupId`). Canvas-free by design: the no-canvas\n * personalization widget is Preview + TextField + Buy.\n */\n\nimport React, { useRef, type CSSProperties, type ReactNode, type SyntheticEvent } from 'react';\nimport { useEmbedContext } from '../embed-realtime/context.js';\n\nexport interface EditorPreviewProps {\n /** Which mockup scene to show (a `product.mockupIds` entry). Defaults to the\n * first mockup that has rendered. */\n mockupId?: string;\n /** Shown before the first mockup arrives / while a render is in flight with no\n * prior image. Defaults to nothing. */\n fallback?: ReactNode;\n /** Alt text for the rendered image. */\n alt?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * How far the displayed device-pixel width may exceed the delivered mockup's\n * natural width before {@link resolutionMismatchHint} fires. Renders default to\n * 1000px wide, so a 1000px image inside a ~1100 device-px slot is fine (browser\n * downscale slack), but stretched across 2000 device px it looks soft and the\n * developer deserves to hear why.\n */\nexport const RESOLUTION_MISMATCH_RATIO = 1.2;\n\n/**\n * The render-width ladder a mismatch suggestion rounds UP to. Mirrors the\n * `product.width` guidance (\"bump to ~2000 for a crisp preview\") with sensible\n * steps — suggesting the exact device-px count would invite over-precise\n * configs that re-trigger on the next viewport.\n */\nconst SUGGESTED_WIDTHS = [1200, 1400, 1600, 1800, 2000, 2500, 3000, 4000] as const;\n\n/** Rounds a device-pixel width up to the next {@link SUGGESTED_WIDTHS} step\n * (capped at the top step). */\nexport function suggestRenderWidth(devicePx: number): number {\n for (const step of SUGGESTED_WIDTHS) {\n if (step >= devicePx) return step;\n }\n return SUGGESTED_WIDTHS[SUGGESTED_WIDTHS.length - 1];\n}\n\n/**\n * Builds the dev-console warning shown when a delivered mockup's natural width\n * is meaningfully below the width it's displayed at in DEVICE pixels (CSS width\n * × `devicePixelRatio`) — the \"my preview looks soft and nothing says why\"\n * trap: renders default to 1000px wide, which blurs on a large or high-density\n * display. Returns `null` when the resolution is adequate (within\n * {@link RESOLUTION_MISMATCH_RATIO}) or either measurement is unusable.\n */\nexport function resolutionMismatchHint(naturalWidth: number, devicePx: number): string | null {\n if (!(naturalWidth > 0) || !(devicePx > 0)) return null;\n if (devicePx <= naturalWidth * RESOLUTION_MISMATCH_RATIO) return null;\n const suggestion = suggestRenderWidth(devicePx);\n return (\n `[RealtimeMockup] mockup rendered at ${naturalWidth}px but displayed at ` +\n `~${devicePx} device px — the preview will look soft. Pass ` +\n `\\`product.width\\` (e.g. ${suggestion}) on the embed for a crisp preview.`\n );\n}\n\n/**\n * The live product mockup. Mount as many as you need under one Root.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorPreview({\n mockupId,\n fallback = null,\n alt = 'Live product mockup',\n className,\n style,\n}: EditorPreviewProps): React.ReactElement {\n const { mockups } = useEmbedContext();\n\n // Mockup ids already warned about this mount — re-renders and repeated loads\n // of the same scene stay quiet; a different scene gets its own one warning.\n const warnedMockupIdsRef = useRef<Set<string>>(new Set());\n\n const result = mockupId\n ? mockups.find((m) => m.mockupId === mockupId && m.imageUrl)\n : mockups.find((m) => m.imageUrl);\n\n if (!result?.imageUrl) {\n return <>{fallback}</>;\n }\n\n // Dev-only resolution check (the `process` reference is typeof-guarded on the\n // same line — non-Node bundlers don't define it). Runs on load because only a\n // decoded image knows its natural width; skips SSR (no `window`) and\n // unmeasurable (zero-width) elements.\n const handleLoad = (event: SyntheticEvent<HTMLImageElement>) => {\n if (typeof process === 'undefined' || process.env?.NODE_ENV === 'production') return;\n if (typeof window === 'undefined') return;\n if (warnedMockupIdsRef.current.has(result.mockupId)) return;\n const img = event.currentTarget;\n const cssWidth = img.getBoundingClientRect().width;\n if (cssWidth <= 0) return;\n const devicePx = Math.round(cssWidth * (window.devicePixelRatio || 1));\n const hint = resolutionMismatchHint(img.naturalWidth, devicePx);\n if (hint) {\n warnedMockupIdsRef.current.add(result.mockupId);\n console.warn(hint);\n }\n };\n\n return (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n data-sc-part=\"preview\"\n src={result.imageUrl}\n alt={alt}\n className={className}\n style={style}\n onLoad={handleLoad}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.TextField>` — a form input bound to a design text layer by TYPED\n * TOKEN (ADR-0085 §1 / T1). Canvas-free by design: in the no-canvas\n * personalization widget it writes the Root's design state directly and the\n * preview re-renders live; with a mounted `Editor.Canvas` the same writes\n * route through the editor command path (undo/redo, repaint) via the canvas\n * bridge — the editor document stays the single write authority (§3). The\n * routing is internal; the API is identical in both compositions.\n *\n * Contract (D10):\n * - `layer` accepts ONLY a `design.layer(\"name\")` token — a bare string\n * throws `E_LAYER_TOKEN_REQUIRED` (today's silent no-op binding became a\n * throw when entering `Editor.*`).\n * - Mount-time revalidation is the authority: the token's name is re-resolved\n * against the mounted Root's CURRENT design state — a token minted from a\n * different design throws `E_LAYER_NOT_FOUND` (dev AND prod).\n * - Mounted + non-`optional` ⇒ required for `Editor.Buy` completeness\n * (non-empty after trim AND differs from seed — C2/C3); unmounted (incl.\n * conditionally hidden) ⇒ not required. Registration lives in Root context.\n * - Reconciliation with canvas edits of the same layer is by construction:\n * one store, last-write-wins; this is a controlled input subscribed to the\n * store, so a canvas edit updates the field.\n */\n\nimport React, { useCallback, useId, useLayoutEffect, useRef, useSyncExternalStore, type CSSProperties } from 'react';\nimport { serializeStateForServer } from '../../rendering/serialize-for-server.js';\nimport { isLayerToken, type LayerToken } from '../../design/design-builder.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\nexport interface EditorTextFieldProps {\n /** The text layer this input edits — mint with `design.layer(\"name\")`.\n * Type-checked against the design's TEXT-layer names when the design is\n * statically built; runtime-validated always. */\n layer: LayerToken<'text'>;\n /** Marked optional ⇒ Buy completeness does not require it (C2/C3). */\n optional?: boolean;\n placeholder?: string;\n /** Accessible label. Defaults to the layer name. */\n 'aria-label'?: string;\n className?: string;\n style?: CSSProperties;\n}\n\n/**\n * A text input bound to a design layer. Works with or without a mounted\n * `Editor.Canvas`.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorTextField(props: EditorTextFieldProps): React.ReactElement {\n const { layer, optional = false, placeholder, className, style } = props;\n const internals = useEditorRootInternals('Editor.TextField');\n const { pushRender, throttleMs, stateStore } = useEmbedContext();\n const instanceId = useId();\n\n // ── Token + MOUNT-time revalidation (render-time on purpose: a bad layer\n // prop is a composition mistake → Root's boundary, dev AND prod). Validated\n // once per layer name, against the state AT MOUNT — later state churn (the\n // user emptying the canvas, teardown ordering) is user state, not a\n // composition mistake; the write path reports it if a write ever misses. ──\n const validatedNameRef = useRef<string | null>(null);\n if (!isLayerToken(layer)) {\n throw new EditorError(\n 'E_LAYER_TOKEN_REQUIRED',\n `the \\`layer\\` prop must be a token minted by the design — pass ` +\n `layer={design.layer(\"name\")}, not ${typeof layer === 'string' ? `the bare string \"${layer}\"` : 'a plain value'}. ` +\n `Tokens validate the name against the design's layers at mint time.`,\n { received: typeof layer === 'string' ? layer : typeof layer, docSlug: 'embed-mode' },\n );\n }\n if (validatedNameRef.current !== layer.name) {\n const kindNow = stateStore.layerKindOf(layer.name);\n if (kindNow === undefined) {\n throw new EditorError(\n 'E_LAYER_NOT_FOUND',\n `no layer \"${layer.name}\" in this Root's design — the token was minted from a ` +\n `different design than the one passed to <Editor.Root design={…}>. Bindable layers ` +\n `here: ${JSON.stringify(stateStore.bindableLayerNames())}.`,\n { layerName: layer.name, validNames: stateStore.bindableLayerNames(), docSlug: 'embed-mode' },\n );\n }\n if (kindNow !== 'text') {\n throw new EditorError(\n 'E_LAYER_WRONG_KIND',\n `layer \"${layer.name}\" is ${kindNow === null ? 'not a bindable kind' : `an ${kindNow} layer`} — ` +\n `<Editor.TextField> binds text layers only.`,\n { layerName: layer.name, actualKind: kindNow, docSlug: 'embed-mode' },\n );\n }\n validatedNameRef.current = layer.name;\n }\n\n // ── Required-layer registration for Buy completeness (C2/C3) ─────────────\n useLayoutEffect(() => {\n return internals.registry.registerTextField(instanceId, { name: layer.name, optional });\n }, [internals.registry, instanceId, layer.name, optional]);\n\n // ── Controlled value from the ONE store (a canvas edit updates the field) ─\n const value = useSyncExternalStore(\n stateStore.subscribe,\n () => stateStore.textOf(layer.name) ?? '',\n () => stateStore.textOf(layer.name) ?? '',\n );\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const next = event.target.value;\n const bridge = internals.registry.getCanvasBridge();\n if (bridge) {\n // Canvas mounted: the editor document is the write authority — route\n // through commands; the canvas onChange lands the new state back in\n // the store and pushes the render.\n if (!bridge.setTextByName(layer.name, next)) {\n internals.reportInvariant(\n new EditorError(\n 'E_LAYER_NOT_FOUND',\n `layer \"${layer.name}\" no longer exists in the mounted canvas — it was removed ` +\n `or renamed after this <Editor.TextField> bound to it. Bound layers must not be ` +\n `renamed or deleted while a field is mounted (ADR-0085 §3).`,\n { layerName: layer.name, docSlug: 'embed-mode' },\n ),\n );\n }\n return;\n }\n // No canvas: the store IS the authority. Trailing-edge throttle in the\n // session keeps the last keystroke always rendering.\n stateStore.updateTextLayer(layer.name, next);\n pushRender(serializeStateForServer(stateStore.getState()), throttleMs);\n },\n [internals, layer.name, stateStore, pushRender, throttleMs],\n );\n\n return (\n <input\n data-sc-part=\"textfield\"\n data-sc-layer={layer.name}\n type=\"text\"\n value={value}\n onChange={handleChange}\n placeholder={placeholder}\n aria-label={props['aria-label'] ?? layer.name}\n className={className}\n style={style}\n />\n );\n}\n","'use client';\n\n/**\n * `<Editor.Buy>` — the SMART commerce part (ADR-0085 §2; plan decision: thin\n * callback-Buy was rejected). Owns quantity, design-completeness validation,\n * and cart-payload assembly; only the final submit is the host's callback —\n * their one line.\n *\n * Completeness rules (v1, C1–C5):\n * - C1 variant resolution — when the product has a COLOR axis (the one kind\n * of variant the renderer gates on), a valid `variantId` must be present\n * (the SDK's `assertVariantSelected`).\n * - C2 every MOUNTED non-`optional` `Editor.TextField` layer non-empty\n * after trim.\n * - C3 those layers must DIFFER from their seed value (F4 — placeholder\n * text like 'YOUR NAME' must not pass).\n * - C4 the design has ≥1 renderable element.\n * - C5 quantity is an integer ≥ 1.\n *\n * Incompleteness is USER state, not a composition error — the button renders\n * disabled with machine-readable `data-sc-buy-state` / `data-sc-buy-missing`\n * reason codes; it never throws. Throws are reserved for composition\n * violations (`E_BUY_NO_PRODUCT`, outside-Root).\n *\n * The payload is assembled from DESIGN STATE (the Root's live store — never\n * the seed, never rendered pixels), so render staleness cannot corrupt an\n * order; the preview is just preview (D10).\n */\n\nimport React, { useCallback, useMemo, useRef, useState, useSyncExternalStore, type CSSProperties, type ReactNode } from 'react';\nimport {\n assertVariantSelected,\n createCartDetail,\n type CartDetail,\n type RenderProduct,\n} from '@snowcone-app/sdk';\nimport { serializeStateForServer, type ServerRenderRequest } from '../../rendering/serialize-for-server.js';\nimport { EditorError } from '../../errors/editorError.js';\nimport { useEmbedContext } from '../embed-realtime/context.js';\nimport type { DesignState } from './designStateStore.js';\nimport { useEditorRootInternals } from './RootInternals.js';\n\n/** A structured incompleteness reason — also serialized (comma-joined) into\n * the button's `data-sc-buy-missing` attribute for agents and styling. */\nexport type BuyMissingReason =\n | 'variant'\n | `layer:${string}`\n | `layer-seed:${string}`\n | 'empty-design'\n | 'quantity';\n\nexport interface EditorBuyPayload {\n productId: string;\n variantId?: string;\n quantity: number;\n /** SDK cart detail (variant resolution + price) when the product carries\n * catalog `options`; `null` for option-less products. */\n cartDetail: CartDetail | null;\n /** The DESIGN STATE at click time (editor shape) — persist this; it is the\n * re-renderable source of truth for the purchased design. */\n designState: DesignState;\n /** The same state serialized for the server render path. */\n serverRequest: ServerRenderRequest;\n}\n\nexport interface EditorBuyProps {\n /** The final submit — the host's one line. Everything before it (variant,\n * quantity, completeness, payload assembly) is this part's job. */\n onAddToCart: (payload: EditorBuyPayload) => void | Promise<void>;\n /** Initial quantity (integer ≥ 1; default 1). */\n quantity?: number;\n /** Button label. Defaults to \"Add to cart\". */\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n}\n\n/** Pure completeness evaluation — exported for tests. @internal */\nexport function evaluateBuyCompleteness(input: {\n product: RenderProduct;\n quantity: number;\n textFields: Array<{ name: string; optional: boolean }>;\n textOf: (name: string) => string | undefined;\n seedTextOf: (name: string) => string | undefined;\n hasRenderableElement: boolean;\n}): BuyMissingReason[] {\n const missing: BuyMissingReason[] = [];\n\n // C1 — color-axis variant resolution, via the SDK's existing gate (only\n // hex/color axes gate rendering; size-style axes render on the default).\n if (input.product.options) {\n try {\n assertVariantSelected(input.product);\n } catch {\n missing.push('variant');\n }\n }\n\n // C2 + C3 — mounted required TextField layers.\n for (const field of input.textFields) {\n if (field.optional) continue;\n const value = (input.textOf(field.name) ?? '').trim();\n if (value.length === 0) {\n missing.push(`layer:${field.name}`);\n continue;\n }\n const seed = (input.seedTextOf(field.name) ?? '').trim();\n if (seed.length > 0 && value === seed) {\n missing.push(`layer-seed:${field.name}`);\n }\n }\n\n // C4 — something to print.\n if (!input.hasRenderableElement) {\n missing.push('empty-design');\n }\n\n // C5 — sane quantity.\n if (!Number.isInteger(input.quantity) || input.quantity < 1) {\n missing.push('quantity');\n }\n\n return missing;\n}\n\n/** Map the embed product's catalog `options` onto the SDK cart helpers'\n * shapes. Derives the selection from the chosen variant's combination. */\nfunction buildCartDetail(product: RenderProduct, quantity: number): CartDetail | null {\n const options = product.options;\n const combinations = options?.combinations;\n if (!options || !combinations?.length) return null;\n\n const combination =\n combinations.find((c) => c.variantId && c.variantId === product.variantId) ?? combinations[0];\n if (!combination) return null;\n\n const selection: Record<string, string> = {};\n for (const [key, value] of Object.entries(combination)) {\n if (key === 'variantId' || key === 'price') continue;\n if (typeof value === 'string') selection[key] = value;\n else if (typeof value === 'number') selection[key] = String(value);\n }\n\n const attributes = Object.fromEntries(\n Object.keys(selection).map((key) => [\n key,\n { key, affectsCombinations: true, choices: [...new Set(combinations.map((c) => String(c[key] ?? '')))] },\n ]),\n );\n\n return createCartDetail({\n productId: product.productId,\n quantity,\n selection,\n combinations: combinations as Parameters<typeof createCartDetail>[0]['combinations'],\n attributes,\n });\n}\n\n/**\n * The add-to-cart button, completeness-gated and payload-assembling.\n *\n * @experimental ADR-0085; subject to change until the P4 gate.\n */\nexport function EditorBuy(props: EditorBuyProps): React.ReactElement {\n const { onAddToCart, quantity = 1, children, className, style } = props;\n const internals = useEditorRootInternals('Editor.Buy');\n const { product, stateStore } = useEmbedContext();\n\n // Composition violation — not user state: throw into Root's boundary.\n if (!product?.productId) {\n throw new EditorError(\n 'E_BUY_NO_PRODUCT',\n '<Editor.Buy> has no product context — pass `product` (with `productId`) on ' +\n '<Editor.Root product={…}>. Buy assembles its cart payload from the Root product ' +\n 'and the live design state.',\n { docSlug: 'embed-mode' },\n );\n }\n\n // Subscribe narrowly: design state + part registry (TextField mounts).\n const stateVersion = useSyncExternalStore(stateStore.subscribe, stateStore.getState, stateStore.getState);\n const registryVersion = useSyncExternalStore(\n internals.registry.subscribe,\n internals.registry.getVersion,\n internals.registry.getVersion,\n );\n\n const missing = useMemo(\n () =>\n evaluateBuyCompleteness({\n product,\n quantity,\n textFields: internals.registry.getTextFields(),\n textOf: (name) => stateStore.textOf(name),\n seedTextOf: (name) => stateStore.seedTextOf(name),\n hasRenderableElement: stateStore.hasRenderableElement(),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [product, quantity, stateVersion, registryVersion],\n );\n const complete = missing.length === 0;\n\n // Double-click inert: the callback fires exactly once per click while\n // assembling/submitting (P2 test contract).\n const [busy, setBusy] = useState(false);\n const busyRef = useRef(false);\n\n const handleClick = useCallback(() => {\n if (busyRef.current || !complete) return;\n busyRef.current = true;\n setBusy(true);\n\n const designState = stateStore.getState();\n const payload: EditorBuyPayload = {\n productId: product.productId,\n ...(product.variantId ? { variantId: product.variantId } : {}),\n quantity,\n cartDetail: buildCartDetail(product, quantity),\n designState,\n serverRequest: serializeStateForServer(designState),\n };\n\n // Invoke synchronously (predictable for hosts and tests); only the\n // SETTLING of an async callback is awaited for the busy window.\n let result: void | Promise<void>;\n try {\n result = onAddToCart(payload);\n } catch (err) {\n busyRef.current = false;\n setBusy(false);\n throw err;\n }\n void Promise.resolve(result).finally(() => {\n busyRef.current = false;\n setBusy(false);\n });\n }, [complete, product, quantity, stateStore, onAddToCart]);\n\n return (\n <button\n type=\"button\"\n data-sc-part=\"buy\"\n data-sc-buy-state={busy ? 'busy' : complete ? 'ready' : 'incomplete'}\n data-sc-buy-missing={missing.join(',') || undefined}\n disabled={!complete || busy}\n aria-busy={busy || undefined}\n onClick={handleClick}\n className={className}\n style={style}\n >\n {children ?? 'Add to cart'}\n </button>\n );\n}\n","'use client';\n\n/**\n * `Editor.*` — composable editor primitives over one `Editor.Root`\n * (ADR-0085). Parts carry behavior + state subscription; the HOST owns all\n * layout (with the documented exception of the canvas's selection-anchored\n * overlays — anchoring contract, ADR-0085 §5).\n *\n * ```tsx\n * import { Editor, design } from '@snowcone-app/canvas/embed';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * // No-canvas personalization widget — the rendering engine never loads:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Preview />\n * <Editor.TextField layer={d.layer('headline')} placeholder=\"Your name\" />\n * <Editor.Buy onAddToCart={({ designState }) => persist(designState)} />\n * </Editor.Root>\n *\n * // Full editor — same surface, plus the lazy canvas:\n * <Editor.Root shop={SHOP_KEY} product={product} design={d} grantUrl=\"/api/grant\">\n * <Editor.Canvas />\n * <Editor.Preview />\n * <Editor.Buy onAddToCart={…} />\n * </Editor.Root>\n * ```\n *\n * All parts are `@experimental` until the P4 gate (the default editor rebuilt\n * from these public parts) passes — the API may change in minors until then.\n */\n\nimport { EditorRoot } from './EditorRoot.js';\nimport { EditorCanvas } from './EditorCanvas.js';\nimport { EditorPreview } from './EditorPreview.js';\nimport { EditorTextField } from './EditorTextField.js';\nimport { EditorBuy } from './EditorBuy.js';\n\nexport const Editor = {\n /** The one provider boundary — session, design, live state, error boundary. */\n Root: EditorRoot,\n /** The editable artboard (the ONE lazy renderer boundary — D9). */\n Canvas: EditorCanvas,\n /** Live product mockup. ×N under one Root is valid. */\n Preview: EditorPreview,\n /** Form input bound to a design text layer by typed token (T1). */\n TextField: EditorTextField,\n /** Smart commerce part: completeness + payload assembly; submit = host callback. */\n Buy: EditorBuy,\n} as const;\n\nexport type { EditorRootProps, EditorRootBaseProps, GrantSource } from './EditorRoot.js';\nexport type { EditorCanvasProps } from './EditorCanvas.js';\nexport type { EditorPreviewProps } from './EditorPreview.js';\nexport type { EditorTextFieldProps } from './EditorTextField.js';\nexport type { EditorBuyProps, EditorBuyPayload, BuyMissingReason } from './EditorBuy.js';\nexport type { DesignState } from './designStateStore.js';\nexport { DesignStateStore } from './designStateStore.js';\n","'use client';\n\n/**\n * `<RealtimeEmbed>` — the legacy turnkey wrapper around `<Editor.Root>`.\n *\n * Everything it used to own (the single RenderSession, the design seed, the\n * live mockups, the context) was EXTRACTED into `EditorRoot` (ADR-0085 / D5 —\n * extraction, not copy): this component is `<EditorRoot>` plus the legacy\n * advisory validation mode (dev-only `console.error` diagnostics instead of\n * `Editor.Root`'s throw-on-misconfiguration, F3). The existing realtime\n * surface — `<RealtimeCanvas>`, `<RealtimeMockup>`, `useRealtimeMockups` —\n * reads the same context `EditorRoot` provides, so nothing existing changes\n * meaning, and the existing realtime tests exercise the new Root.\n *\n * @example\n * ```tsx\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED for a product with a color/variant axis (BEEB77 has\n * // a Frame color) — omit it and the render hangs. Pass `options` too so a\n * // wrong/missing variantId fails fast instead of timing out. Read both from\n * // getProduct(productId) (its options.combinations[].variantId).\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>\n * <RealtimeCanvas /> {/* editor *\\/}\n * <RealtimeMockup /> {/* live preview *\\/}\n * </div>\n * </RealtimeEmbed>\n * ```\n */\n\nimport React from 'react';\nimport {\n EditorRoot,\n type EditorRootBaseProps,\n type EditorRootProps,\n type GrantSource,\n} from '../editor/EditorRoot.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport { SLOW_RENDER_HINT_MS, slowRenderHint } from '../editor/EditorRoot.js';\nexport type { GrantSource };\n\n// Omit only from the non-union half — Omit over the GrantSource union would\n// collapse the exactly-one-of grant/grantUrl discrimination.\nexport type RealtimeEmbedProps = GrantSource & Omit<EditorRootBaseProps, '__validation'>;\n\nexport function RealtimeEmbed(props: RealtimeEmbedProps): React.ReactElement {\n return <EditorRoot {...(props as EditorRootProps)} __validation=\"warn\" />;\n}\n","'use client';\n\n/**\n * `<RealtimeCanvas>` — the interactive editor half of a realtime embed\n * (legacy turnkey API; `Editor.Canvas` is the primitives-era equivalent).\n *\n * Mounts a `<SnowconeCanvas>` seeded from the embed's `design`, and forwards\n * every edit to the shared RenderSession as a server render. All the\n * load-bearing wiring an embedder used to copy by hand is internal: the\n * `sc-root` class, `inheritTheme`, edit→`serializeStateForServer`→\n * `renderState`, and the artboard/placement match.\n *\n * Since ADR-0085 (D9) the implementation lives in the shared lazy renderer\n * chunk ({@link EditorCanvasImpl}) behind a dynamic import — the embed\n * entry's static import graph stays renderer-free, so a no-canvas\n * composition never downloads the rendering engine. The canvas therefore\n * mounts one micro-beat after first paint (a chunk fetch on cold cache); the\n * forwarded ref attaches when it does.\n *\n * Defaults to the chrome-less `kit=\"embed-only\"` — bring your own controls as\n * `children` (they render as an overlay INSIDE the canvas's editor context, so\n * `useTextBinding(name)` / `useImageBinding(name)` resolve against the live\n * elements). For a full in-canvas editor pass `kit=\"compact-customizer\"` or\n * `kit=\"pro-studio\"`.\n *\n * Must be rendered inside `<RealtimeEmbed>` (or any `EmbedContext` provider).\n */\n\nimport React, { forwardRef, useEffect, useState, type CSSProperties, type ReactNode } from 'react';\nimport type { CanvasState, SnowconeCanvasHandle } from '../embed/SnowconeCanvas.js';\nimport type { KitPresetId, KitDefinition } from '../../kits/types.js';\nimport type { CanvasServices } from '../../contexts/CanvasServicesContext.js';\nimport { loadCanvasImpl } from '../editor/EditorCanvas.js';\n\nexport interface RealtimeCanvasProps {\n /** Your controls (toolbar, inputs). Rendered as an overlay inside the editor\n * context so binding hooks work. */\n children?: ReactNode;\n /**\n * Editor chrome to mount. The default `'embed-only'` is a chrome-less canvas —\n * the host supplies every control as `children` (text inputs, image swap)\n * through `useTextBinding` / `useImageBinding`. That's the right call for a\n * fill-in-the-blanks personalizer, but it gives the shopper NO way to select a\n * layer and change its font size, add an element, or reorder layers.\n *\n * To ship a real editor through the turnkey realtime path, pass a richer\n * preset — `'compact-customizer'` (a trimmed toolbar) or `'pro-studio'` (full\n * panels). Every edit still flows to the shared RenderSession as a\n * server render automatically; you get add-element / font-size / layers for\n * free without ejecting to a raw `SnowconeCanvas` + `RenderSession`.\n *\n * Pair a chrome'd kit with `children` only when your overlay adds to — not\n * duplicates — the kit's controls, or you'll get double chrome.\n *\n * @default 'embed-only'\n */\n kit?: KitPresetId | KitDefinition;\n /** Inherit the host app's theme instead of managing its own (default true). */\n inheritTheme?: boolean;\n /** Cap the canvas height in px. */\n maxHeight?: number;\n /**\n * Privileged-service wiring for the editor chrome (Image Browser search /\n * AI tabs). Usually set once on `<RealtimeEmbed services={…}>` and inherited;\n * pass it here only to override for this canvas. Host the URLs on your\n * server — your vendor keys live there.\n */\n services?: CanvasServices;\n /**\n * Observe the live design state. Fires with the full {@link CanvasState}\n * (elements stamped with their artboard name) whenever the canvas content\n * changes — including once after the initial seed loads — in addition to the\n * embed's internal edit→server-render flow, which is unaffected. This is the\n * state you persist at add-to-cart / checkout so the purchased design can be\n * re-rendered server-side later.\n *\n * Safe to pass inline: the underlying canvas reads the callback from a ref,\n * so a new identity each render never re-fires or loops.\n */\n onChange?: (state: CanvasState) => void;\n className?: string;\n style?: CSSProperties;\n}\n\ntype ImplComponent = Awaited<ReturnType<typeof loadCanvasImpl>>;\n\n/**\n * Note the export naming wart, kept for backwards compatibility:\n * - The ref handle's {@link SnowconeCanvasHandle.exportArtboards} resolves a\n * record keyed by artboard **name** (e.g. `'Front'`) — names match the\n * `placements` you configured on the embed.\n * - The lower-level `useExport().exportArtboard(id)` hook takes an artboard\n * **ID** (get one from `useArtboards()`).\n * For print-res exports at checkout, the ref handle is the intended path:\n * `ref.current.exportArtboards({ all: true, scale: 4, format: 'blob' })`.\n */\nexport const RealtimeCanvas = forwardRef<SnowconeCanvasHandle, RealtimeCanvasProps>(\n function RealtimeCanvas(props: RealtimeCanvasProps, ref): React.ReactElement {\n const { children, className, style, maxHeight, ...rest } = props;\n\n const [Impl, setImpl] = useState<ImplComponent | null>(null);\n useEffect(() => {\n let cancelled = false;\n loadCanvasImpl().then(\n (component) => {\n if (!cancelled) setImpl(() => component);\n },\n (err) => {\n // Legacy surface keeps the advisory console contract (no Root\n // boundary is guaranteed to exist here).\n console.error('[RealtimeCanvas] failed to load the rendering chunk:', err);\n },\n );\n return () => {\n cancelled = true;\n };\n }, []);\n\n if (!Impl) {\n return (\n <div\n className={`sc-root${className ? ` ${className}` : ''}`}\n style={{ minHeight: maxHeight ?? 200, ...style }}\n aria-busy=\"true\"\n />\n );\n }\n\n return (\n <Impl ref={ref} selfScope maxHeight={maxHeight} className={className} style={style} {...rest}>\n {children}\n </Impl>\n );\n },\n);\n","'use client';\n\n/**\n * `<RealtimeMockup>` — the live preview half of a realtime embed (legacy\n * turnkey API). The implementation was EXTRACTED to `Editor.Preview`\n * (ADR-0085 / D5); this wrapper keeps the original name and props. (The\n * rendered `<img>` now carries `data-sc-part=\"preview\"` — additive only.)\n *\n * Because it shares one session with the rest of the embed, the preview can\n * never desync from the editor and needs no wiring of its own. Place it\n * anywhere inside `<RealtimeEmbed>`.\n */\n\nimport React from 'react';\nimport { EditorPreview, type EditorPreviewProps } from '../editor/EditorPreview.js';\n\n// Re-exported from the extraction home so existing imports keep working.\nexport {\n RESOLUTION_MISMATCH_RATIO,\n resolutionMismatchHint,\n suggestRenderWidth,\n} from '../editor/EditorPreview.js';\n\nexport type RealtimeMockupProps = EditorPreviewProps;\n\nexport function RealtimeMockup(props: RealtimeMockupProps): React.ReactElement {\n return <EditorPreview {...props} />;\n}\n","'use client';\n\nimport type { MockupResult } from '@snowcone-app/sdk';\nimport { useEmbedContext } from './context.js';\n\nexport interface UseRealtimeMockupsResult {\n /** All mockups from the latest render (one per requested mockupId). */\n mockups: MockupResult[];\n /** True between a render dispatch and the next mockup / error. */\n isRendering: boolean;\n /** Last render/timeout error message, or null. */\n error: string | null;\n}\n\n/**\n * Read the live mockups for a custom preview UI. Reactive: re-renders when new\n * mockups arrive. Must be called inside `<RealtimeEmbed>`.\n *\n * For the common case (just show the rendered image) use `<RealtimeMockup>`\n * instead — this hook is for building your own gallery / loading treatment.\n */\nexport function useRealtimeMockups(): UseRealtimeMockupsResult {\n const { mockups, isRendering, error } = useEmbedContext();\n return { mockups, isRendering, error };\n}\n","/**\n * @snowcone-app/canvas/embed — Realtime embed primitives (Tier 2)\n *\n * The turnkey way to drop a live, server-rendered product editor into your app.\n * Three components that share one session so the editor and the preview can't\n * desync, plus the `design()` builder that seeds both:\n *\n * ```tsx\n * import { RealtimeEmbed, RealtimeCanvas, RealtimeMockup, design }\n * from '@snowcone-app/canvas/embed';\n * import '@snowcone-app/canvas/style.css';\n *\n * const d = design({ name: 'Front', width: 1480, height: 2328 })\n * .background(artUrl, { aspectRatio: 1480 / 2328, name: 'art' })\n * .text('YOUR NAME', { anchor: 'top', name: 'headline' });\n *\n * <RealtimeEmbed\n * shop=\"YOUR_SHOP_ID\"\n * grantUrl=\"/api/realtime/grant\"\n * // variantId is REQUIRED when the product has a color/variant axis (BEEB77\n * // does) — omit it and the render hangs. Read it + options from getProduct().\n * product={{ productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC', placements: ['Front'] }}\n * design={d}\n * >\n * <RealtimeCanvas />\n * <RealtimeMockup />\n * </RealtimeEmbed>\n * ```\n *\n * Everything an embed needs is REQUIRED on `<RealtimeEmbed>` — there's no\n * silently-optional prop to forget. For full manual control (your own session,\n * custom layout, multi-placement, color variants) drop to `<SnowconeCanvas>` +\n * `RenderSession` directly; see the docs' \"eject\" section.\n *\n * @packageDocumentation\n */\n\n// Register icons on module load (the editor + overlay controls use them).\nimport { ensureIconsRegistered } from '../icons/registry.js';\nensureIconsRegistered();\n\n// === Editor.* composable primitives (ADR-0085) ===\n// @experimental until the P4 default-rebuilt-from-parts gate passes — the API\n// may change in minors. The turnkey Realtime* components below are stable.\nexport { Editor, DesignStateStore } from '../components/editor/index.js';\nexport type {\n EditorRootProps,\n EditorRootBaseProps,\n EditorCanvasProps,\n EditorPreviewProps,\n EditorTextFieldProps,\n EditorBuyProps,\n EditorBuyPayload,\n BuyMissingReason,\n DesignState,\n} from '../components/editor/index.js';\nexport { EditorError, isEditorError } from '../errors/editorError.js';\nexport type { EditorErrorCode, EditorErrorData } from '../errors/editorError.js';\n\n// === Embed primitives ===\nexport { RealtimeEmbed } from '../components/embed-realtime/RealtimeEmbed.js';\nexport type { RealtimeEmbedProps, GrantSource } from '../components/embed-realtime/RealtimeEmbed.js';\n\nexport { RealtimeCanvas } from '../components/embed-realtime/RealtimeCanvas.js';\nexport type { RealtimeCanvasProps } from '../components/embed-realtime/RealtimeCanvas.js';\n// `<RealtimeCanvas ref>` exposes the underlying canvas handle (print-res\n// `exportArtboards`, keyed by artboard NAME); `onChange` hands you the same\n// CanvasState shape — persist it at checkout, re-render it server-side later.\nexport type { SnowconeCanvasHandle, CanvasState } from '../components/embed/SnowconeCanvas.js';\n\nexport { RealtimeMockup } from '../components/embed-realtime/RealtimeMockup.js';\nexport type { RealtimeMockupProps } from '../components/embed-realtime/RealtimeMockup.js';\n\nexport { useRealtimeMockups } from '../components/embed-realtime/useRealtimeMockups.js';\nexport type { UseRealtimeMockupsResult } from '../components/embed-realtime/useRealtimeMockups.js';\n\nexport { validateEmbed, collectEmbedIssues } from '../components/embed-realtime/validateEmbed.js';\nexport type { ValidateEmbedInput, EmbedIssue } from '../components/embed-realtime/validateEmbed.js';\n\n// === Design builder — the single source of truth for an embed ===\nexport { design, DesignBuilder, isLayerToken } from '../design/design-builder.js';\nexport type {\n Anchor,\n ShapeKind,\n DesignArtboard,\n AnyDesign,\n LayerKind,\n LayerToken,\n} from '../design/design-builder.js';\n\n// === Chrome-building hooks (build your own editor chrome inside <RealtimeCanvas>) ===\n// These run inside the canvas's editor context — render the component that\n// calls them as `children` of <RealtimeCanvas> (the overlay slot). Same\n// exports as the stable entry, so chrome built against `@snowcone-app/canvas`\n// ports to the embed entry unchanged.\n\nexport { useEditor } from '../contexts/EditorContext.js';\nexport type { EditorContextValue, EditorProviderProps } from '../contexts/EditorContext.js';\n\nexport { useLayers } from '../hooks/useLayers.js';\nexport type { LayerInfo, UseLayersOptions, UseLayersReturn } from '../hooks/useLayers.js';\n\nexport { useCommands } from '../hooks/useCommands.js';\nexport type { UseCommandsReturn } from '../hooks/useCommands.js';\n\nexport { useArtboards } from '../hooks/useArtboards.js';\nexport type { ArtboardInfo, UseArtboardsReturn } from '../hooks/useArtboards.js';\n\n// NOTE the naming wart: `useExport().exportArtboard(id)` takes an artboard ID\n// (from `useArtboards()`), while the <RealtimeCanvas ref> handle's\n// `exportArtboards()` resolves a record keyed by artboard NAME.\nexport { useExport } from '../hooks/useExport.js';\nexport type { ExportProgress, ContinuousExportOptions, UseExportReturn } from '../hooks/useExport.js';\n\nexport { useSelectedElement } from '../hooks/useSelectedElement.js';\n\n// === State serialization (CanvasStateV1 — persist a design at checkout) ===\nexport { serializeState } from '../state/index.js';\nexport type {\n CanvasStateV1,\n SerializedArtboard,\n SerializedElement,\n} from '../state/index.js';\n\n// === Binding hooks (build your own controls inside <RealtimeCanvas>) ===\nexport { useTextBinding } from '../hooks/useTextBinding.js';\nexport { useImageBinding } from '../hooks/useImageBinding.js';\nexport { useColorBinding } from '../hooks/useColorBinding.js';\nexport type { ColorBindingResult } from '../hooks/useColorBinding.js';\nexport { useFontBinding } from '../hooks/useFontBinding.js';\nexport type { FontBindingResult } from '../hooks/useFontBinding.js';\nexport { useElementByName } from '../hooks/useElementByName.js';\n\n// === Editable templates (saved state + buyer-editable field manifest) ===\nexport {\n readTemplateFields,\n withTemplateFields,\n TEMPLATE_FIELDS_KEY,\n} from '../design/template-fields.js';\nexport type {\n TemplateField,\n TemplateTextField,\n TemplateImageField,\n TemplateColorField,\n TemplateSelectField,\n} from '../design/template-fields.js';\n\n// === Privileged services (Image Browser search / AI generation) ===\n// Same pattern as `grantUrl`: host the proxy routes on your server, your\n// vendor keys live there. Wire via `services` on <RealtimeEmbed>.\nexport { CanvasServicesProvider, useCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport type { CanvasServices, ResolvedCanvasServices } from '../contexts/CanvasServicesContext.js';\nexport { createProxyImageSearch, createProxyGenerate } from '../services/imageSearch.js';\nexport type {\n ImageSearchProvider,\n ImageSearchResult,\n ImageSearchResponse,\n ImageSearchParams,\n GenerateProvider,\n GenerateParams,\n GenerateResponse,\n} from '../services/imageSearch.js';\n\n// === Re-exported SDK types embedders touch ===\nexport type {\n RenderProduct,\n RenderProductOptions,\n RenderProductCombination,\n RenderProductRequiredPlacement,\n MockupResult,\n RealtimeGrant,\n} from '@snowcone-app/sdk';\n"],"names":["EmbedContext","createContext","useEmbedContext","ctx","useContext","TAG","requiredPlacementLabels","product","_a","p","variantIds","_b","c","id","collectEmbedIssues","shop","design","hasGrant","issues","assertVariantSelected","err","json","placement","required","names","el","n","dupes","i","validateEmbed","input","issue","textOf","nameOf","DesignStateStore","seed","listener","seedTexts","name","text","next","e","layerKindOfConfig","found","elements","EditorError","t","l","EditorPartsRegistry","instanceId","partName","parts","reg","bridge","EditorRootInternalsContext","useEditorRootInternals","makeInvariantReporter","routeToErrorState","error","isDevOrTest","recordContainedEditorError","SLOW_RENDER_HINT_MS","slowRenderHint","toGetToken","props","grant","ErrorCard","onRetry","code","isEditorError","jsxs","jsx","CatchingBoundary","Component","process","EditorBoundary","reportedError","children","retryable","EditorRootInner","throttleMs","onMockups","onRenderError","wsUrl","services","internals","__validation","useMemo","guideBundle","usePieceGuideBundle","pieceGuides","artboard","pieceGuidesForArtboard","onMockupsRef","useRef","onRenderErrorRef","mockups","setMockups","useState","isRendering","setIsRendering","setError","auth","authKey","productKey","validationKey","fatal","validatedKeyRef","useEffect","sessionResult","RenderSession","session","constructError","pushRender","state","throttle","message","results","timer","value","registryVersion","useSyncExternalStore","body","CanvasServicesProvider","EditorRoot","internalsRef","setReportedError","implLoader","m","loadCanvasImpl","EditorCanvas","forwardRef","maxHeight","className","style","ref","useId","useLayoutEffect","Impl","setImpl","cancelled","component","RESOLUTION_MISMATCH_RATIO","SUGGESTED_WIDTHS","suggestRenderWidth","devicePx","step","resolutionMismatchHint","naturalWidth","suggestion","EditorPreview","mockupId","fallback","alt","warnedMockupIdsRef","result","handleLoad","event","img","cssWidth","hint","EditorTextField","layer","optional","placeholder","stateStore","validatedNameRef","isLayerToken","kindNow","handleChange","useCallback","serializeStateForServer","evaluateBuyCompleteness","missing","field","buildCartDetail","quantity","options","combinations","combination","selection","key","attributes","createCartDetail","EditorBuy","onAddToCart","stateVersion","complete","busy","setBusy","busyRef","handleClick","designState","payload","Editor","RealtimeEmbed","RealtimeCanvas","rest","RealtimeMockup","useRealtimeMockups","ensureIconsRegistered"],"mappings":"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"}