@snowcone-app/canvas 0.17.2 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/{ImportManager-C_wBjWaV.js → CanvasRenderer-DUc-MOeR.js} +586 -806
  2. package/dist/CanvasRenderer-DUc-MOeR.js.map +1 -0
  3. package/dist/{CanvasStateV1-BG2hEc3-.js → CanvasStateV1-Bq48qhv5.js} +3 -3
  4. package/dist/{CanvasStateV1-BG2hEc3-.js.map → CanvasStateV1-Bq48qhv5.js.map} +1 -1
  5. package/dist/ContextualToolbars-CkLjHNPn.js +5833 -0
  6. package/dist/ContextualToolbars-CkLjHNPn.js.map +1 -0
  7. package/dist/EditorCanvasImpl-Bv4yagew.js +81 -0
  8. package/dist/EditorCanvasImpl-Bv4yagew.js.map +1 -0
  9. package/dist/EditorContext-5QpqAhjh.js +1184 -0
  10. package/dist/{EditorContext-CGkfmbgo.js.map → EditorContext-5QpqAhjh.js.map} +1 -1
  11. package/dist/{FontAnalyzer-CLv7_msL.js → FontAnalyzer-DIlqmyuf.js} +35 -35
  12. package/dist/FontAnalyzer-DIlqmyuf.js.map +1 -0
  13. package/dist/{ElementFactory-CuHSAPfg.js → ImportManager-D--7JnvW.js} +699 -476
  14. package/dist/ImportManager-D--7JnvW.js.map +1 -0
  15. package/dist/MenuButton-CeoEAtzP.js +7444 -0
  16. package/dist/MenuButton-CeoEAtzP.js.map +1 -0
  17. package/dist/SnowconeCanvas-C_O-aeaQ.js +1166 -0
  18. package/dist/SnowconeCanvas-C_O-aeaQ.js.map +1 -0
  19. package/dist/advanced.mjs +266 -264
  20. package/dist/advanced.mjs.map +1 -1
  21. package/dist/api/embed.d.ts +1 -1
  22. package/dist/components/ContextualToolbars.d.ts +8 -0
  23. package/dist/components/editor/EditorAdd.d.ts +11 -0
  24. package/dist/components/editor/EditorCanvasImpl.d.ts +6 -0
  25. package/dist/components/editor/EditorControls.d.ts +14 -0
  26. package/dist/components/editor/EditorHistory.d.ts +11 -0
  27. package/dist/components/editor/EditorLayers.d.ts +16 -0
  28. package/dist/components/editor/EditorMenu.d.ts +11 -0
  29. package/dist/components/editor/RootInternals.d.ts +7 -0
  30. package/dist/components/editor/index.d.ts +20 -0
  31. package/dist/components/embed/addElementTypes.d.ts +9 -0
  32. package/dist/contexts/EditorContext.d.ts +38 -0
  33. package/dist/core/preview-registry.d.ts +34 -0
  34. package/dist/{editorErrors-BY4Pdg7a.js → editorErrors-DXNfVXtD.js} +2 -2
  35. package/dist/{editorErrors-BY4Pdg7a.js.map → editorErrors-DXNfVXtD.js.map} +1 -1
  36. package/dist/embed-Cdbjay9i.js +961 -0
  37. package/dist/embed-Cdbjay9i.js.map +1 -0
  38. package/dist/embed.mjs +5 -5
  39. package/dist/index.mjs +7 -7
  40. package/dist/internals.mjs +12 -12
  41. package/dist/{template-fields-Z9x13sjM.js → template-fields-DgoBtajp.js} +266 -240
  42. package/dist/template-fields-DgoBtajp.js.map +1 -0
  43. package/dist/testing.mjs +3 -3
  44. package/dist/{usePieceGuideBundle-C1ipFnZd.js → usePieceGuideBundle-DVOISsB1.js} +2 -2
  45. package/dist/{usePieceGuideBundle-C1ipFnZd.js.map → usePieceGuideBundle-DVOISsB1.js.map} +1 -1
  46. package/dist/validation-0IscSfRb.js +9304 -0
  47. package/dist/validation-0IscSfRb.js.map +1 -0
  48. package/package.json +1 -1
  49. package/dist/EditorCanvasImpl-DgXvuWXX.js +0 -70
  50. package/dist/EditorCanvasImpl-DgXvuWXX.js.map +0 -1
  51. package/dist/EditorContext-CGkfmbgo.js +0 -1178
  52. package/dist/ElementFactory-CuHSAPfg.js.map +0 -1
  53. package/dist/FontAnalyzer-CLv7_msL.js.map +0 -1
  54. package/dist/ImportManager-C_wBjWaV.js.map +0 -1
  55. package/dist/SnowconeCanvas-wdckG-6O.js +0 -1179
  56. package/dist/SnowconeCanvas-wdckG-6O.js.map +0 -1
  57. package/dist/UnifiedFontService-Dsu5cwfT.js +0 -1478
  58. package/dist/UnifiedFontService-Dsu5cwfT.js.map +0 -1
  59. package/dist/embed-32ZVWfmj.js +0 -746
  60. package/dist/embed-32ZVWfmj.js.map +0 -1
  61. package/dist/iconify-D6eVIEy4.js +0 -1089
  62. package/dist/iconify-D6eVIEy4.js.map +0 -1
  63. package/dist/template-fields-Z9x13sjM.js.map +0 -1
  64. package/dist/validation-C795COGQ.js +0 -19959
  65. package/dist/validation-C795COGQ.js.map +0 -1
