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.
- package/dist/core/createApp.d.ts +4 -103
- package/dist/core/createApp.js +3 -24
- package/dist/core/createBlock.d.ts +2 -2
- package/dist/core/createBlock.js +55 -192
- package/dist/core/createLayout.d.ts +6 -77
- package/dist/core/createLayout.js +12 -50
- package/dist/core/editing/createEditableBlock.d.ts +9 -75
- package/dist/core/editing/createEditableBlock.js +258 -640
- package/dist/core/hooks/useArtifactHost.js +56 -46
- package/dist/core/hooks/useIsEditable.js +2 -2
- package/dist/core/lib/artifact.d.ts +4 -0
- package/dist/core/lib/artifactData.js +8 -3
- package/dist/core/lib/artifactHost.js +40 -0
- package/dist/core/lib/artifactRuntime.js +20 -1
- package/dist/core/lib/contentType.d.ts +23 -38
- package/dist/core/lib/contentType.js +34 -62
- package/dist/core/lib/iconTypes.d.ts +0 -3
- package/dist/core/lib/icons.js +63 -51
- package/dist/core/lib/recordScope.js +1 -1
- package/dist/features/canvas/CanvasOverlays.js +94 -176
- package/dist/features/canvas/CanvasPageFrame.js +62 -68
- package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -3
- package/dist/features/canvas/canvasOverlayGeometry.js +1 -7
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +3 -21
- package/dist/features/canvas/sidebar/LayoutPageBlocks.js +1 -2
- package/dist/features/canvas/useCanvasCamera.js +1 -1
- package/dist/features/canvas/useCanvasFrame.js +1 -1
- package/dist/features/content/ContentCollection.js +2 -2
- package/dist/features/content/collection-form.js +6 -7
- package/dist/features/page/CuratedPageContent.js +15 -24
- package/dist/features/page/UnplacedBlockContent.js +1 -6
- package/dist/features/preview/CamoxPreview.js +30 -33
- package/dist/features/preview/EditablePageContent.js +131 -151
- package/dist/features/preview/components/BlockActionsPopover.js +43 -152
- package/dist/features/preview/components/CanvasPreview.js +2 -2
- package/dist/features/preview/components/Frame.js +3 -3
- package/dist/features/preview/components/IconFieldEditor.js +1 -1
- package/dist/features/preview/components/ItemFieldsEditor.js +1 -3
- package/dist/features/preview/components/Overlays.js +18 -84
- package/dist/features/preview/components/PageTree.js +57 -103
- package/dist/features/preview/components/PreviewPanel.js +8 -11
- package/dist/features/preview/components/RecordCombobox.js +65 -78
- package/dist/features/preview/components/ReferenceFieldEditor.js +1 -19
- package/dist/features/preview/components/ReferenceListFieldEditor.js +1 -19
- package/dist/features/preview/components/RemovedBlockPlaceholder.js +2 -2
- package/dist/features/preview/components/SelectionEditor.js +5 -4
- package/dist/features/preview/components/useRepeatableItemActions.js +18 -24
- package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
- package/dist/features/preview/overlayMessages.js +1 -4
- package/dist/features/preview/previewStore.js +3 -23
- package/dist/features/renderer/RendererApp.js +17 -141
- package/dist/features/renderer/definitionAnswers.js +1 -8
- package/dist/features/renderer/rendererHost.js +1 -31
- package/dist/features/renderer/studioConnection.js +1 -25
- package/dist/features/runtime/pageApp.js +8 -4
- package/dist/features/runtime/runtime.js +3 -3
- package/dist/features/studio/agentRunToast.js +71 -0
- package/dist/features/studio/components/ChatWidget.js +2 -0
- package/dist/features/studio/components/DraftBar.js +2 -3
- package/dist/features/studio/components/DraftsControl.js +150 -176
- package/dist/features/studio/components/ReviewDraftSheet.js +344 -548
- package/dist/features/studio/components/ThreadMessages.js +89 -22
- package/dist/features/studio/draftLabel.js +1 -1
- package/dist/features/studio/studioStore.js +5 -17
- package/dist/features/studio/viewSwitch.js +2 -4
- package/dist/features/vite/blockBoilerplate.js +1 -1
- package/dist/features/vite/definitionsSync.js +1 -8
- package/dist/lib/queries.js +0 -1
- package/dist/lib/studio-definitions.js +0 -2
- package/dist/lib/studio-reads.js +0 -5
- package/dist/lib/use-thread.js +196 -138
- package/dist/package.js +1 -1
- package/dist/studio-overlays.css +0 -29
- package/dist/studio.css +1 -1
- package/package.json +6 -4
- package/skills/camox/SKILL.md +1 -1
- package/skills/camox/references/artifacts.md +89 -5
- package/skills/camox/references/block-definitions.md +21 -25
- package/skills/camox/references/dom-integrations.md +1 -1
- package/skills/camox/references/layout-definitions.md +3 -12
- package/skills/camox/references/routed-layouts.md +2 -2
- package/skills/camox-expand/SKILL.md +5 -5
- package/skills/camoxify/SKILL.md +4 -4
- package/dist/features/canvas/canvasInsertionSeams.js +0 -44
- package/dist/features/preview/components/AddBlockSheet.js +0 -314
- package/dist/features/preview/components/BlockPeek.js +0 -66
- package/dist/features/preview/components/BlockThumbnail.js +0 -281
- package/dist/features/preview/components/blockGridNavigation.js +0 -15
- 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 {
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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.
|
|
27
|
-
|
|
28
|
-
const
|
|
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 <
|
|
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:
|
|
43
|
-
settings:
|
|
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:
|
|
85
|
-
settings:
|
|
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,
|
|
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(
|
|
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] !==
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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 ($[
|
|
94
|
-
t5 = /* @__PURE__ */
|
|
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:
|
|
84
|
+
children: t4
|
|
108
85
|
});
|
|
109
|
-
$[
|
|
110
|
-
$[
|
|
111
|
-
$[
|
|
112
|
-
} else
|
|
113
|
-
return
|
|
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
|
|
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(
|
|
40
|
-
|
|
41
|
-
|
|
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,
|
|
766
|
-
*
|
|
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
|
|
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:
|
|
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: "
|
|
65
|
+
children: "Delete"
|
|
67
66
|
});
|
|
68
67
|
$[8] = t7;
|
|
69
68
|
} else t7 = $[8];
|