camox 0.69.0 → 0.72.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 (89) hide show
  1. package/dist/core/createApp.d.ts +4 -103
  2. package/dist/core/createApp.js +3 -24
  3. package/dist/core/createBlock.d.ts +2 -2
  4. package/dist/core/createBlock.js +55 -192
  5. package/dist/core/createLayout.d.ts +6 -77
  6. package/dist/core/createLayout.js +12 -50
  7. package/dist/core/editing/createEditableBlock.d.ts +9 -75
  8. package/dist/core/editing/createEditableBlock.js +258 -640
  9. package/dist/core/hooks/useArtifactHost.js +56 -46
  10. package/dist/core/hooks/useIsEditable.js +2 -2
  11. package/dist/core/lib/artifact.d.ts +4 -0
  12. package/dist/core/lib/artifactData.js +8 -3
  13. package/dist/core/lib/artifactHost.js +40 -0
  14. package/dist/core/lib/artifactRuntime.js +20 -1
  15. package/dist/core/lib/contentType.d.ts +23 -38
  16. package/dist/core/lib/contentType.js +34 -62
  17. package/dist/core/lib/iconTypes.d.ts +0 -3
  18. package/dist/core/lib/icons.js +63 -51
  19. package/dist/core/lib/recordScope.js +1 -1
  20. package/dist/features/canvas/CanvasOverlays.js +94 -176
  21. package/dist/features/canvas/CanvasPageFrame.js +62 -68
  22. package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -3
  23. package/dist/features/canvas/canvasOverlayGeometry.js +1 -7
  24. package/dist/features/canvas/sidebar/CuratedPageInspector.js +3 -21
  25. package/dist/features/canvas/sidebar/LayoutPageBlocks.js +1 -2
  26. package/dist/features/canvas/useCanvasCamera.js +1 -1
  27. package/dist/features/canvas/useCanvasFrame.js +1 -1
  28. package/dist/features/content/ContentCollection.js +2 -2
  29. package/dist/features/content/collection-form.js +6 -7
  30. package/dist/features/page/CuratedPageContent.js +15 -24
  31. package/dist/features/page/UnplacedBlockContent.js +1 -6
  32. package/dist/features/preview/CamoxPreview.js +30 -33
  33. package/dist/features/preview/EditablePageContent.js +131 -151
  34. package/dist/features/preview/components/BlockActionsPopover.js +43 -152
  35. package/dist/features/preview/components/CanvasPreview.js +2 -2
  36. package/dist/features/preview/components/Frame.js +3 -3
  37. package/dist/features/preview/components/IconFieldEditor.js +1 -1
  38. package/dist/features/preview/components/ItemFieldsEditor.js +1 -3
  39. package/dist/features/preview/components/Overlays.js +18 -84
  40. package/dist/features/preview/components/PageTree.js +57 -103
  41. package/dist/features/preview/components/PreviewPanel.js +8 -11
  42. package/dist/features/preview/components/RecordCombobox.js +65 -78
  43. package/dist/features/preview/components/ReferenceFieldEditor.js +1 -19
  44. package/dist/features/preview/components/ReferenceListFieldEditor.js +1 -19
  45. package/dist/features/preview/components/RemovedBlockPlaceholder.js +2 -2
  46. package/dist/features/preview/components/SelectionEditor.js +5 -4
  47. package/dist/features/preview/components/useRepeatableItemActions.js +18 -24
  48. package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
  49. package/dist/features/preview/overlayMessages.js +1 -4
  50. package/dist/features/preview/previewStore.js +3 -23
  51. package/dist/features/renderer/RendererApp.js +17 -141
  52. package/dist/features/renderer/definitionAnswers.js +1 -8
  53. package/dist/features/renderer/rendererHost.js +1 -31
  54. package/dist/features/renderer/studioConnection.js +1 -25
  55. package/dist/features/runtime/pageApp.js +8 -4
  56. package/dist/features/runtime/runtime.js +3 -3
  57. package/dist/features/studio/agentRunToast.js +71 -0
  58. package/dist/features/studio/components/ChatWidget.js +2 -0
  59. package/dist/features/studio/components/DraftBar.js +2 -3
  60. package/dist/features/studio/components/DraftsControl.js +150 -176
  61. package/dist/features/studio/components/ReviewDraftSheet.js +344 -548
  62. package/dist/features/studio/components/ThreadMessages.js +89 -22
  63. package/dist/features/studio/draftLabel.js +1 -1
  64. package/dist/features/studio/studioStore.js +5 -17
  65. package/dist/features/studio/viewSwitch.js +2 -4
  66. package/dist/features/vite/blockBoilerplate.js +1 -1
  67. package/dist/features/vite/definitionsSync.js +1 -8
  68. package/dist/lib/queries.js +0 -1
  69. package/dist/lib/studio-definitions.js +0 -2
  70. package/dist/lib/studio-reads.js +0 -5
  71. package/dist/lib/use-thread.js +196 -138
  72. package/dist/package.js +1 -1
  73. package/dist/studio-overlays.css +0 -29
  74. package/dist/studio.css +1 -1
  75. package/package.json +6 -4
  76. package/skills/camox/SKILL.md +1 -1
  77. package/skills/camox/references/artifacts.md +89 -5
  78. package/skills/camox/references/block-definitions.md +21 -25
  79. package/skills/camox/references/dom-integrations.md +1 -1
  80. package/skills/camox/references/layout-definitions.md +3 -12
  81. package/skills/camox/references/routed-layouts.md +2 -2
  82. package/skills/camox-expand/SKILL.md +5 -5
  83. package/skills/camoxify/SKILL.md +4 -4
  84. package/dist/features/canvas/canvasInsertionSeams.js +0 -44
  85. package/dist/features/preview/components/AddBlockSheet.js +0 -314
  86. package/dist/features/preview/components/BlockPeek.js +0 -66
  87. package/dist/features/preview/components/BlockThumbnail.js +0 -281
  88. package/dist/features/preview/components/blockGridNavigation.js +0 -15
  89. package/dist/features/preview/referencePickerFocus.js +0 -29