@@ -35,7 +35,7 @@
35
35
  * @packageDocumentation
36
36
  */
37
37
  export { Editor, DesignStateStore } from '../components/editor/index.js';
38
- export type { EditorRootProps, EditorRootBaseProps, EditorCanvasProps, EditorPreviewProps, EditorTextFieldProps, EditorBuyProps, EditorBuyPayload, BuyMissingReason, DesignState, } from '../components/editor/index.js';
38
+ export type { EditorRootProps, EditorRootBaseProps, EditorCanvasProps, EditorPreviewProps, EditorTextFieldProps, EditorBuyProps, EditorBuyPayload, BuyMissingReason, DesignState, EditorLayersProps, EditorControlsProps, EditorHistoryProps, EditorMenuProps, EditorAddProps, } from '../components/editor/index.js';
39
39
  export { EditorError, isEditorError } from '../errors/editorError.js';
40
40
  export type { EditorErrorCode, EditorErrorData } from '../errors/editorError.js';
41
41
  export { RealtimeEmbed } from '../components/embed-realtime/RealtimeEmbed.js';
@@ -155,6 +155,14 @@ export interface ContextualToolbarsProps {
155
155
  * this and the ambient context applies; passing it explicitly wins either way.
156
156
  */
157
157
  services?: CanvasServices;
158
+ /**
159
+ * `data-sc-part` value for the toolbar root (the Editor.* parts contract,
160
+ * ADR-0085 §5 — the class-3 floating toolbar is themable and selectable via
161
+ * `data-sc-part` even though the host doesn't position it). Set by the
162
+ * canvas's built-in floating mount; omitted everywhere else.
163
+ * @internal
164
+ */
165
+ partAttr?: string;
158
166
  }
159
167
  export declare const ContextualToolbars: React.FC<ContextualToolbarsProps>;
160
168
  export default ContextualToolbars;
@@ -0,0 +1,11 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ export interface EditorAddProps {
3
+ className?: string;
4
+ style?: CSSProperties;
5
+ }
6
+ /**
7
+ * The ⊕ add-element menu.
8
+ *
9
+ * @experimental ADR-0085; subject to change until the P4 gate.
10
+ */
11
+ export declare function EditorAdd({ className, style }: EditorAddProps): React.ReactElement;
@@ -26,6 +26,12 @@ export interface EditorCanvasImplProps {
26
26
  selfScope?: boolean;
27
27
  /** `data-sc-part` value for the wrapping div (the parts contract). */
28
28
  partAttr?: string;
29
+ /** Mount the built-in floating contextual toolbar (ADR-0085 §5: with no
30
+ * `Editor.Controls` mounted, `Editor.Canvas` defaults to the floating
31
+ * toolbar; a registered DOCKED Controls suppresses it). Set by
32
+ * `Editor.Canvas` only — the legacy `<RealtimeCanvas>` wrapper keeps
33
+ * today's chrome-less behavior. @internal */
34
+ builtinControls?: boolean;
29
35
  className?: string;
30
36
  style?: CSSProperties;
31
37
  }
