@snowcone-app/canvas 0.17.1 → 0.17.3

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/{CanvasStateV1-C6i6vU6p.js → CanvasStateV1-BG2hEc3-.js} +3 -3
  2. package/dist/{CanvasStateV1-C6i6vU6p.js.map → CanvasStateV1-BG2hEc3-.js.map} +1 -1
  3. package/dist/EditorCanvasImpl-DQxqdgpq.js +70 -0
  4. package/dist/EditorCanvasImpl-DQxqdgpq.js.map +1 -0
  5. package/dist/EditorContext-CGkfmbgo.js +1178 -0
  6. package/dist/EditorContext-CGkfmbgo.js.map +1 -0
  7. package/dist/{ElementFactory-C05JJkRp.js → ElementFactory-CuHSAPfg.js} +1469 -710
  8. package/dist/ElementFactory-CuHSAPfg.js.map +1 -0
  9. package/dist/{HybridHistoryManager-Bht98XRv.js → FontAnalyzer-CLv7_msL.js} +2104 -2903
  10. package/dist/FontAnalyzer-CLv7_msL.js.map +1 -0
  11. package/dist/{ImportManager-kRYfIX-D.js → ImportManager-C_wBjWaV.js} +147 -147
  12. package/dist/{ImportManager-kRYfIX-D.js.map → ImportManager-C_wBjWaV.js.map} +1 -1
  13. package/dist/SnowconeCanvas-DBbmx9qW.js +1187 -0
  14. package/dist/SnowconeCanvas-DBbmx9qW.js.map +1 -0
  15. package/dist/{UnifiedFontService-BAtqqkU4.js → UnifiedFontService-Dsu5cwfT.js} +141 -141
  16. package/dist/UnifiedFontService-Dsu5cwfT.js.map +1 -0
  17. package/dist/advanced.mjs +10 -10
  18. package/dist/components/editor/RootInternals.d.ts +7 -0
  19. package/dist/components/embed/EmbedRoot.d.ts +23 -0
  20. package/dist/components/embed/SnowconeCanvas.d.ts +13 -0
  21. package/dist/components/embed/kernel.d.ts +114 -0
  22. package/dist/contexts/BoundLayerGuardContext.d.ts +36 -0
  23. package/dist/core/GroupElement.d.ts +0 -5
  24. package/dist/core/TextElement.d.ts +8 -3
  25. package/dist/core/paint-registry.d.ts +42 -0
  26. package/dist/core/rich-text-layout.d.ts +28 -0
  27. package/dist/{editorErrors-DbIEtCTt.js → editorErrors-BY4Pdg7a.js} +2 -2
  28. package/dist/{editorErrors-DbIEtCTt.js.map → editorErrors-BY4Pdg7a.js.map} +1 -1
  29. package/dist/{embed-B5kewSQY.js → embed--B8ot6Lj.js} +207 -199
  30. package/dist/embed--B8ot6Lj.js.map +1 -0
  31. package/dist/embed.mjs +21 -22
  32. package/dist/embed.mjs.map +1 -1
  33. package/dist/index.mjs +7 -7
  34. package/dist/internals.mjs +93 -93
  35. package/dist/rendering/element-painters.d.ts +16 -0
  36. package/dist/rendering/rich-text-renderer.d.ts +3 -28
  37. package/dist/{template-fields-GOM4MNfq.js → template-fields-Z9x13sjM.js} +32 -33
  38. package/dist/{template-fields-GOM4MNfq.js.map → template-fields-Z9x13sjM.js.map} +1 -1
  39. package/dist/testing.mjs +7 -7
  40. package/dist/transforms/ArchTransform.d.ts +0 -1
  41. package/dist/transforms/AscendTransform.d.ts +0 -1
  42. package/dist/transforms/CircleTransform.d.ts +0 -1
  43. package/dist/transforms/FlagTransform.d.ts +0 -1
  44. package/dist/transforms/LeanTransform.d.ts +0 -1
  45. package/dist/transforms/WaveTransform.d.ts +0 -1
  46. package/dist/{usePieceGuideBundle-CGERAQJl.js → usePieceGuideBundle-C1ipFnZd.js} +2 -2
  47. package/dist/{usePieceGuideBundle-CGERAQJl.js.map → usePieceGuideBundle-C1ipFnZd.js.map} +1 -1
  48. package/dist/{validation-DEd6EOCP.js → validation-C795COGQ.js} +4803 -4791
  49. package/dist/validation-C795COGQ.js.map +1 -0
  50. package/dist/vendor/ui/primitives/kbd.d.ts +1 -1
  51. package/dist/workers/export-worker.bundle.string.d.ts +1 -1
  52. package/package.json +1 -1
  53. package/dist/EditorCanvasImpl-C8SsT3C2.js +0 -68
  54. package/dist/EditorCanvasImpl-C8SsT3C2.js.map +0 -1
  55. package/dist/EditorContext-CyanYzo2.js +0 -1131
  56. package/dist/EditorContext-CyanYzo2.js.map +0 -1
  57. package/dist/ElementFactory-C05JJkRp.js.map +0 -1
  58. package/dist/HybridHistoryManager-Bht98XRv.js.map +0 -1
  59. package/dist/SnowconeCanvas-C3eZ9PP8.js +0 -1047
  60. package/dist/SnowconeCanvas-C3eZ9PP8.js.map +0 -1
  61. package/dist/UnifiedFontService-BAtqqkU4.js.map +0 -1
  62. package/dist/editorError-DMENTZ-3.js +0 -19
  63. package/dist/editorError-DMENTZ-3.js.map +0 -1
  64. package/dist/embed-B5kewSQY.js.map +0 -1
  65. package/dist/validation-DEd6EOCP.js.map +0 -1