@@ -3,35 +3,31 @@ import { previewStore, sameEditingOwner } from "../previewStore.js";
3
3
  import { PreviewEditingOwnerContext } from "../previewSelection.js";
4
4
  import { c } from "react/compiler-runtime";
5
5
  import * as React from "react";
6
- import { generateKeyBetween } from "fractional-indexing";
6
+ import { emptyFieldValues } from "@camox/api-contract";
7
7
  import { useMutation } from "@tanstack/react-query";
8
+ import { generateKeyBetween } from "fractional-indexing";
8
9
 
9
10
  //#region src/features/preview/components/useRepeatableItemActions.ts
10
- const buildDefaultContent = (itemProperties) => {
11
- const content = {};
12
- if (!itemProperties) return content;
13
- for (const [key, prop] of Object.entries(itemProperties)) {
14
- if (prop.fieldType === "Image" || prop.fieldType === "File") continue;
15
- if (prop.type === "array" && prop.items?.properties) continue;
16
- if ("default" in prop) content[key] = prop.default;
17
- }
11
+ /** A new item's content: every field empty, except nested repeaters, whose items are rows. */
12
+ const emptyItemContent = (itemProperties) => {
13
+ const content = emptyFieldValues({ properties: itemProperties });
14
+ for (const [key, prop] of Object.entries(itemProperties ?? {})) if (prop.fieldType === "Repeater") delete content[key];
18
15
  return content;
19
16
  };
17
+ /** A new item's settings: every setting empty, or none when the repeater has no settings. */
18
+ const emptyItemSettings = (schema) => schema.itemSettingsSchema ? emptyFieldValues(schema.itemSettingsSchema) : void 0;
19
+ /** The empty items a new item's nested repeaters start with: as many as each requires. */
20
20
  const buildNestedItemSeeds = (itemProperties) => {
21
21
  const seeds = [];
22
22
  if (!itemProperties) return seeds;
23
23
  let counter = 0;
24
24
  const recurse = (properties, parentTempId) => {
25
25
  for (const [fieldName, fieldSchema] of Object.entries(properties)) {
26
- if (fieldSchema.type !== "array" || !fieldSchema.items?.properties) continue;
27
- if (fieldSchema.fieldType === "ImageList" || fieldSchema.fieldType === "FileList") continue;
28
- const defaultCount = fieldSchema.defaultItems ?? fieldSchema.minItems ?? 0;
29
- if (defaultCount <= 0) continue;
30
- const nestedItemProps = fieldSchema.items.properties;
31
- const nestedContent = buildDefaultContent(nestedItemProps);
32
- const nestedSettingsDefaults = fieldSchema.defaultItemSettings;
26
+ if (fieldSchema.fieldType !== "Repeater") continue;
27
+ const count = fieldSchema.minItems ?? 0;
28
+ const nestedItemProps = fieldSchema.items?.properties;
33
29
  let prevPos = null;
34
- for (let i = 0; i < defaultCount; i++) {
30
+ for (let i = 0; i < count; i++) {
35
31
  const tempId = `nested_${++counter}`;
36
32
  const position = generateKeyBetween(prevPos, null);
37
33
  prevPos = position;
@@ -39,11 +35,11 @@ const buildNestedItemSeeds = (itemProperties) => {
39
35
  tempId,
40
36
  parentTempId,
41
37
  fieldName,
42
- content: { ...nestedContent },
43
- settings: nestedSettingsDefaults ? { ...nestedSettingsDefaults } : void 0,
38
+ content: emptyItemContent(nestedItemProps),
39
+ settings: emptyItemSettings(fieldSchema),
44
40
  position
45
41
  });
46
- recurse(nestedItemProps, tempId);
42
+ if (nestedItemProps) recurse(nestedItemProps, tempId);
47
43
  }
48
44
  }
49
45
  };
@@ -74,15 +70,13 @@ const useRepeatableItemActions = (t0) => {
74
70
  if (owner === null) return;
75
71
  if (!arraySchema) return;
76
72
  const itemsSchema = arraySchema.items;
77
- const defaultContent = buildDefaultContent(itemsSchema?.properties);
78
- const defaultSettings = arraySchema.defaultItemSettings;
79
73
  const nestedItems = buildNestedItemSeeds(itemsSchema?.properties);
80
74
  createRepeatableItem.mutate({
81
75
  blockId,
82
76
  parentItemId: parentItemId ?? void 0,
83
77
  fieldName,
84
- content: defaultContent,
85
- settings: defaultSettings ? { ...defaultSettings } : void 0,
78
+ content: emptyItemContent(itemsSchema?.properties),
79
+ settings: emptyItemSettings(arraySchema),
86
80
  nestedItems: nestedItems.length > 0 ? nestedItems : void 0,
87
81
  afterPosition: options?.afterPosition
88
82
  }, { onSuccess: (created) => {
@@ -3,8 +3,8 @@ import { reads, useStudioCache } from "../../../lib/studio-reads.js";
3
3
  import { blockMutations } from "../../../lib/queries.js";
4
4
  import { useLocalePath } from "../../../lib/view-locale.js";
5
5
  import { c } from "react/compiler-runtime";
6
- import { generateKeyBetween } from "fractional-indexing";
7
6
  import { useMutation } from "@tanstack/react-query";
7
+ import { generateKeyBetween } from "fractional-indexing";
8
8
 
9
9
  //#region src/features/preview/components/useUpdateBlockPosition.ts
10
10
  function useUpdateBlockPosition() {
@@ -73,9 +73,6 @@ function selectionHoverMessage(selection, hovered) {
73
73
  function isOverlayMessage(data) {
74
74
  return typeof data === "object" && data !== null && "type" in data && typeof data.type === "string" && data.type.startsWith("CAMOX_");
75
75
  }
76
- function postOverlayMessage(message) {
77
- window.parent?.postMessage(message, "*");
78
- }
79
76
 
80
77
  //#endregion
81
- export { isOverlayMessage, overlayFieldId, postOverlayMessage, recordFieldId, recordPlacementId, selectionHoverMessage };
78
+ export { isOverlayMessage, overlayFieldId, recordFieldId, recordPlacementId, selectionHoverMessage };
@@ -97,7 +97,6 @@ const selectIsCanvasShown = (state) => state.context.view === "canvas";
97
97
  const initialPreviewContext = {
98
98
  view: "preview",
99
99
  isToolbarHidden: false,
100
- addBlockSheet: null,
101
100
  isCreatePageModalOpen: false,
102
101
  editingPageId: null,
103
102
  viewportMode: "full",
@@ -151,8 +150,7 @@ const previewStore = createStore({
151
150
  if (sameEditingOwner(context.editingContext, owner)) return context;
152
151
  return {
153
152
  ...context,
154
- editingContext: owner ? targetContext(owner, null) : null,
155
- addBlockSheet: null
153
+ editingContext: owner ? targetContext(owner, null) : null
156
154
  };
157
155
  },
158
156
  activateLayout: (context, event) => {
@@ -163,8 +161,7 @@ const previewStore = createStore({
163
161
  if (sameEditingOwner(context.editingContext, owner)) return context;
164
162
  return {
165
163
  ...context,
166
- editingContext: targetContext(owner, null),
167
- addBlockSheet: null
164
+ editingContext: targetContext(owner, null)
168
165
  };
169
166
  },
170
167
  selectTarget: (context, event) => ({
@@ -176,8 +173,7 @@ const previewStore = createStore({
176
173
  editingContext: targetContext(event, {
177
174
  type: "block",
178
175
  blockId: event.blockId
179
- }),
180
- addBlockSheet: null
176
+ })
181
177
  }),
182
178
  selectItem: (context, event) => ({
183
179
  ...context,
@@ -314,22 +310,6 @@ const previewStore = createStore({
314
310
  selection: null
315
311
  } : null
316
312
  }),
317
- openAddBlockSheet: (context, event) => ({
318
- ...context,
319
- addBlockSheet: { afterPosition: event.afterPosition }
320
- }),
321
- closeAddBlockSheet: (context) => ({
322
- ...context,
323
- addBlockSheet: null
324
- }),
325
- focusCreatedBlock: (context, event) => ({
326
- ...context,
327
- editingContext: targetContext(event, {
328
- type: "block",
329
- blockId: event.blockId
330
- }),
331
- addBlockSheet: null
332
- }),
333
313
  openCreatePageModal: (context) => ({
334
314
  ...context,
335
315
  isCreatePageModalOpen: true
@@ -8,11 +8,10 @@ import { CanvasWorkspaceContext } from "../canvas/canvasZoom.js";
8
8
  import { PreviewEditingOwnerContext } from "../preview/previewSelection.js";
9
9
  import { StudioNoticeContext } from "../preview/studioNotice.js";
10
10
  import { ContentEditsContext } from "../../core/editing/contentEdits.js";
11
- import { PreviewDocumentContext } from "../runtime/PreviewDocumentContext.js";
12
11
  import { restyle } from "../preview/components/previewStyles.js";
12
+ import { PreviewDocumentContext } from "../runtime/PreviewDocumentContext.js";
13
13
  import { FrameContext } from "../preview/components/Frame.js";
14
14
  import { DerivedPageContent } from "../page/DerivedPageContent.js";
15
- import { BlockPeek } from "../preview/components/BlockPeek.js";
16
15
  import { EditablePageContent } from "../preview/EditablePageContent.js";
17
16
  import { c } from "react/compiler-runtime";
18
17
  import * as React from "react";
@@ -30,10 +29,9 @@ import { createPortal } from "react-dom";
30
29
  * to load fails each frame, as a page that throws does.
31
30
  */
32
31
  function RendererApp(t0) {
33
- const $ = c(27);
32
+ const $ = c(21);
34
33
  const { connection, camoxApp, codeLoaded, projectUuid, runtimeBasePath } = t0;
35
34
  const frames = useFrames(connection);
36
- const thumbnails = React.useSyncExternalStore(connection.subscribe, connection.thumbnails, connection.thumbnails);
37
35
  const t1 = connection.edit;
38
36
  let t2;
39
37
  if ($[0] !== connection) {
@@ -70,47 +68,26 @@ function RendererApp(t0) {
70
68
  $[8] = t3;
71
69
  } else t3 = $[8];
72
70
  let t4;
73
- if ($[15] !== camoxApp || $[16] !== thumbnails) {
74
- let t5;
75
- if ($[18] !== camoxApp) {
76
- t5 = (t6) => {
77
- const { thumbnailId, slot, blockType } = t6;
78
- return createPortal(/* @__PURE__ */ jsx(RendererThumbnail, {
79
- slot,
80
- blockType,
81
- camoxApp
82
- }), slot, thumbnailId);
83
- };
84
- $[18] = camoxApp;
85
- $[19] = t5;
86
- } else t5 = $[19];
87
- t4 = thumbnails.map(t5);
88
- $[15] = camoxApp;
89
- $[16] = thumbnails;
71
+ if ($[15] !== t2 || $[16] !== t3) {
72
+ t4 = /* @__PURE__ */ jsx(StudioNoticeContext, {
73
+ value: t2,
74
+ children: t3
75
+ });
76
+ $[15] = t2;
77
+ $[16] = t3;
90
78
  $[17] = t4;
91
79
  } else t4 = $[17];
92
80
  let t5;
93
- if ($[20] !== t2 || $[21] !== t3 || $[22] !== t4) {
94
- t5 = /* @__PURE__ */ jsxs(StudioNoticeContext, {
95
- value: t2,
96
- children: [t3, t4]
97
- });
98
- $[20] = t2;
99
- $[21] = t3;
100
- $[22] = t4;
101
- $[23] = t5;
102
- } else t5 = $[23];
103
- let t6;
104
- if ($[24] !== connection.edit || $[25] !== t5) {
105
- t6 = /* @__PURE__ */ jsx(ContentEditsContext, {
81
+ if ($[18] !== connection.edit || $[19] !== t4) {
82
+ t5 = /* @__PURE__ */ jsx(ContentEditsContext, {
106
83
  value: t1,
107
- children: t5
84
+ children: t4
108
85
  });
109
- $[24] = connection.edit;
110
- $[25] = t5;
111
- $[26] = t6;
112
- } else t6 = $[26];
113
- return t6;
86
+ $[18] = connection.edit;
87
+ $[19] = t4;
88
+ $[20] = t5;
89
+ } else t5 = $[20];
90
+ return t5;
114
91
  }
115
92
  /**
116
93
  * The frames the studio gives the renderer to fill. Each change renders in a transition, so a
@@ -138,107 +115,6 @@ function useFrames(connection) {
138
115
  React.useEffect(t0, t1);
139
116
  return frames;
140
117
  }
141
- /** A block's thumbnail, rendered by the draft's code into its frame: nothing for a block it lacks. */
142
- function RendererThumbnail(t0) {
143
- const $ = c(17);
144
- const { slot, blockType, camoxApp } = t0;
145
- const frameWindow = slot.ownerDocument.defaultView;
146
- const left = useLeftInSlot(slot);
147
- const t1 = frameWindow?.frameElement ?? null;
148
- let t2;
149
- if ($[0] !== frameWindow || $[1] !== t1) {
150
- t2 = {
151
- window: frameWindow,
152
- iframeElement: t1
153
- };
154
- $[0] = frameWindow;
155
- $[1] = t1;
156
- $[2] = t2;
157
- } else t2 = $[2];
158
- const frameContext = t2;
159
- let t3;
160
- if ($[3] !== blockType || $[4] !== camoxApp) {
161
- t3 = /* @__PURE__ */ jsx(ThumbnailBlock, {
162
- blockType,
163
- camoxApp
164
- });
165
- $[3] = blockType;
166
- $[4] = camoxApp;
167
- $[5] = t3;
168
- } else t3 = $[5];
169
- let t4;
170
- if ($[6] !== left) {
171
- t4 = /* @__PURE__ */ jsx(RemovesLeft, { nodes: left });
172
- $[6] = left;
173
- $[7] = t4;
174
- } else t4 = $[7];
175
- let t5;
176
- if ($[8] !== t3 || $[9] !== t4) {
177
- t5 = /* @__PURE__ */ jsxs(React.Suspense, {
178
- fallback: null,
179
- children: [t3, t4]
180
- });
181
- $[8] = t3;
182
- $[9] = t4;
183
- $[10] = t5;
184
- } else t5 = $[10];
185
- let t6;
186
- if ($[11] !== left || $[12] !== t5) {
187
- t6 = /* @__PURE__ */ jsx(ThumbnailErrorBoundary, {
188
- left,
189
- children: t5
190
- });
191
- $[11] = left;
192
- $[12] = t5;
193
- $[13] = t6;
194
- } else t6 = $[13];
195
- let t7;
196
- if ($[14] !== frameContext || $[15] !== t6) {
197
- t7 = /* @__PURE__ */ jsx(NavigationProvider, {
198
- location: THUMBNAIL_LOCATION,
199
- navigate: noNavigation,
200
- children: /* @__PURE__ */ jsx(FrameContext.Provider, {
201
- value: frameContext,
202
- children: t6
203
- })
204
- });
205
- $[14] = frameContext;
206
- $[15] = t6;
207
- $[16] = t7;
208
- } else t7 = $[16];
209
- return t7;
210
- }
211
- const THUMBNAIL_LOCATION = {
212
- href: "",
213
- pathname: "/",
214
- search: "",
215
- hash: ""
216
- };
217
- const noNavigation = () => {};
218
- var ThumbnailErrorBoundary = class extends React.Component {
219
- state = { failed: false };
220
- static getDerivedStateFromError() {
221
- return { failed: true };
222
- }
223
- componentDidCatch(error) {
224
- console.error("Camox: a block's thumbnail failed to render.", error);
225
- }
226
- render() {
227
- return this.state.failed ? /* @__PURE__ */ jsx(RemovesLeft, { nodes: this.props.left }) : this.props.children;
228
- }
229
- };
230
- function ThumbnailBlock(t0) {
231
- const $ = c(2);
232
- const { blockType, camoxApp } = t0;
233
- const block = camoxApp.getBlockById(blockType) ?? (camoxApp.canLoadMoreBlocks() ? React.use(camoxApp.loadBlock(blockType)) : void 0);
234
- let t1;
235
- if ($[0] !== block) {
236
- t1 = block ? /* @__PURE__ */ jsx(BlockPeek, { block }) : null;
237
- $[0] = block;
238
- $[1] = t1;
239
- } else t1 = $[1];
240
- return t1;
241
- }
242
118
  /**
243
119
  * What another renderer document left in `slot`, read before this one renders into it. Each new
244
120
  * revision loads another renderer document, and removing the last one's frame never unmounts
@@ -1,15 +1,8 @@
1
1
  import { curatedLayoutContext } from "../../core/layoutContext.js";
2
2
 
3
3
  //#region src/features/renderer/definitionAnswers.ts
4
- /** The block of `type` in the draft's code, loading it if it is lazy. */
5
- async function blockOfCode(camoxApp, type) {
6
- const block = camoxApp.getBlockById(type);
7
- if (block || !camoxApp.canLoadMoreBlocks()) return block;
8
- return camoxApp.loadBlock(type);
9
- }
10
4
  async function answerFromCode(camoxApp, question) {
11
5
  switch (question.type) {
12
- case "initialBundle": return (await blockOfCode(camoxApp, question.blockType))?._internal.getInitialBundle() ?? null;
13
6
  case "prepareFrame": return null;
14
7
  case "pageTitle": {
15
8
  const layout = camoxApp.getLayoutById(question.layoutId);
@@ -24,4 +17,4 @@ async function answerFromCode(camoxApp, question) {
24
17
  }
25
18
 
26
19
  //#endregion
27
- export { answerFromCode, blockOfCode };
20
+ export { answerFromCode };
@@ -1,4 +1,3 @@
1
- import { referencePickerFocus } from "../preview/referencePickerFocus.js";
2
1
  import { canvasStore } from "../canvas/canvasStore.js";
3
2
  import { previewStore } from "../preview/previewStore.js";
4
3
  import { SDK_VERSION, deferredInbox } from "./protocol.js";
@@ -20,10 +19,7 @@ const storeMessages = {
20
19
  })
21
20
  };
22
21
  /** The stores the renderer forwards its events to, as the host applies them. */
23
- const forwarded = {
24
- preview: previewStore,
25
- referencePickerFocus
26
- };
22
+ const forwarded = { preview: previewStore };
27
23
  /** Applies an event the renderer forwarded to the studio's store. */
28
24
  const applyStoreEvent = (message) => {
29
25
  const store = forwarded[message.store];
@@ -43,7 +39,6 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
43
39
  studioCache
44
40
  }) : void 0;
45
41
  const frames = /* @__PURE__ */ new Map();
46
- const thumbnails = /* @__PURE__ */ new Map();
47
42
  /** The questions asked that no renderer answered yet. */
48
43
  const asked = /* @__PURE__ */ new Map();
49
44
  let lastAskId = 0;
@@ -122,12 +117,6 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
122
117
  slot,
123
118
  target
124
119
  });
125
- for (const [thumbnailId, { slot, blockType }] of thumbnails) post({
126
- type: "thumbnail",
127
- thumbnailId,
128
- slot,
129
- blockType
130
- });
131
120
  for (const [askId, { question }] of asked) post({
132
121
  type: "ask",
133
122
  askId,
@@ -213,25 +202,6 @@ function createRendererHost({ studioCache, draftScope, queryClient, notify } = {
213
202
  });
214
203
  });
215
204
  },
216
- showThumbnail(thumbnailId, slot, blockType) {
217
- thumbnails.set(thumbnailId, {
218
- slot,
219
- blockType
220
- });
221
- post({
222
- type: "thumbnail",
223
- thumbnailId,
224
- slot,
225
- blockType
226
- });
227
- },
228
- hideThumbnail(thumbnailId) {
229
- if (!thumbnails.delete(thumbnailId)) return;
230
- post({
231
- type: "thumbnailEnd",
232
- thumbnailId
233
- });
234
- },
235
205
  subscribe(listener) {
236
206
  connectionListeners.add(listener);
237
207
  return () => connectionListeners.delete(listener);
@@ -1,4 +1,3 @@
1
- import { referencePickerFocus } from "../preview/referencePickerFocus.js";
2
1
  import { canvasStore } from "../canvas/canvasStore.js";
3
2
  import { previewStore } from "../preview/previewStore.js";
4
3
  import { SDK_VERSION, deferredInbox } from "./protocol.js";
@@ -11,10 +10,7 @@ const mirrors = {
11
10
  canvas: canvasStore
12
11
  };
13
12
  /** The stores of this document whose events are forwarded to the studio's. */
14
- const forwards = {
15
- preview: previewStore,
16
- referencePickerFocus
17
- };
13
+ const forwards = { preview: previewStore };
18
14
  /** Has this document's copy of a mirrored store take the studio's state. */
19
15
  const mirror = (message) => mirrors[message.store]?.send({
20
16
  type: "mirror",
@@ -30,7 +26,6 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
30
26
  let welcomed = false;
31
27
  let frames = [];
32
28
  const listeners = /* @__PURE__ */ new Set();
33
- let thumbnails = [];
34
29
  const changed = () => {
35
30
  for (const listener of listeners) listener();
36
31
  };
@@ -38,10 +33,6 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
38
33
  frames = next;
39
34
  changed();
40
35
  };
41
- const setThumbnails = (next) => {
42
- thumbnails = next;
43
- changed();
44
- };
45
36
  /** The edits sent to the studio that it hasn't answered yet. */
46
37
  const editsInFlight = /* @__PURE__ */ new Map();
47
38
  let lastEditId = 0;
@@ -93,20 +84,6 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
93
84
  exact: true
94
85
  });
95
86
  return;
96
- case "thumbnail": {
97
- const { thumbnailId, slot, blockType } = message;
98
- const thumbnail = {
99
- thumbnailId,
100
- slot,
101
- blockType
102
- };
103
- const index = thumbnails.findIndex((shown) => shown.thumbnailId === thumbnailId);
104
- setThumbnails(index < 0 ? [...thumbnails, thumbnail] : thumbnails.map((shown, at) => at === index ? thumbnail : shown));
105
- return;
106
- }
107
- case "thumbnailEnd":
108
- setThumbnails(thumbnails.filter(({ thumbnailId }) => thumbnailId !== message.thumbnailId));
109
- return;
110
87
  case "ask": {
111
88
  const { askId, question } = message;
112
89
  if (question.type === "prepareFrame") {
@@ -165,7 +142,6 @@ function connectToStudio(handle, { queryClient, studioCache, draftScope, camoxAp
165
142
  return {
166
143
  connected: () => welcomed,
167
144
  frames: () => frames,
168
- thumbnails: () => thumbnails,
169
145
  subscribe(listener) {
170
146
  listeners.add(listener);
171
147
  return () => listeners.delete(listener);
@@ -1,8 +1,9 @@
1
1
  import { DraftScopeContext } from "../../lib/draft-scope.js";
2
2
  import { useAuthState, useSignInRedirect } from "../../lib/auth.js";
3
+ import { ArtifactCaptureContext } from "../../core/hooks/useArtifactHost.js";
3
4
  import { useSignInShortcut } from "../provider/signInShortcut.js";
4
- import { PreviewDocumentContext } from "./PreviewDocumentContext.js";
5
5
  import { PreviewActivation } from "../preview/components/PreviewActivation.js";
6
+ import { PreviewDocumentContext } from "./PreviewDocumentContext.js";
6
7
  import { Frame } from "../preview/components/Frame.js";
7
8
  import { PreviewSignInPage } from "../provider/PreviewSignInPage.js";
8
9
  import { CoreCamoxProvider } from "../provider/CoreCamoxProvider.js";
@@ -36,9 +37,12 @@ function PageApp(t0) {
36
37
  sessionless: input.look,
37
38
  children: /* @__PURE__ */ jsx(PreviewDocumentContext.Provider, {
38
39
  value: currentInput.previewDocument,
39
- children: input.previewHandoff ? /* @__PURE__ */ jsx(PreviewSignInPage, {}) : input.look ? /* @__PURE__ */ jsx(PageContent, {
40
- camoxApp,
41
- input: currentInput
40
+ children: input.previewHandoff ? /* @__PURE__ */ jsx(PreviewSignInPage, {}) : input.look ? /* @__PURE__ */ jsx(ArtifactCaptureContext, {
41
+ value: true,
42
+ children: /* @__PURE__ */ jsx(PageContent, {
43
+ camoxApp,
44
+ input: currentInput
45
+ })
42
46
  }) : /* @__PURE__ */ jsx(PageExperience, {
43
47
  camoxApp,
44
48
  input: currentInput,
@@ -762,8 +762,8 @@ async function lookAtLayoutPage(request, options, reading, path, match) {
762
762
  }
763
763
  /**
764
764
  * The look document's Block Definition mode: the block of the Block Definition `type` as the
765
- * draft would show it placed, with its default content and Block Settings and the overrides the
766
- * URL gives merged on, by the API, which checks them against its schemas. An override it refuses
765
+ * draft would show it placed, its content and Block Settings empty but for the overrides the URL
766
+ * gives, merged by the API, which checks them against its schemas. An override it refuses
767
767
  * answers its message. The block is read as a page reads its blocks, so it renders and hydrates
768
768
  * as a page's block does; its page is the Locale's home, which links resolve against.
769
769
  */
@@ -809,7 +809,7 @@ async function lookAtBlockDefinition(request, options, reading, type) {
809
809
  }
810
810
  /**
811
811
  * The look document's Layout Definition mode: the curated Layout `layoutId` around no page, its
812
- * blocks with their default content and Block Settings and the overrides the URL gives merged on,
812
+ * blocks with their content and Block Settings empty but for the overrides the URL gives, merged
813
813
  * by the API, which checks them against their schemas and refuses a Singleton or Derived Layout,
814
814
  * answering its message. Where a page's content goes, a labelled placeholder as tall as the URL
815
815
  * says. Its path is the Locale's home, which links resolve against.
@@ -0,0 +1,71 @@
1
+ import { c } from "react/compiler-runtime";
2
+ import * as React from "react";
3
+ import { toast } from "@camox/ui/toaster";
4
+
5
+ //#region src/features/studio/agentRunToast.ts
6
+ /**
7
+ * Says the agent is working in a toast while a run goes in the draft's thread, anyone's, so the
8
+ * editor knows wherever they are in the studio, then how it ended. Live's runs are too quick to
9
+ * need one. Leaving the thread takes the toast away.
10
+ */
11
+ function useAgentRunToast(view, draftId) {
12
+ const $ = c(13);
13
+ const id = React.useId();
14
+ const running = draftId !== null && view.running;
15
+ const ran = React.useRef(false);
16
+ let t0;
17
+ if ($[0] !== id || $[1] !== view) {
18
+ t0 = () => {
19
+ const last = view.messages.at(-1)?.from;
20
+ if (last === "failed") toast.error("Agent couldn't finish", { id });
21
+ else if (last === "stopped") toast.dismiss(id);
22
+ else toast.success("Agent is done", { id });
23
+ };
24
+ $[0] = id;
25
+ $[1] = view;
26
+ $[2] = t0;
27
+ } else t0 = $[2];
28
+ const ended = React.useEffectEvent(t0);
29
+ let t1;
30
+ if ($[3] !== ended || $[4] !== id || $[5] !== running) {
31
+ t1 = () => {
32
+ if (running) {
33
+ ran.current = true;
34
+ toast.loading("Agent is working…", { id });
35
+ } else if (ran.current) {
36
+ ran.current = false;
37
+ ended();
38
+ }
39
+ };
40
+ $[3] = ended;
41
+ $[4] = id;
42
+ $[5] = running;
43
+ $[6] = t1;
44
+ } else t1 = $[6];
45
+ let t2;
46
+ if ($[7] !== id || $[8] !== running) {
47
+ t2 = [running, id];
48
+ $[7] = id;
49
+ $[8] = running;
50
+ $[9] = t2;
51
+ } else t2 = $[9];
52
+ React.useEffect(t1, t2);
53
+ let t3;
54
+ let t4;
55
+ if ($[10] !== id) {
56
+ t3 = () => () => {
57
+ if (ran.current) toast.dismiss(id);
58
+ };
59
+ t4 = [id];
60
+ $[10] = id;
61
+ $[11] = t3;
62
+ $[12] = t4;
63
+ } else {
64
+ t3 = $[11];
65
+ t4 = $[12];
66
+ }
67
+ React.useEffect(t3, t4);
68
+ }
69
+
70
+ //#endregion
71
+ export { useAgentRunToast };
@@ -7,6 +7,7 @@ import { BOTTOM_CARD_EDGES, CARD_BODY_EDGES } from "../../preview/components/Sid
7
7
  import { studioStore } from "../studioStore.js";
8
8
  import { FollowAgentContext } from "../followAgentContext.js";
9
9
  import { useThread } from "../../../lib/use-thread.js";
10
+ import { useAgentRunToast } from "../agentRunToast.js";
10
11
  import { EditorWhereContext } from "../editorWhereContext.js";
11
12
  import { useEditorSelection } from "../useEditorSelection.js";
12
13
  import { ThreadComposer, useComposerCarrier } from "./ThreadComposer.js";
@@ -141,6 +142,7 @@ function Thread(t0) {
141
142
  $[1] = t1;
142
143
  } else t1 = $[1];
143
144
  const { view, sending, send, stop, error, touched } = useThread(apiUrl, projectId, draftId, t1);
145
+ useAgentRunToast(view, draftId);
144
146
  const follow = React.use(FollowAgentContext);
145
147
  let t2;
146
148
  if ($[2] !== follow) {
@@ -14,8 +14,7 @@ import { FloatingToolbar } from "@camox/ui/floating-toolbar";
14
14
  */
15
15
  const SETTLE_MS = 1500;
16
16
  /**
17
- * Asks what to do with the draft being viewed, once its edits settle: discard its changes or
18
- * publish them. `stacked` places it in the Preview toolbar's column, just above the toolbar;
17
+ * Asks what to do with the draft being viewed, once its edits settle: delete it or publish it. `stacked` places it in the Preview toolbar's column, just above the toolbar;
19
18
  * otherwise it floats at the bottom of the screen on its own.
20
19
  */
21
20
  function DraftBar(t0) {
@@ -63,7 +62,7 @@ function DraftBar(t0) {
63
62
  type: "button",
64
63
  variant: "outline",
65
64
  onClick: _temp,
66
- children: "Discard"
65
+ children: "Delete"
67
66
  });
68
67
  $[8] = t7;
69
68
  } else t7 = $[8];