camox 0.71.0 → 0.74.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +41 -185
- 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/useIsEditable.js +2 -2
- package/dist/core/lib/artifactData.js +8 -3
- 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/PageInfo.js +121 -98
- 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 +6 -5
- 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/routes/pageRuntime.js +15 -4
- package/dist/features/runtime/ClaimCard.js +192 -0
- package/dist/features/runtime/pageApp.js +5 -4
- package/dist/features/runtime/runtime.js +29 -8
- package/dist/features/runtime/worker.js +2 -2
- package/dist/features/runtime/workerRequest.d.ts +6 -0
- package/dist/features/runtime/workerRequest.js +13 -1
- package/dist/features/runtime/workerRuntime.d.ts +2 -2
- package/dist/features/runtime/workerRuntime.js +2 -2
- package/dist/features/studio/components/AgentSidebar.js +7 -7
- package/dist/features/studio/components/ChatWidget.js +142 -106
- package/dist/features/studio/components/ContentFindings.js +127 -230
- package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
- package/dist/features/studio/components/DraftBar.js +98 -53
- package/dist/features/studio/components/DraftsControl.js +203 -190
- package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
- package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
- package/dist/features/studio/components/Squareling.js +5 -5
- package/dist/features/studio/components/ThreadComposer.js +106 -127
- package/dist/features/studio/components/ThreadMessages.js +137 -45
- package/dist/features/studio/findingSentence.js +14 -12
- package/dist/features/studio/fixMessage.js +23 -0
- package/dist/features/studio/reportSentence.js +1 -1
- package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
- package/dist/features/studio/studioStore.js +29 -15
- package/dist/features/studio/workingSentence.js +1 -1
- package/dist/features/vite/blockBoilerplate.js +1 -1
- package/dist/features/vite/definitionsSync.js +1 -8
- package/dist/lib/api-client.js +5 -1
- package/dist/lib/queries.js +5 -6
- package/dist/lib/studio-definitions.js +0 -2
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -10
- 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 +4 -4
- package/skills/camox/SKILL.md +1 -1
- package/skills/camox/references/artifacts.md +4 -4
- 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
- package/dist/features/studio/components/ReviewDraftSheet.js +0 -1587
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
import { useProjectUuid } from "../../../lib/auth.js";
|
|
2
|
-
import { usePageBlocks } from "../../../lib/normalized-data.js";
|
|
3
|
-
import { reads, useReadQuery, useStudioCache } from "../../../lib/studio-reads.js";
|
|
4
|
-
import { blockMutations } from "../../../lib/queries.js";
|
|
5
|
-
import { useBlockDefinitions } from "../../../lib/studio-definitions.js";
|
|
6
|
-
import { useLocalePath } from "../../../lib/view-locale.js";
|
|
7
|
-
import { previewStore, sameEditingOwner } from "../previewStore.js";
|
|
8
|
-
import { useRendererHost } from "../../renderer/RendererFrames.js";
|
|
9
|
-
import { getGridNavigationIndex } from "./blockGridNavigation.js";
|
|
10
|
-
import { BlockThumbnail } from "./BlockThumbnail.js";
|
|
11
|
-
import { usePreviewedPage } from "../CamoxPreview.js";
|
|
12
|
-
import * as React from "react";
|
|
13
|
-
import { generateUuidv7 } from "@camox/api-contract/ids";
|
|
14
|
-
import { generateKeyBetween } from "fractional-indexing";
|
|
15
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
16
|
-
import { useSelector } from "@xstate/store-react";
|
|
17
|
-
import { useMutation } from "@tanstack/react-query";
|
|
18
|
-
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "@camox/ui/sheet";
|
|
19
|
-
import { Badge } from "@camox/ui/badge";
|
|
20
|
-
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, commandFilter } from "@camox/ui/command";
|
|
21
|
-
|
|
22
|
-
//#region src/features/preview/components/AddBlockSheet.tsx
|
|
23
|
-
const AddBlockSheet = ({ focusCreatedBlock = true }) => {
|
|
24
|
-
const [highlightedValue, setHighlightedValue] = React.useState("");
|
|
25
|
-
const [search, setSearch] = React.useState("");
|
|
26
|
-
const [error, setError] = React.useState(null);
|
|
27
|
-
const submitting = React.useRef(false);
|
|
28
|
-
const mounted = React.useRef(false);
|
|
29
|
-
React.useEffect(() => {
|
|
30
|
-
mounted.current = true;
|
|
31
|
-
return () => {
|
|
32
|
-
mounted.current = false;
|
|
33
|
-
};
|
|
34
|
-
}, []);
|
|
35
|
-
const gridRef = React.useRef(null);
|
|
36
|
-
const sheet = useSelector(previewStore, (state) => state.context.addBlockSheet);
|
|
37
|
-
const studioCache = useStudioCache();
|
|
38
|
-
const projectUuid = useProjectUuid();
|
|
39
|
-
const pathname = useLocalePath();
|
|
40
|
-
const createBlock = useMutation({
|
|
41
|
-
...blockMutations.create(),
|
|
42
|
-
onMutate: (variables) => {
|
|
43
|
-
const edit = studioCache.edit();
|
|
44
|
-
const page = reads.pageStructure({
|
|
45
|
-
path: pathname,
|
|
46
|
-
projectUuid
|
|
47
|
-
});
|
|
48
|
-
const previousPage = edit.get(page);
|
|
49
|
-
if (!previousPage) return { edit };
|
|
50
|
-
const blockIds = previousPage.page.blockIds;
|
|
51
|
-
const pageBlocks = blockIds.map((id) => edit.get(reads.blockBundle(id))?.block).filter((b) => b != null);
|
|
52
|
-
const { afterPosition } = variables;
|
|
53
|
-
let position;
|
|
54
|
-
if (afterPosition == null) {
|
|
55
|
-
const lastBlock = pageBlocks[pageBlocks.length - 1];
|
|
56
|
-
position = generateKeyBetween(lastBlock?.position ?? null, null);
|
|
57
|
-
} else if (afterPosition === "") {
|
|
58
|
-
const firstBlock = pageBlocks[0];
|
|
59
|
-
position = generateKeyBetween(null, firstBlock?.position ?? null);
|
|
60
|
-
} else {
|
|
61
|
-
let afterIndex = -1;
|
|
62
|
-
for (let i = pageBlocks.length - 1; i >= 0; i--) if (String(pageBlocks[i].position) <= afterPosition) {
|
|
63
|
-
afterIndex = i;
|
|
64
|
-
break;
|
|
65
|
-
}
|
|
66
|
-
const nextBlock = afterIndex >= 0 ? pageBlocks[afterIndex + 1] : pageBlocks[0];
|
|
67
|
-
position = generateKeyBetween(afterIndex >= 0 ? pageBlocks[afterIndex].position : null, nextBlock?.position ?? null);
|
|
68
|
-
}
|
|
69
|
-
const now = Date.now();
|
|
70
|
-
const optimisticId = variables.id ?? generateUuidv7();
|
|
71
|
-
const optimisticBlock = {
|
|
72
|
-
id: optimisticId,
|
|
73
|
-
pageId: variables.pageId,
|
|
74
|
-
layoutId: null,
|
|
75
|
-
type: variables.type,
|
|
76
|
-
content: variables.content,
|
|
77
|
-
settings: variables.settings ?? null,
|
|
78
|
-
slot: null,
|
|
79
|
-
summary: "",
|
|
80
|
-
title: "",
|
|
81
|
-
position,
|
|
82
|
-
createdAt: now,
|
|
83
|
-
updatedAt: now
|
|
84
|
-
};
|
|
85
|
-
edit.set(reads.blockBundle(optimisticId), {
|
|
86
|
-
block: optimisticBlock,
|
|
87
|
-
repeatableItems: [],
|
|
88
|
-
files: []
|
|
89
|
-
});
|
|
90
|
-
const insertIndex = pageBlocks.findIndex((b) => b.position > position);
|
|
91
|
-
const newBlockIds = [...blockIds];
|
|
92
|
-
if (insertIndex === -1) newBlockIds.push(optimisticId);
|
|
93
|
-
else newBlockIds.splice(insertIndex, 0, optimisticId);
|
|
94
|
-
edit.set(page, {
|
|
95
|
-
...previousPage,
|
|
96
|
-
page: {
|
|
97
|
-
...previousPage.page,
|
|
98
|
-
blockIds: newBlockIds
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
return { edit };
|
|
102
|
-
},
|
|
103
|
-
onError: (_error, _variables, context) => context?.edit.rollback(),
|
|
104
|
-
onSettled: (_data, _error, _variables, context) => context?.edit.settle()
|
|
105
|
-
});
|
|
106
|
-
const { data: project } = useReadQuery(reads.project({ projectUuid }));
|
|
107
|
-
const rendererHost = useRendererHost();
|
|
108
|
-
const availableBlocks = useBlockDefinitions().filter((block) => !block.layoutOnly);
|
|
109
|
-
const page = usePreviewedPage();
|
|
110
|
-
const { pageBlocks } = usePageBlocks(page);
|
|
111
|
-
const { data: totalCounts = {} } = useReadQuery(reads.blockUsageCounts({ projectId: project?.id ?? 0 }), { enabled: !!project });
|
|
112
|
-
const filteredBlocks = availableBlocks.map((block) => ({
|
|
113
|
-
block,
|
|
114
|
-
score: search.trim() ? commandFilter(block.id, search.trim(), [block.title, block.description]) : 1
|
|
115
|
-
})).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score || (totalCounts[b.block.id] ?? 0) - (totalCounts[a.block.id] ?? 0)).map(({ block }) => block);
|
|
116
|
-
const selectedValue = filteredBlocks.some((block) => block.id === highlightedValue) ? highlightedValue : filteredBlocks[0]?.id ?? "";
|
|
117
|
-
const pageCounts = React.useMemo(() => {
|
|
118
|
-
const counts = {};
|
|
119
|
-
if (!page) return counts;
|
|
120
|
-
for (const block of pageBlocks) counts[block.type] = (counts[block.type] ?? 0) + 1;
|
|
121
|
-
return counts;
|
|
122
|
-
}, [page, pageBlocks]);
|
|
123
|
-
const [previousSheet, setPreviousSheet] = React.useState(sheet);
|
|
124
|
-
if (sheet !== previousSheet) {
|
|
125
|
-
setPreviousSheet(sheet);
|
|
126
|
-
setHighlightedValue("");
|
|
127
|
-
setSearch("");
|
|
128
|
-
setError(null);
|
|
129
|
-
}
|
|
130
|
-
const handleAddBlock = async (block) => {
|
|
131
|
-
if (!page || !sheet || submitting.current) return;
|
|
132
|
-
submitting.current = true;
|
|
133
|
-
setError(null);
|
|
134
|
-
const owner = {
|
|
135
|
-
kind: "page",
|
|
136
|
-
pageId: page.page.id
|
|
137
|
-
};
|
|
138
|
-
try {
|
|
139
|
-
const bundle = (rendererHost ? await initialBundleFrom(rendererHost, block.id) : null) ?? {
|
|
140
|
-
content: block.defaultContent,
|
|
141
|
-
settings: block.defaultSettings,
|
|
142
|
-
repeatableItems: []
|
|
143
|
-
};
|
|
144
|
-
const { id: blockId } = await createBlock.mutateAsync({
|
|
145
|
-
id: generateUuidv7(),
|
|
146
|
-
pageId: page.page.id,
|
|
147
|
-
type: block.id,
|
|
148
|
-
content: bundle.content,
|
|
149
|
-
settings: bundle.settings,
|
|
150
|
-
afterPosition: sheet.afterPosition,
|
|
151
|
-
repeatableItems: bundle.repeatableItems
|
|
152
|
-
});
|
|
153
|
-
const context = previewStore.getSnapshot().context;
|
|
154
|
-
if (!mounted.current) return;
|
|
155
|
-
if (focusCreatedBlock && !sameEditingOwner(context.editingContext, owner)) return;
|
|
156
|
-
if (context.addBlockSheet !== sheet) return;
|
|
157
|
-
previewStore.send({ type: "closeAddBlockSheet" });
|
|
158
|
-
if (focusCreatedBlock) previewStore.send({
|
|
159
|
-
type: "focusCreatedBlock",
|
|
160
|
-
...owner,
|
|
161
|
-
blockId
|
|
162
|
-
});
|
|
163
|
-
} catch {
|
|
164
|
-
if (previewStore.getSnapshot().context.addBlockSheet === sheet) setError("Could not add this block. Please try again.");
|
|
165
|
-
} finally {
|
|
166
|
-
submitting.current = false;
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
const displayCount = (blockId) => {
|
|
170
|
-
const total = totalCounts[blockId] ?? 0;
|
|
171
|
-
if (total === 0) return "Never used";
|
|
172
|
-
const page = pageCounts[blockId] ?? "none";
|
|
173
|
-
return `${total} use${total > 1 ? "s" : ""} (${page} here)`;
|
|
174
|
-
};
|
|
175
|
-
return /* @__PURE__ */ jsx(Sheet, {
|
|
176
|
-
open: sheet != null,
|
|
177
|
-
onOpenChange: (open) => {
|
|
178
|
-
if (!open && !submitting.current) previewStore.send({ type: "closeAddBlockSheet" });
|
|
179
|
-
},
|
|
180
|
-
children: /* @__PURE__ */ jsxs(SheetContent, {
|
|
181
|
-
side: "right",
|
|
182
|
-
className: "gap-0 overflow-hidden data-[side=right]:w-full data-[side=right]:sm:max-w-4xl",
|
|
183
|
-
children: [
|
|
184
|
-
/* @__PURE__ */ jsxs(SheetHeader, {
|
|
185
|
-
className: "pr-12",
|
|
186
|
-
children: [/* @__PURE__ */ jsx(SheetTitle, { children: "Add a block" }), /* @__PURE__ */ jsx(SheetDescription, { children: "Search blocks, use the arrow keys to browse, and press Enter to add." })]
|
|
187
|
-
}),
|
|
188
|
-
/* @__PURE__ */ jsxs(Command, {
|
|
189
|
-
label: "Search blocks",
|
|
190
|
-
shouldFilter: false,
|
|
191
|
-
value: selectedValue,
|
|
192
|
-
onValueChange: setHighlightedValue,
|
|
193
|
-
className: "h-0 min-h-0 flex-1 rounded-none! bg-transparent! px-4! pt-0! pb-0!",
|
|
194
|
-
onKeyDown: (e) => {
|
|
195
|
-
if (e.nativeEvent.isComposing || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
196
|
-
if (![
|
|
197
|
-
"ArrowLeft",
|
|
198
|
-
"ArrowRight",
|
|
199
|
-
"ArrowUp",
|
|
200
|
-
"ArrowDown"
|
|
201
|
-
].includes(e.key)) return;
|
|
202
|
-
e.preventDefault();
|
|
203
|
-
const grid = gridRef.current?.querySelector("[cmdk-group-items]");
|
|
204
|
-
if (!grid || submitting.current) return;
|
|
205
|
-
const items = Array.from(grid.querySelectorAll("[cmdk-item]:not([data-disabled=\"true\"])"));
|
|
206
|
-
const columns = getComputedStyle(grid).gridTemplateColumns.split(" ").length;
|
|
207
|
-
const index = items.findIndex((item) => item.dataset.selected === "true");
|
|
208
|
-
const item = items[getGridNavigationIndex(index, items.length, columns, e.key)];
|
|
209
|
-
if (!item) return;
|
|
210
|
-
setHighlightedValue(item.dataset.value ?? "");
|
|
211
|
-
item.scrollIntoView({ block: "nearest" });
|
|
212
|
-
},
|
|
213
|
-
children: [/* @__PURE__ */ jsx(CommandInput, {
|
|
214
|
-
placeholder: "Search blocks...",
|
|
215
|
-
"aria-label": "Search blocks",
|
|
216
|
-
value: search,
|
|
217
|
-
onValueChange: (value) => {
|
|
218
|
-
setSearch(value);
|
|
219
|
-
setHighlightedValue("");
|
|
220
|
-
},
|
|
221
|
-
className: "px-0 pt-0",
|
|
222
|
-
autoFocus: true
|
|
223
|
-
}), /* @__PURE__ */ jsxs(CommandList, {
|
|
224
|
-
label: "Available blocks",
|
|
225
|
-
className: "mt-4 max-h-none min-h-0 flex-1 pb-4",
|
|
226
|
-
"aria-busy": createBlock.isPending,
|
|
227
|
-
children: [/* @__PURE__ */ jsx(CommandEmpty, { children: "No blocks found." }), /* @__PURE__ */ jsx(CommandGroup, {
|
|
228
|
-
ref: gridRef,
|
|
229
|
-
className: "@container p-0 [&>[cmdk-group-items]]:grid [&>[cmdk-group-items]]:grid-cols-1 [&>[cmdk-group-items]]:gap-4 @xl:[&>[cmdk-group-items]]:grid-cols-2 @3xl:[&>[cmdk-group-items]]:grid-cols-3",
|
|
230
|
-
children: filteredBlocks.map((block) => /* @__PURE__ */ jsxs(CommandItem, {
|
|
231
|
-
value: block.id,
|
|
232
|
-
keywords: [block.title, block.description],
|
|
233
|
-
disabled: createBlock.isPending,
|
|
234
|
-
hideCheck: true,
|
|
235
|
-
onSelect: () => {
|
|
236
|
-
handleAddBlock(block);
|
|
237
|
-
},
|
|
238
|
-
className: "group bg-card data-[selected=true]:border-primary flex flex-col items-stretch gap-0 overflow-hidden rounded-lg border-2 p-0",
|
|
239
|
-
children: [/* @__PURE__ */ jsx(BlockThumbnail, {
|
|
240
|
-
blockType: block.id,
|
|
241
|
-
title: block.title,
|
|
242
|
-
className: "h-44"
|
|
243
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
244
|
-
className: "border-border flex flex-col gap-1 border-t px-3 py-2",
|
|
245
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
246
|
-
className: "flex items-center justify-between gap-2",
|
|
247
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
248
|
-
className: "min-w-0 leading-5 font-medium",
|
|
249
|
-
children: block.title
|
|
250
|
-
}), block.synced && /* @__PURE__ */ jsx(Badge, {
|
|
251
|
-
variant: "secondary",
|
|
252
|
-
size: "sm",
|
|
253
|
-
children: "Synced"
|
|
254
|
-
})]
|
|
255
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
256
|
-
className: "text-muted-foreground text-xs leading-4",
|
|
257
|
-
children: displayCount(block.id)
|
|
258
|
-
})]
|
|
259
|
-
})]
|
|
260
|
-
}, block.id))
|
|
261
|
-
})]
|
|
262
|
-
})]
|
|
263
|
-
}),
|
|
264
|
-
(createBlock.isPending || error) && /* @__PURE__ */ jsxs("div", {
|
|
265
|
-
className: "border-border border-t p-4",
|
|
266
|
-
children: [createBlock.isPending && /* @__PURE__ */ jsx("p", {
|
|
267
|
-
role: "status",
|
|
268
|
-
children: "Adding block…"
|
|
269
|
-
}), error && /* @__PURE__ */ jsx("p", {
|
|
270
|
-
role: "alert",
|
|
271
|
-
className: "text-destructive",
|
|
272
|
-
children: error
|
|
273
|
-
})]
|
|
274
|
-
})
|
|
275
|
-
]
|
|
276
|
-
})
|
|
277
|
-
});
|
|
278
|
-
};
|
|
279
|
-
/**
|
|
280
|
-
* How long adding a block waits for the renderer frame to give the block's initial content
|
|
281
|
-
* before it uses the synced defaults. A tuning value.
|
|
282
|
-
*/
|
|
283
|
-
const INITIAL_BUNDLE_WAIT_MS = 3e3;
|
|
284
|
-
/**
|
|
285
|
-
* The initial content a `blockType` block's code builds, asked of the renderer frame. Null,
|
|
286
|
-
* for the synced defaults, when the renderer runs another SDK version, which answers nothing,
|
|
287
|
-
* or hasn't answered within `INITIAL_BUNDLE_WAIT_MS`, as when it never connects.
|
|
288
|
-
*/
|
|
289
|
-
function initialBundleFrom(host, blockType) {
|
|
290
|
-
return new Promise((resolve, reject) => {
|
|
291
|
-
const settle = (bundle) => {
|
|
292
|
-
clearTimeout(timeout);
|
|
293
|
-
stopWatching();
|
|
294
|
-
resolve(bundle);
|
|
295
|
-
};
|
|
296
|
-
const timeout = setTimeout(() => settle(null), INITIAL_BUNDLE_WAIT_MS);
|
|
297
|
-
const watch = () => {
|
|
298
|
-
if (host.status() === "updating") settle(null);
|
|
299
|
-
};
|
|
300
|
-
const stopWatching = host.subscribeStatus(watch);
|
|
301
|
-
watch();
|
|
302
|
-
host.ask({
|
|
303
|
-
type: "initialBundle",
|
|
304
|
-
blockType
|
|
305
|
-
}).then(settle, (error) => {
|
|
306
|
-
clearTimeout(timeout);
|
|
307
|
-
stopWatching();
|
|
308
|
-
reject(error);
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
//#endregion
|
|
314
|
-
export { AddBlockSheet, INITIAL_BUNDLE_WAIT_MS };
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { NormalizedDataProvider } from "../../../lib/normalized-data.js";
|
|
2
|
-
import { c } from "react/compiler-runtime";
|
|
3
|
-
import * as React from "react";
|
|
4
|
-
import { jsx } from "react/jsx-runtime";
|
|
5
|
-
|
|
6
|
-
//#region src/features/preview/components/BlockPeek.tsx
|
|
7
|
-
/**
|
|
8
|
-
* A block rendered by its code from its peek bundle: what its thumbnail shows. It catches no
|
|
9
|
-
* error: a broken block shows no thumbnail, which is for the thumbnail to do.
|
|
10
|
-
*/
|
|
11
|
-
const BlockPeek = (t0) => {
|
|
12
|
-
const $ = c(13);
|
|
13
|
-
const { block } = t0;
|
|
14
|
-
let t1;
|
|
15
|
-
if ($[0] !== block._internal) {
|
|
16
|
-
t1 = block._internal.getPeekBundle();
|
|
17
|
-
$[0] = block._internal;
|
|
18
|
-
$[1] = t1;
|
|
19
|
-
} else t1 = $[1];
|
|
20
|
-
const bundle = t1;
|
|
21
|
-
const t2 = bundle.block.content;
|
|
22
|
-
const t3 = bundle.block.settings;
|
|
23
|
-
let t4;
|
|
24
|
-
if ($[2] !== block._internal.id || $[3] !== t2 || $[4] !== t3) {
|
|
25
|
-
t4 = {
|
|
26
|
-
_id: "thumbnail",
|
|
27
|
-
type: block._internal.id,
|
|
28
|
-
content: t2,
|
|
29
|
-
settings: t3,
|
|
30
|
-
position: ""
|
|
31
|
-
};
|
|
32
|
-
$[2] = block._internal.id;
|
|
33
|
-
$[3] = t2;
|
|
34
|
-
$[4] = t3;
|
|
35
|
-
$[5] = t4;
|
|
36
|
-
} else t4 = $[5];
|
|
37
|
-
let t5;
|
|
38
|
-
if ($[6] !== block._internal.Component || $[7] !== t4) {
|
|
39
|
-
t5 = /* @__PURE__ */ jsx(block._internal.Component, {
|
|
40
|
-
blockData: t4,
|
|
41
|
-
mode: "peek"
|
|
42
|
-
});
|
|
43
|
-
$[6] = block._internal.Component;
|
|
44
|
-
$[7] = t4;
|
|
45
|
-
$[8] = t5;
|
|
46
|
-
} else t5 = $[8];
|
|
47
|
-
let t6;
|
|
48
|
-
if ($[9] !== bundle.files || $[10] !== bundle.repeatableItems || $[11] !== t5) {
|
|
49
|
-
t6 = /* @__PURE__ */ jsx(React.Suspense, {
|
|
50
|
-
fallback: null,
|
|
51
|
-
children: /* @__PURE__ */ jsx(NormalizedDataProvider, {
|
|
52
|
-
files: bundle.files,
|
|
53
|
-
repeatableItems: bundle.repeatableItems,
|
|
54
|
-
children: t5
|
|
55
|
-
})
|
|
56
|
-
});
|
|
57
|
-
$[9] = bundle.files;
|
|
58
|
-
$[10] = bundle.repeatableItems;
|
|
59
|
-
$[11] = t5;
|
|
60
|
-
$[12] = t6;
|
|
61
|
-
} else t6 = $[12];
|
|
62
|
-
return t6;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
//#endregion
|
|
66
|
-
export { BlockPeek };
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
import { cn } from "../../../lib/utils.js";
|
|
2
|
-
import { useEditingFrame } from "../editingFrame.js";
|
|
3
|
-
import { useRendererHost } from "../../renderer/RendererFrames.js";
|
|
4
|
-
import { EMPTY_PREVIEW_DOCUMENT, isSiteStyle } from "./previewStyles.js";
|
|
5
|
-
import { FrameContext } from "./Frame.js";
|
|
6
|
-
import { c } from "react/compiler-runtime";
|
|
7
|
-
import * as React from "react";
|
|
8
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { createPortal } from "react-dom";
|
|
10
|
-
|
|
11
|
-
//#region src/features/preview/components/BlockThumbnail.tsx
|
|
12
|
-
const VIEWPORT_WIDTH = 1200;
|
|
13
|
-
const VIEWPORT_HEIGHT = 800;
|
|
14
|
-
const ThumbnailFrame = (t0) => {
|
|
15
|
-
const $ = c(26);
|
|
16
|
-
const { blockType, title, width } = t0;
|
|
17
|
-
const sourceDocument = useEditingFrame().document;
|
|
18
|
-
const [frame, setFrame] = React.useState(null);
|
|
19
|
-
const [root, setRoot] = React.useState(null);
|
|
20
|
-
const [content, setContent] = React.useState(null);
|
|
21
|
-
const [contentHeight, setContentHeight] = React.useState(VIEWPORT_HEIGHT);
|
|
22
|
-
const initialization = React.useRef(0);
|
|
23
|
-
let t1;
|
|
24
|
-
if ($[0] !== frame?.contentDocument || $[1] !== sourceDocument) {
|
|
25
|
-
t1 = () => {
|
|
26
|
-
const doc = frame?.contentDocument;
|
|
27
|
-
const mount = doc?.querySelector("[data-camox-preview-root]");
|
|
28
|
-
if (!doc || !mount) return;
|
|
29
|
-
const source = sourceDocument ?? document;
|
|
30
|
-
doc.head.replaceChildren();
|
|
31
|
-
const base = doc.createElement("base");
|
|
32
|
-
base.href = source.baseURI;
|
|
33
|
-
doc.head.appendChild(base);
|
|
34
|
-
const stylesheetsLoaded = [];
|
|
35
|
-
source.querySelectorAll("style, link[rel=\"stylesheet\"]").forEach((style) => {
|
|
36
|
-
if (!isSiteStyle(style)) return;
|
|
37
|
-
const clone = style.cloneNode(true);
|
|
38
|
-
if (clone.localName === "link") stylesheetsLoaded.push(new Promise((resolve) => {
|
|
39
|
-
clone.addEventListener("load", resolve, { once: true });
|
|
40
|
-
clone.addEventListener("error", resolve, { once: true });
|
|
41
|
-
}));
|
|
42
|
-
doc.head.appendChild(clone);
|
|
43
|
-
});
|
|
44
|
-
if (source !== document) for (const [from, to] of [
|
|
45
|
-
[source.documentElement, doc.documentElement],
|
|
46
|
-
[source.body, doc.body],
|
|
47
|
-
[source.querySelector("[data-camox-preview-root]"), mount]
|
|
48
|
-
]) {
|
|
49
|
-
if (!from || !to) continue;
|
|
50
|
-
for (const attribute of Array.from(from.attributes)) if (!attribute.name.startsWith("on")) to.setAttribute(attribute.name, attribute.value);
|
|
51
|
-
}
|
|
52
|
-
const reset = doc.createElement("style");
|
|
53
|
-
reset.textContent = "\n html, body { margin: 0 !important; overflow: hidden !important; }\n *, *::before, *::after {\n animation: none !important;\n transition: none !important;\n caret-color: transparent !important;\n }\n ";
|
|
54
|
-
doc.head.appendChild(reset);
|
|
55
|
-
doc.body.setAttribute("inert", "");
|
|
56
|
-
const generation = initialization.current = initialization.current + 1;
|
|
57
|
-
Promise.all(stylesheetsLoaded).then(() => {
|
|
58
|
-
if (initialization.current === generation) setRoot(mount);
|
|
59
|
-
});
|
|
60
|
-
};
|
|
61
|
-
$[0] = frame?.contentDocument;
|
|
62
|
-
$[1] = sourceDocument;
|
|
63
|
-
$[2] = t1;
|
|
64
|
-
} else t1 = $[2];
|
|
65
|
-
const initialize = t1;
|
|
66
|
-
let t2;
|
|
67
|
-
let t3;
|
|
68
|
-
if ($[3] !== initialize) {
|
|
69
|
-
t2 = () => {
|
|
70
|
-
initialize();
|
|
71
|
-
};
|
|
72
|
-
t3 = [initialize];
|
|
73
|
-
$[3] = initialize;
|
|
74
|
-
$[4] = t2;
|
|
75
|
-
$[5] = t3;
|
|
76
|
-
} else {
|
|
77
|
-
t2 = $[4];
|
|
78
|
-
t3 = $[5];
|
|
79
|
-
}
|
|
80
|
-
React.useEffect(t2, t3);
|
|
81
|
-
let t4;
|
|
82
|
-
let t5;
|
|
83
|
-
if ($[6] !== content) {
|
|
84
|
-
t4 = () => {
|
|
85
|
-
if (!content) return;
|
|
86
|
-
const observer = new ResizeObserver(() => {
|
|
87
|
-
setContentHeight(content.getBoundingClientRect().height);
|
|
88
|
-
});
|
|
89
|
-
observer.observe(content);
|
|
90
|
-
return () => observer.disconnect();
|
|
91
|
-
};
|
|
92
|
-
t5 = [content];
|
|
93
|
-
$[6] = content;
|
|
94
|
-
$[7] = t4;
|
|
95
|
-
$[8] = t5;
|
|
96
|
-
} else {
|
|
97
|
-
t4 = $[7];
|
|
98
|
-
t5 = $[8];
|
|
99
|
-
}
|
|
100
|
-
React.useEffect(t4, t5);
|
|
101
|
-
const t6 = contentHeight * width / VIEWPORT_WIDTH;
|
|
102
|
-
let t7;
|
|
103
|
-
if ($[9] !== t6) {
|
|
104
|
-
t7 = { height: t6 };
|
|
105
|
-
$[9] = t6;
|
|
106
|
-
$[10] = t7;
|
|
107
|
-
} else t7 = $[10];
|
|
108
|
-
const t8 = `${title} preview`;
|
|
109
|
-
const t9 = `scale(${width / VIEWPORT_WIDTH})`;
|
|
110
|
-
let t10;
|
|
111
|
-
if ($[11] !== t9) {
|
|
112
|
-
t10 = {
|
|
113
|
-
width: VIEWPORT_WIDTH,
|
|
114
|
-
height: VIEWPORT_HEIGHT,
|
|
115
|
-
transform: t9
|
|
116
|
-
};
|
|
117
|
-
$[11] = t9;
|
|
118
|
-
$[12] = t10;
|
|
119
|
-
} else t10 = $[12];
|
|
120
|
-
let t11;
|
|
121
|
-
if ($[13] !== initialize || $[14] !== t10 || $[15] !== t8) {
|
|
122
|
-
t11 = /* @__PURE__ */ jsx("iframe", {
|
|
123
|
-
ref: setFrame,
|
|
124
|
-
title: t8,
|
|
125
|
-
srcDoc: EMPTY_PREVIEW_DOCUMENT,
|
|
126
|
-
onLoad: initialize,
|
|
127
|
-
tabIndex: -1,
|
|
128
|
-
className: "pointer-events-none absolute top-0 left-0 origin-top-left border-0",
|
|
129
|
-
style: t10
|
|
130
|
-
});
|
|
131
|
-
$[13] = initialize;
|
|
132
|
-
$[14] = t10;
|
|
133
|
-
$[15] = t8;
|
|
134
|
-
$[16] = t11;
|
|
135
|
-
} else t11 = $[16];
|
|
136
|
-
let t12;
|
|
137
|
-
if ($[17] !== blockType || $[18] !== content || $[19] !== frame || $[20] !== root) {
|
|
138
|
-
t12 = root && createPortal(/* @__PURE__ */ jsx(FrameContext.Provider, {
|
|
139
|
-
value: {
|
|
140
|
-
window: frame?.contentWindow ?? null,
|
|
141
|
-
iframeElement: frame
|
|
142
|
-
},
|
|
143
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
144
|
-
ref: setContent,
|
|
145
|
-
style: { display: "flow-root" },
|
|
146
|
-
children: content && /* @__PURE__ */ jsx(ThumbnailContent, {
|
|
147
|
-
blockType,
|
|
148
|
-
slot: content
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
}), root);
|
|
152
|
-
$[17] = blockType;
|
|
153
|
-
$[18] = content;
|
|
154
|
-
$[19] = frame;
|
|
155
|
-
$[20] = root;
|
|
156
|
-
$[21] = t12;
|
|
157
|
-
} else t12 = $[21];
|
|
158
|
-
let t13;
|
|
159
|
-
if ($[22] !== t11 || $[23] !== t12 || $[24] !== t7) {
|
|
160
|
-
t13 = /* @__PURE__ */ jsxs("div", {
|
|
161
|
-
className: "relative max-h-full w-full shrink-0 overflow-hidden",
|
|
162
|
-
style: t7,
|
|
163
|
-
children: [t11, t12]
|
|
164
|
-
});
|
|
165
|
-
$[22] = t11;
|
|
166
|
-
$[23] = t12;
|
|
167
|
-
$[24] = t7;
|
|
168
|
-
$[25] = t13;
|
|
169
|
-
} else t13 = $[25];
|
|
170
|
-
return t13;
|
|
171
|
-
};
|
|
172
|
-
/**
|
|
173
|
-
* What the thumbnail shows: the block rendered into `slot` by the renderer frame, which runs the
|
|
174
|
-
* draft's code.
|
|
175
|
-
*/
|
|
176
|
-
const ThumbnailContent = (t0) => {
|
|
177
|
-
const $ = c(6);
|
|
178
|
-
const { blockType, slot } = t0;
|
|
179
|
-
const host = useRendererHost();
|
|
180
|
-
const thumbnailId = React.useId();
|
|
181
|
-
let t1;
|
|
182
|
-
let t2;
|
|
183
|
-
if ($[0] !== blockType || $[1] !== host || $[2] !== slot || $[3] !== thumbnailId) {
|
|
184
|
-
t1 = () => {
|
|
185
|
-
if (!host) return;
|
|
186
|
-
host.showThumbnail(thumbnailId, slot, blockType);
|
|
187
|
-
return () => host.hideThumbnail(thumbnailId);
|
|
188
|
-
};
|
|
189
|
-
t2 = [
|
|
190
|
-
host,
|
|
191
|
-
thumbnailId,
|
|
192
|
-
slot,
|
|
193
|
-
blockType
|
|
194
|
-
];
|
|
195
|
-
$[0] = blockType;
|
|
196
|
-
$[1] = host;
|
|
197
|
-
$[2] = slot;
|
|
198
|
-
$[3] = thumbnailId;
|
|
199
|
-
$[4] = t1;
|
|
200
|
-
$[5] = t2;
|
|
201
|
-
} else {
|
|
202
|
-
t1 = $[4];
|
|
203
|
-
t2 = $[5];
|
|
204
|
-
}
|
|
205
|
-
React.useLayoutEffect(t1, t2);
|
|
206
|
-
return null;
|
|
207
|
-
};
|
|
208
|
-
/** A block's thumbnail, rendered by the renderer frame with the draft's code. */
|
|
209
|
-
const BlockThumbnail = (t0) => {
|
|
210
|
-
const $ = c(13);
|
|
211
|
-
const { blockType, title, className } = t0;
|
|
212
|
-
const ref = React.useRef(null);
|
|
213
|
-
const [isVisible, setIsVisible] = React.useState(false);
|
|
214
|
-
const [width, setWidth] = React.useState(0);
|
|
215
|
-
const renderable = !!useRendererHost();
|
|
216
|
-
let t1;
|
|
217
|
-
let t2;
|
|
218
|
-
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
|
219
|
-
t1 = () => {
|
|
220
|
-
const element = ref.current;
|
|
221
|
-
if (!element) return;
|
|
222
|
-
const intersectionObserver = new IntersectionObserver((t3) => {
|
|
223
|
-
const [entry] = t3;
|
|
224
|
-
setIsVisible(entry.isIntersecting);
|
|
225
|
-
});
|
|
226
|
-
const resizeObserver = new ResizeObserver((t4) => {
|
|
227
|
-
const [entry_0] = t4;
|
|
228
|
-
setWidth(entry_0.contentRect.width);
|
|
229
|
-
});
|
|
230
|
-
intersectionObserver.observe(element);
|
|
231
|
-
resizeObserver.observe(element);
|
|
232
|
-
return () => {
|
|
233
|
-
intersectionObserver.disconnect();
|
|
234
|
-
resizeObserver.disconnect();
|
|
235
|
-
};
|
|
236
|
-
};
|
|
237
|
-
t2 = [];
|
|
238
|
-
$[0] = t1;
|
|
239
|
-
$[1] = t2;
|
|
240
|
-
} else {
|
|
241
|
-
t1 = $[0];
|
|
242
|
-
t2 = $[1];
|
|
243
|
-
}
|
|
244
|
-
React.useEffect(t1, t2);
|
|
245
|
-
let t3;
|
|
246
|
-
if ($[2] !== className) {
|
|
247
|
-
t3 = cn("bg-muted pointer-events-none relative flex h-28 w-full items-center overflow-hidden", className);
|
|
248
|
-
$[2] = className;
|
|
249
|
-
$[3] = t3;
|
|
250
|
-
} else t3 = $[3];
|
|
251
|
-
let t4;
|
|
252
|
-
if ($[4] !== blockType || $[5] !== isVisible || $[6] !== renderable || $[7] !== title || $[8] !== width) {
|
|
253
|
-
t4 = renderable && isVisible && width > 0 && /* @__PURE__ */ jsx(ThumbnailFrame, {
|
|
254
|
-
blockType,
|
|
255
|
-
title,
|
|
256
|
-
width
|
|
257
|
-
});
|
|
258
|
-
$[4] = blockType;
|
|
259
|
-
$[5] = isVisible;
|
|
260
|
-
$[6] = renderable;
|
|
261
|
-
$[7] = title;
|
|
262
|
-
$[8] = width;
|
|
263
|
-
$[9] = t4;
|
|
264
|
-
} else t4 = $[9];
|
|
265
|
-
let t5;
|
|
266
|
-
if ($[10] !== t3 || $[11] !== t4) {
|
|
267
|
-
t5 = /* @__PURE__ */ jsx("div", {
|
|
268
|
-
ref,
|
|
269
|
-
className: t3,
|
|
270
|
-
"aria-hidden": "true",
|
|
271
|
-
children: t4
|
|
272
|
-
});
|
|
273
|
-
$[10] = t3;
|
|
274
|
-
$[11] = t4;
|
|
275
|
-
$[12] = t5;
|
|
276
|
-
} else t5 = $[12];
|
|
277
|
-
return t5;
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
//#endregion
|
|
281
|
-
export { BlockThumbnail };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
//#region src/features/preview/components/blockGridNavigation.ts
|
|
2
|
-
/** Move within a non-wrapping grid, clamping down into a short final row. */
|
|
3
|
-
function getGridNavigationIndex(index, count, columns, key) {
|
|
4
|
-
if (count === 0) return -1;
|
|
5
|
-
if (index < 0) return 0;
|
|
6
|
-
const column = index % columns;
|
|
7
|
-
if (key === "ArrowLeft") return column > 0 ? index - 1 : index;
|
|
8
|
-
if (key === "ArrowRight") return column < columns - 1 ? Math.min(index + 1, count - 1) : index;
|
|
9
|
-
if (key === "ArrowUp") return index >= columns ? index - columns : index;
|
|
10
|
-
if (key === "ArrowDown") return (Math.floor(index / columns) + 1) * columns < count ? Math.min(index + columns, count - 1) : index;
|
|
11
|
-
return index;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
export { getGridNavigationIndex };
|