@@ -0,0 +1,114 @@
1
+ import { default as React } from 'react';
2
+ import { CanvasError, AnyElementConfig } from '../../types/index.js';
3
+ import { AlignmentPoint, ArtboardConfig, CanvasState, ExportStatusEvent, PieceGuidesConfig, SnowconeCanvasHandle } from './SnowconeCanvas.js';
4
+ export type ImageLoadingState = 'idle' | 'loading' | 'success' | 'error';
5
+ /**
6
+ * Calculate the effective export scale for an artboard.
7
+ * If the scaled dimensions would exceed maxSize, reduces the scale to cap at maxSize.
8
+ *
9
+ * @param width - Artboard width in pixels
10
+ * @param height - Artboard height in pixels
11
+ * @param requestedScale - The requested export scale multiplier
12
+ * @param maxSize - Maximum dimension (largest side) for exported image
13
+ * @returns The effective scale to use (may be lower than requestedScale)
14
+ */
15
+ export declare function calculateEffectiveScale(width: number, height: number, requestedScale: number, maxSize: number): number;
16
+ /**
17
+ * Error channel: structured `onError` emission + the CanvasRenderer static
18
+ * render-error wire + the ErrorBoundary handler.
19
+ */
20
+ export declare function useCanvasErrorChannel(onError: ((error: CanvasError) => void) | undefined): {
21
+ emitError: (error: CanvasError) => void;
22
+ handleBoundaryError: (error: Error) => void;
23
+ };
24
+ export interface ArtboardKernelOptions {
25
+ artboardConfigs: ArtboardConfig[] | undefined;
26
+ width: number;
27
+ height: number;
28
+ pieceGuides: PieceGuidesConfig | undefined;
29
+ controlledActiveArtboard: string | undefined;
30
+ onArtboardChange: ((name: string) => void) | undefined;
31
+ /**
32
+ * Rebuild the editor document from scratch on mount (clear artboards +
33
+ * elements first). Used by `Editor.Canvas`: with the P1 inversion the
34
+ * editor document lives at `Editor.Root` and OUTLIVES Canvas mounts, so a
35
+ * remount must reflect the live seed instead of accreting onto the previous
36
+ * mount's artboards/elements (the D8 soak cycles exactly this).
37
+ * @internal
38
+ */
39
+ resetDocumentOnMount?: boolean;
40
+ }
41
+ /**
42
+ * Artboard init + controlled `activeArtboard` sync + `onArtboardChange`.
43
+ */
44
+ export declare function useArtboardKernel(opts: ArtboardKernelOptions): void;
45
+ export interface InitialElementsKernelOptions {
46
+ initialElements: AnyElementConfig[] | undefined;
47
+ emitError: (error: CanvasError) => void;
48
+ }
49
+ /**
50
+ * Restore saved state (`initialElements`) onto the named artboards, then
51
+ * best-effort load the referenced fonts and force one repaint.
52
+ */
53
+ export declare function useInitialElementsKernel(opts: InitialElementsKernelOptions): {
54
+ initialElementsLoadedState: boolean;
55
+ };
56
+ export interface InitialImageKernelOptions {
57
+ initialImage: string | undefined;
58
+ initialImageAlignment: AlignmentPoint;
59
+ initialImageScale: number;
60
+ initialImageScaleMode: 'cover' | 'contain';
61
+ artboardConfigs: ArtboardConfig[] | undefined;
62
+ onImageLoad: ((src: string) => void) | undefined;
63
+ onImageError: ((src: string, error: Error) => void) | undefined;
64
+ emitError: (error: CanvasError) => void;
65
+ }
66
+ /**
67
+ * Load `initialImage` into every artboard with cover/contain placement.
68
+ */
69
+ export declare function useInitialImageKernel(opts: InitialImageKernelOptions): {
70
+ imageLoadingState: ImageLoadingState;
71
+ imageError: Error | null;
72
+ };
73
+ export interface ChangeCallbacksKernelOptions {
74
+ onChange: ((state: CanvasState) => void) | undefined;
75
+ onSelectionChange: ((elementId: string | null) => void) | undefined;
76
+ }
77
+ /**
78
+ * `onChange` / `onSelectionChange` emission. Both fire through latest-refs so
79
+ * an inline callback (a fresh closure identity on every host render) can't
80
+ * re-trigger the effects — the component must not require consumers to
81
+ * memoize their callbacks. Depending on the callback identity turns "callback
82
+ * updates host state" into an infinite render loop; depending only on the
83
+ * DATA fires exactly when the canvas actually changes. Pinned by
84
+ * SnowconeCanvas.onChange-loop.test.tsx.
85
+ */
86
+ export declare function useChangeCallbacksKernel(opts: ChangeCallbacksKernelOptions): void;
87
+ export interface ExportKernelOptions {
88
+ autoExportInterval: number | undefined;
89
+ autoExportConfig: {
90
+ enabled?: boolean;
91
+ debounceMs?: number;
92
+ maxWaitMs?: number;
93
+ } | undefined;
94
+ autoExportFormat: 'dataUrl' | 'blob';
95
+ autoExportAll: boolean;
96
+ exportScale: number;
97
+ maxExportSize: number;
98
+ exportImageFormat: 'png' | 'jpg' | 'jpeg' | 'webp';
99
+ exportImageQuality: number;
100
+ onExport: ((exports: Record<string, string | Blob>) => void) | undefined;
101
+ onExportScheduled: (() => void) | undefined;
102
+ onExportStatus: ((event: ExportStatusEvent) => void) | undefined;
103
+ onExportReady: ((exportFn: () => Promise<Record<string, string | Blob>>) => void) | undefined;
104
+ onReady: (() => void) | undefined;
105
+ hasInitialElements: boolean;
106
+ initialElementsLoaded: boolean;
107
+ emitError: (error: CanvasError) => void;
108
+ }
109
+ /**
110
+ * Export kernel: the imperative `exportArtboards` handle, `onExportReady`,
111
+ * smart auto-export (debounced, change-detected), content readiness, the
112
+ * `onReady` signal, and the canvas-ready gate.
113
+ */
114
+ export declare function useExportKernel(opts: ExportKernelOptions, ref: React.ForwardedRef<SnowconeCanvasHandle>): void;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Bound-layer mutation guard (ADR-0085 §3, enforced in P1).
3
+ *
4
+ * While an `Editor.TextField` is registered for layer N, renaming or deleting
5
+ * layer N must be impossible: the editor UI suppresses the affordances, and
6
+ * the programmatic command path throws `E_BOUND_LAYER_MUTATION` naming the
7
+ * bound part — so an end-user gesture can never detonate the prod error card
8
+ * (the invalid state is unreachable from the UI), while agent/host code gets
9
+ * a loud structured throw.
10
+ *
11
+ * `Editor.Root` provides its parts registry through this context ABOVE
12
+ * `EditorProvider`, so the command layer (`useCommandHistory`) and the chrome
13
+ * (LayersPanel, keyboard shortcuts) can consult it. Without a Root (legacy
14
+ * standalone `SnowconeCanvas`) the context is null and nothing changes.
15
+ *
16
+ * This module is deliberately dependency-free: it sits in the always-mounted
17
+ * Editor.Root graph (renderer-free, CI-gated) and is imported by both the
18
+ * contexts layer and the editor parts.
19
+ */
20
+ export interface BoundLayerGuard {
21
+ /** Subscribe to registry changes (TextFields mount/unmount). */
22
+ subscribe(listener: () => void): () => void;
23
+ /** Monotonic version for `useSyncExternalStore`. */
24
+ getVersion(): number;
25
+ /** The part bound to a layer name, or null when the layer is unbound. */
26
+ getBoundLayer(name: string): {
27
+ part: string;
28
+ } | null;
29
+ }
30
+ export declare const BoundLayerGuardContext: import('react').Context<BoundLayerGuard | null>;
31
+ /**
32
+ * Reactive bound-layer test for UI suppression: re-renders when TextFields
33
+ * mount/unmount, so rename/delete affordances appear the moment a layer
34
+ * stops being bound. Always returns false outside an `<Editor.Root>`.
35
+ */
36
+ export declare function useIsLayerBound(): (name: string | undefined) => boolean;
@@ -59,11 +59,6 @@ export declare class GroupElement extends BaseElement {
59
59
  * Elements with isClipping=true clip all elements below them in the group
60
60
  */
61
61
  render(ctx: CanvasRenderingContext2D, isSelected?: boolean, isHovered?: boolean): void;
62
- /**
63
- * Render group with clipping masks
64
- * Elements with isClipping=true clip all elements below them
65
- */
66
- private _renderWithClipping;
67
62
  /**
68
63
  * Render dashed outline around group
69
64
  * Uses an oriented bounding box that doesn't change size during rotation
@@ -20,10 +20,15 @@ export declare class TextElement extends BaseElement {
20
20
  */
21
21
  getBoundingBox(): BoundingBox;
22
22
  /**
23
- * Render the element
24
- * Must be implemented by subclasses
23
+ * Render the element.
24
+ *
25
+ * Paints through the paint registry (P1 element/renderer split): the shared
26
+ * paint function for this transformType is registered by the rendering
27
+ * engine (`src/rendering/element-painters.ts`), so the element model never
28
+ * statically imports the paint pipeline. Selection and hover visuals are
29
+ * handled by SelectionRenderer and HoverRenderer.
25
30
  */
26
- render(_ctx: CanvasRenderingContext2D, _isSelected?: boolean, _isHovered?: boolean): void;
31
+ render(ctx: CanvasRenderingContext2D, _isSelected?: boolean, _isHovered?: boolean): void;
27
32
  /**
28
33
  * Serialize to JSON
29
34
  */
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Paint registry — the dependency-inversion seam between the element MODEL
3
+ * and the rendering engine (ADR-0085 / D9, the P1 element/renderer split).
4
+ *
5
+ * The element classes (TextElement subclasses, GroupElement) are STATE: they
6
+ * mount with `Editor.Root` in every composition, including the no-canvas
7
+ * personalization widget, so their static import graph must stay renderer-free
8
+ * (CI-gated by scripts/check-import-graph.mjs). Their `render()` methods used
9
+ * to statically import the shared paint functions from `src/rendering/*`,
10
+ * dragging the whole paint pipeline into the always-mounted graph.
11
+ *
12
+ * Inversion: the model looks paint functions up HERE at paint time; the heavy
13
+ * side (`src/rendering/element-painters.ts`, inside `Editor.Canvas`'s lazy
14
+ * chunk) registers them at module evaluation. Every module that DRIVES element
15
+ * painting (CanvasRenderer, ExportManager, ElementPreviewRenderer) imports the
16
+ * painters module, so by the time any `element.render()` runs the registry is
17
+ * populated — a miss is an internal wiring bug, not a user-reachable state,
18
+ * and throws with the fix in the message.
19
+ */
20
+ /** Paints one serialized text-transform element. The serialized shape is the
21
+ * element's `toJSON()` output; the heavy side narrows it to its concrete
22
+ * Serialized*Element type. */
23
+ export type TextTransformPainter = (ctx: CanvasRenderingContext2D, serialized: object) => void;
24
+ /** The subset of an element the group-clipping compositor needs — structural
25
+ * on purpose so this module never imports an element class. */
26
+ export interface PaintableChild {
27
+ isClipping?: boolean;
28
+ transformType: string;
29
+ render(ctx: CanvasRenderingContext2D, isSelected?: boolean, isHovered?: boolean): void;
30
+ getBoundingBox(): {
31
+ x: number;
32
+ y: number;
33
+ width: number;
34
+ height: number;
35
+ };
36
+ }
37
+ /** Composites a group's children honoring `isClipping` masks. */
38
+ export type GroupClippingPainter = (ctx: CanvasRenderingContext2D, children: PaintableChild[]) => void;
39
+ export declare function registerTextTransformPainter(type: string, painter: TextTransformPainter): void;
40
+ export declare function getTextTransformPainter(type: string): TextTransformPainter;
41
+ export declare function registerGroupClippingPainter(painter: GroupClippingPainter): void;
42
+ export declare function getGroupClippingPainter(): GroupClippingPainter;
@@ -0,0 +1,28 @@
1
+ import { CharacterStyle, RichText } from '../types/index.js';
2
+ /**
3
+ * Wrap rich text spans to fit within a given width, preserving character-level formatting
4
+ *
5
+ * This function handles character-level formatting correctly by:
6
+ * 1. First merging consecutive spans with the same style
7
+ * 2. Finding word boundaries (spaces) across spans
8
+ * 3. Wrapping at word boundaries, not at span boundaries
9
+ */
10
+ export declare function wrapRichTextSpans(spans: Array<{
11
+ text: string;
12
+ style: CharacterStyle;
13
+ }>, maxWidth: number, element: {
14
+ fontSize: number;
15
+ fontFamily: string;
16
+ bold?: boolean;
17
+ italic?: boolean;
18
+ }): Array<{
19
+ text: string;
20
+ style: CharacterStyle;
21
+ }[]>;
22
+ /**
23
+ * Split rich text into lines by explicit newlines, preserving span formatting
24
+ */
25
+ export declare function splitRichTextIntoLines(richText: RichText): Array<{
26
+ text: string;
27
+ style: CharacterStyle;
28
+ }[]>;
@@ -1,4 +1,4 @@
1
- import { a as n, i as t } from "./editorError-DMENTZ-3.js";
1
+ import { h as n, i as t } from "./EditorContext-CGkfmbgo.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-DbIEtCTt.js.map
29
+ //# sourceMappingURL=editorErrors-BY4Pdg7a.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editorErrors-DbIEtCTt.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-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;"}