@@ -0,0 +1,14 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ export interface EditorControlsProps {
3
+ /** Where the contextual zone lives (ADR-0085 §5). The host docks the part
4
+ * by where it renders it — there is deliberately no "bottom"/"top" value. */
5
+ placement?: 'docked' | 'floating';
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /**
10
+ * The contextual controls zone.
11
+ *
12
+ * @experimental ADR-0085; subject to change until the P4 gate.
13
+ */
14
+ export declare function EditorControls({ placement, className, style, }: EditorControlsProps): React.ReactElement | null;
@@ -0,0 +1,11 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ export interface EditorHistoryProps {
3
+ className?: string;
4
+ style?: CSSProperties;
5
+ }
6
+ /**
7
+ * Undo/redo for the editor document.
8
+ *
9
+ * @experimental ADR-0085; subject to change until the P4 gate.
10
+ */
11
+ export declare function EditorHistory({ className, style }: EditorHistoryProps): React.ReactElement;
@@ -0,0 +1,16 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ export interface EditorLayersProps {
3
+ /** Flow direction of the canvas-free list (the wrapped document panel is a
4
+ * vertical column). Default `'vertical'`. */
5
+ direction?: 'vertical' | 'horizontal';
6
+ className?: string;
7
+ style?: CSSProperties;
8
+ }
9
+ /**
10
+ * Layer list. Canvas-free (the no-canvas composition shows the design's
11
+ * layers read-only); with a mounted `Editor.Canvas` it is the live document
12
+ * panel.
13
+ *
14
+ * @experimental ADR-0085; subject to change until the P4 gate.
15
+ */
16
+ export declare function EditorLayers({ direction, className, style, }: EditorLayersProps): React.ReactElement;
@@ -0,0 +1,11 @@
1
+ import { default as React, CSSProperties } from 'react';
2
+ export interface EditorMenuProps {
3
+ className?: string;
4
+ style?: CSSProperties;
5
+ }
6
+ /**
7
+ * The editor's overflow menu.
8
+ *
9
+ * @experimental ADR-0085; subject to change until the P4 gate.
10
+ */
11
+ export declare function EditorMenu({ className, style }: EditorMenuProps): React.ReactElement;
@@ -17,6 +17,7 @@ export declare class EditorPartsRegistry {
17
17
  private canvasIds;
18
18
  private requirements;
19
19
  private textFields;
20
+ private controls;
20
21
  private bridge;
21
22
  private listeners;
22
23
  private version;
@@ -43,6 +44,12 @@ export declare class EditorPartsRegistry {
43
44
  getBoundLayer(name: string): {
44
45
  part: string;
45
46
  } | null;
47
+ /** `Editor.Controls` registration (ADR-0085 §5): a mounted DOCKED Controls
48
+ * suppresses the canvas's built-in floating contextual toolbar — one
49
+ * contextual zone at a time. `placement="floating"` registers without
50
+ * suppressing (it declares today's default explicitly). */
51
+ registerControls(instanceId: string, placement: 'docked' | 'floating'): () => void;
52
+ hasDockedControls(): boolean;
46
53
  registerCanvasBridge(bridge: CanvasBridge): () => void;
47
54
  getCanvasBridge(): CanvasBridge | null;
48
55
  private bump;
@@ -2,6 +2,11 @@ import { EditorRoot } from './EditorRoot.js';
2
2
  import { EditorPreview } from './EditorPreview.js';
3
3
  import { EditorTextField } from './EditorTextField.js';
4
4
  import { EditorBuy } from './EditorBuy.js';
5
+ import { EditorLayers } from './EditorLayers.js';
6
+ import { EditorControls } from './EditorControls.js';
7
+ import { EditorHistory } from './EditorHistory.js';
8
+ import { EditorMenu } from './EditorMenu.js';
9
+ import { EditorAdd } from './EditorAdd.js';
5
10
  export declare const Editor: {
6
11
  /** The one provider boundary — session, design, live state, error boundary. */
7
12
  readonly Root: typeof EditorRoot;
@@ -13,6 +18,16 @@ export declare const Editor: {
13
18
  readonly TextField: typeof EditorTextField;
14
19
  /** Smart commerce part: completeness + payload assembly; submit = host callback. */
15
20
  readonly Buy: typeof EditorBuy;
21
+ /** Layer list. The one editor part that works canvas-free (ADR-0085 §4). */
22
+ readonly Layers: typeof EditorLayers;
23
+ /** Morphing contextual zone — ONE coarse part; placement docked|floating (§5). */
24
+ readonly Controls: typeof EditorControls;
25
+ /** Undo/redo controls. Requires Editor.Canvas. */
26
+ readonly History: typeof EditorHistory;
27
+ /** The one ⋯ overflow menu. Requires Editor.Canvas. */
28
+ readonly Menu: typeof EditorMenu;
29
+ /** The ⊕ add-element menu. Requires Editor.Canvas. */
30
+ readonly Add: typeof EditorAdd;
16
31
  };
17
32
  export type { EditorRootProps, EditorRootBaseProps, GrantSource } from './EditorRoot.js';
18
33
  export type { EditorCanvasProps } from './EditorCanvas.js';
@@ -21,3 +36,8 @@ export type { EditorTextFieldProps } from './EditorTextField.js';
21
36
  export type { EditorBuyProps, EditorBuyPayload, BuyMissingReason } from './EditorBuy.js';
22
37
  export type { DesignState } from './designStateStore.js';
23
38
  export { DesignStateStore } from './designStateStore.js';
39
+ export type { EditorLayersProps } from './EditorLayers.js';
40
+ export type { EditorControlsProps } from './EditorControls.js';
41
+ export type { EditorHistoryProps } from './EditorHistory.js';
42
+ export type { EditorMenuProps } from './EditorMenu.js';
43
+ export type { EditorAddProps } from './EditorAdd.js';
@@ -0,0 +1,9 @@
1
+ import { default as React } from 'react';
2
+ export interface AddElementType {
3
+ /** The element type passed to `handleAddElement` ('shape' opens the
4
+ * shape-type drawer first instead of defaulting to a rectangle). */
5
+ type: string;
6
+ label: string;
7
+ icon: React.ReactNode;
8
+ }
9
+ export declare const ADD_ELEMENT_TYPES: AddElementType[];
@@ -106,6 +106,28 @@ export interface EditorContextValue {
106
106
  isCanvasReady: boolean;
107
107
  setCanvasReady: (ready: boolean) => void;
108
108
  }
109
+ /**
110
+ * Stable lazy access to the latest {@link EditorContextValue} — re-render
111
+ * containment for chrome that needs editor state only inside EVENT HANDLERS
112
+ * (save, export, add-element), never at render time (ADR-0085 / D3:
113
+ * subscribing to the fat context re-renders on every editor change, including
114
+ * each keystroke routed through the command path).
115
+ *
116
+ * The provided object's identity NEVER changes; `get()` returns the value as
117
+ * of the provider's latest render. Do not render from it — anything read at
118
+ * render time will go stale without a re-render. For reactive reads use the
119
+ * narrow sub-context hooks instead.
120
+ */
121
+ export interface EditorHandles {
122
+ /** The latest full editor context value (lazy — call inside handlers). */
123
+ get(): EditorContextValue;
124
+ }
125
+ /**
126
+ * Read the stable editor handles. Same provider requirement as `useEditor()`.
127
+ *
128
+ * @throws {Error} If called outside of an `EditorProvider`
129
+ */
130
+ export declare const useEditorHandles: () => EditorHandles;
109
131
  /** Props for {@link EditorProvider}. */
110
132
  export interface EditorProviderProps {
111
133
  children: ReactNode;
@@ -155,6 +177,22 @@ export declare const EditorProvider: React.FC<EditorProviderProps>;
155
177
  /**
156
178
  * Access the full editor context: elements, selection, artboards, history, and operations.
157
179
  *
180
+ * ## Stability contract (ADR-0085)
181
+ *
182
+ * `useEditor()` is the headless floor of the `Editor.*` primitives. Its v1
183
+ * STABLE subset — pinned by the type-level snapshot in
184
+ * `components/editor/__tests__/useEditorStableSubset.test.ts` — is:
185
+ *
186
+ * - **Elements**: `elements`, `elementStore`, `getElementById`
187
+ * - **Selection**: `selectedId`, `multiSelection`, `selectedElement`,
188
+ * `setSelectedId`, `setMultiSelection`, `handleSelectionChange`
189
+ * - **Command execution**: `executeElementUpdate`, `executeAddElement`,
190
+ * `executeRemoveElement`, `executeReorderElement`, `executeCommandBatch`
191
+ * - **Undo/redo**: `undo`, `redo`, `canUndo`, `canRedo`
192
+ *
193
+ * Everything else on the returned value is `@experimental` and may change in
194
+ * minors until the P4 gate (the default editor rebuilt from public parts).
195
+ *
158
196
  * Must be called inside an `EditorProvider`. For focused access, prefer the
159
197
  * sub-context hooks which expose smaller slices of state and cause fewer re-renders:
160
198
  *
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Layer-preview registry — the dependency-inversion seam between the layer
3
+ * panels (always-mountable chrome: `Editor.Layers` / `embed/LayersPanel`) and
4
+ * the rendering engine, extending the P1 element/renderer split
5
+ * (`core/paint-registry.ts`).
6
+ *
7
+ * `useLayers` / `useLayerPreview` used to statically import
8
+ * `utils/ElementPreviewRenderer`, dragging the whole paint pipeline into any
9
+ * graph that shows a layers panel — which would put the renderer in
10
+ * `Editor.Layers`' always-mounted graph (CI-gated renderer-free by
11
+ * scripts/check-import-graph.mjs). Inversion: the panels look the preview
12
+ * painter up HERE at preview time; the heavy side
13
+ * (`src/rendering/element-painters.ts`, inside `Editor.Canvas`'s lazy chunk)
14
+ * registers it at module evaluation.
15
+ *
16
+ * Contract difference from the paint registry: a MISS here is a legitimate
17
+ * state, not a wiring bug. Thumbnails are an enhancement that needs the
18
+ * rendering engine — a canvas-free composition (no `Editor.Canvas` mounted)
19
+ * has no painter and the panels fall back to their icon placeholder. So the
20
+ * getter returns `null` instead of throwing.
21
+ */
22
+ export interface ElementPreviewOptions {
23
+ width?: number;
24
+ height?: number;
25
+ padding?: number;
26
+ backgroundColor?: string;
27
+ }
28
+ /** Renders a thumbnail data-URL for one live editor element. Structural
29
+ * `object` on purpose so this module never imports an element class. */
30
+ export type ElementPreviewPainter = (element: object, options?: ElementPreviewOptions) => string;
31
+ export declare function registerElementPreviewPainter(painter: ElementPreviewPainter): void;
32
+ /** The registered preview painter, or `null` while the rendering engine is
33
+ * not loaded (the canvas-free fallback — render the icon placeholder). */
34
+ export declare function getElementPreviewPainter(): ElementPreviewPainter | null;
@@ -1,4 +1,4 @@
1
- import { h as n, i as t } from "./EditorContext-CGkfmbgo.js";
1
+ import { h as n, i as t } from "./EditorContext-5QpqAhjh.js";
2
2
  const r = [];
3
3
  function i(e) {
4
4
  t() && r.push(e);
@@ -26,4 +26,4 @@ export {
26
26
  d as g,
27
27
  i as r
28
28
  };
29
- //# sourceMappingURL=editorErrors-BY4Pdg7a.js.map
29
+ //# sourceMappingURL=editorErrors-DXNfVXtD.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editorErrors-BY4Pdg7a.js","sources":["../src/testing/editorErrors.ts"],"sourcesContent":["/**\n * Test-side hooks into the `Editor.*` error contract (ADR-0085 / D11).\n *\n * Containment is a PROD feature: under `NODE_ENV=test`, Root's boundary\n * rethrows render-time composition errors, so a broken composition fails the\n * test naturally. The remaining blind spot is the NON-throwing channel —\n * runtime failures routed straight to the error card (e.g. the lazy renderer\n * chunk failing to load, `E_CHUNK_LOAD_FAILED`) and prod-routed handler\n * invariants. Those are recorded here in test envs so\n * {@link expectNoEditorErrors} can fail a green-looking test that actually\n * rendered an error card.\n *\n * ```ts\n * import { expectNoEditorErrors } from '@snowcone-app/canvas/testing';\n *\n * afterEach(() => expectNoEditorErrors());\n * ```\n */\n\nimport { isEditorError, isDevOrTest } from '../errors/editorError.js';\n\nconst recorded: Error[] = [];\n\n/** Record a contained editor error (test/dev envs only). @internal */\nexport function recordContainedEditorError(error: Error): void {\n if (isDevOrTest()) recorded.push(error);\n}\n\n/** Errors contained since the last drain, without draining. */\nexport function getContainedEditorErrors(): readonly Error[] {\n return [...recorded];\n}\n\n/** Drop all recorded errors (e.g. after asserting an EXPECTED failure). */\nexport function resetContainedEditorErrors(): void {\n recorded.length = 0;\n}\n\n/**\n * Assert that no editor error was contained (rendered as an error card)\n * since the last reset/call. Drains the record either way so one leaked\n * error doesn't fail every later test in the file.\n */\nexport function expectNoEditorErrors(): void {\n if (recorded.length === 0) return;\n const summary = recorded\n .map((e) => (isEditorError(e) ? `${e.code}: ${e.message}` : `${e.name}: ${e.message}`))\n .join('\\n - ');\n recorded.length = 0;\n throw new Error(\n `expectNoEditorErrors: ${summary.includes('\\n') ? 'errors were' : 'an error was'} contained by ` +\n `<Editor.Root>'s boundary during this test:\\n - ${summary}\\n` +\n 'A contained error renders an error card in prod — this composition is broken even if the test rendered \"successfully\".',\n );\n}\n"],"names":["recorded","recordContainedEditorError","error","isDevOrTest","getContainedEditorErrors","resetContainedEditorErrors","expectNoEditorErrors","summary","e","isEditorError"],"mappings":";AAqBA,MAAMA,IAAoB,CAAA;AAGnB,SAASC,EAA2BC,GAAoB;AAC7D,EAAIC,EAAA,KAAeH,EAAS,KAAKE,CAAK;AACxC;AAGO,SAASE,IAA6C;AAC3D,SAAO,CAAC,GAAGJ,CAAQ;AACrB;AAGO,SAASK,IAAmC;AACjD,EAAAL,EAAS,SAAS;AACpB;AAOO,SAASM,IAA6B;AAC3C,MAAIN,EAAS,WAAW,EAAG;AAC3B,QAAMO,IAAUP,EACb,IAAI,CAACQ,MAAOC,EAAcD,CAAC,IAAI,GAAGA,EAAE,IAAI,KAAKA,EAAE,OAAO,KAAK,GAAGA,EAAE,IAAI,KAAKA,EAAE,OAAO,EAAG,EACrF,KAAK;AAAA,KAAQ;AAChB,QAAAR,EAAS,SAAS,GACZ,IAAI;AAAA,IACR,yBAAyBO,EAAQ,SAAS;AAAA,CAAI,IAAI,gBAAgB,cAAc;AAAA,MAC3BA,CAAO;AAAA;AAAA,EAAA;AAGhE;"}
1
+ {"version":3,"file":"editorErrors-DXNfVXtD.js","sources":["../src/testing/editorErrors.ts"],"sourcesContent":["/**\n * Test-side hooks into the `Editor.*` error contract (ADR-0085 / D11).\n *\n * Containment is a PROD feature: under `NODE_ENV=test`, Root's boundary\n * rethrows render-time composition errors, so a broken composition fails the\n * test naturally. The remaining blind spot is the NON-throwing channel —\n * runtime failures routed straight to the error card (e.g. the lazy renderer\n * chunk failing to load, `E_CHUNK_LOAD_FAILED`) and prod-routed handler\n * invariants. Those are recorded here in test envs so\n * {@link expectNoEditorErrors} can fail a green-looking test that actually\n * rendered an error card.\n *\n * ```ts\n * import { expectNoEditorErrors } from '@snowcone-app/canvas/testing';\n *\n * afterEach(() => expectNoEditorErrors());\n * ```\n */\n\nimport { isEditorError, isDevOrTest } from '../errors/editorError.js';\n\nconst recorded: Error[] = [];\n\n/** Record a contained editor error (test/dev envs only). @internal */\nexport function recordContainedEditorError(error: Error): void {\n if (isDevOrTest()) recorded.push(error);\n}\n\n/** Errors contained since the last drain, without draining. */\nexport function getContainedEditorErrors(): readonly Error[] {\n return [...recorded];\n}\n\n/** Drop all recorded errors (e.g. after asserting an EXPECTED failure). */\nexport function resetContainedEditorErrors(): void {\n recorded.length = 0;\n}\n\n/**\n * Assert that no editor error was contained (rendered as an error card)\n * since the last reset/call. Drains the record either way so one leaked\n * error doesn't fail every later test in the file.\n */\nexport function expectNoEditorErrors(): void {\n if (recorded.length === 0) return;\n const summary = recorded\n .map((e) => (isEditorError(e) ? `${e.code}: ${e.message}` : `${e.name}: ${e.message}`))\n .join('\\n - ');\n recorded.length = 0;\n throw new Error(\n `expectNoEditorErrors: ${summary.includes('\\n') ? 'errors were' : 'an error was'} contained by ` +\n `<Editor.Root>'s boundary during this test:\\n - ${summary}\\n` +\n 'A contained error renders an error card in prod — this composition is broken even if the test rendered \"successfully\".',\n );\n}\n"],"names":["recorded","recordContainedEditorError","error","isDevOrTest","getContainedEditorErrors","resetContainedEditorErrors","expectNoEditorErrors","summary","e","isEditorError"],"mappings":";AAqBA,MAAMA,IAAoB,CAAA;AAGnB,SAASC,EAA2BC,GAAoB;AAC7D,EAAIC,EAAA,KAAeH,EAAS,KAAKE,CAAK;AACxC;AAGO,SAASE,IAA6C;AAC3D,SAAO,CAAC,GAAGJ,CAAQ;AACrB;AAGO,SAASK,IAAmC;AACjD,EAAAL,EAAS,SAAS;AACpB;AAOO,SAASM,IAA6B;AAC3C,MAAIN,EAAS,WAAW,EAAG;AAC3B,QAAMO,IAAUP,EACb,IAAI,CAACQ,MAAOC,EAAcD,CAAC,IAAI,GAAGA,EAAE,IAAI,KAAKA,EAAE,OAAO,KAAK,GAAGA,EAAE,IAAI,KAAKA,EAAE,OAAO,EAAG,EACrF,KAAK;AAAA,KAAQ;AAChB,QAAAR,EAAS,SAAS,GACZ,IAAI;AAAA,IACR,yBAAyBO,EAAQ,SAAS;AAAA,CAAI,IAAI,gBAAgB,cAAc;AAAA,MAC3BA,CAAO;AAAA;AAAA,EAAA;AAGhE;"}