camox 0.32.0 → 0.33.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 (58) hide show
  1. package/dist/core/createBlock.d.ts +1 -1
  2. package/dist/core/createBlock.js +88 -108
  3. package/dist/core/hooks/useIsEditable.js +6 -10
  4. package/dist/core/lib/fieldTypes.js +10 -219
  5. package/dist/features/agent-chat/components/AgentChatSidebar.js +172 -0
  6. package/dist/features/agent-chat/components/AgentChatThread.js +9 -9
  7. package/dist/features/preview/CamoxPreview.js +137 -729
  8. package/dist/features/preview/components/{AddBlockSheet.js → AddBlockSidebar.js} +121 -131
  9. package/dist/features/preview/components/AssetFieldEditor.js +107 -82
  10. package/dist/features/preview/components/AssetLightbox.js +4 -4
  11. package/dist/features/preview/components/AssetPickerModal.js +277 -0
  12. package/dist/features/preview/components/BlockActionsPopover.js +18 -24
  13. package/dist/features/preview/components/CreatePageModal.js +6 -6
  14. package/dist/features/preview/components/FieldToolbar.js +64 -127
  15. package/dist/features/preview/components/ItemFieldsEditor.js +98 -125
  16. package/dist/features/preview/components/LeftSidebar.js +64 -0
  17. package/dist/features/preview/components/LinkFieldEditor.js +1 -1
  18. package/dist/features/preview/components/MultipleAssetFieldEditor.js +94 -56
  19. package/dist/features/preview/components/OverlayTracker.js +15 -15
  20. package/dist/features/preview/components/Overlays.js +12 -12
  21. package/dist/features/preview/components/PageEditorSidebar.js +563 -0
  22. package/dist/features/preview/components/PageInfoSidebar.js +1453 -0
  23. package/dist/features/preview/components/PageNavigatorSidebar.js +590 -0
  24. package/dist/features/preview/components/PagePicker.js +3 -3
  25. package/dist/features/preview/components/PageStatusBadge.js +1 -1
  26. package/dist/features/preview/components/PageTree.js +204 -564
  27. package/dist/features/preview/components/PreviewPanel.js +123 -158
  28. package/dist/features/preview/components/PreviewToolbar.js +260 -256
  29. package/dist/features/preview/components/PublishDialog.js +2 -2
  30. package/dist/features/preview/components/RepeatableItemsList.js +2 -2
  31. package/dist/features/preview/components/RightSidebar.js +109 -0
  32. package/dist/features/preview/components/UnlinkAssetButton.js +2 -2
  33. package/dist/features/preview/components/useRepeatableItemActions.js +3 -138
  34. package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
  35. package/dist/features/preview/previewQueryFns.js +23 -0
  36. package/dist/features/preview/previewStore.js +46 -63
  37. package/dist/features/provider/CamoxProvider.js +255 -70
  38. package/dist/features/provider/useAdminShortcuts.js +5 -48
  39. package/dist/features/routes/pageRoute.js +1 -1
  40. package/dist/features/studio/CamoxStudio.js +6 -5
  41. package/dist/features/studio/components/EnvironmentMenu.js +2 -2
  42. package/dist/features/studio/components/Navbar.js +53 -71
  43. package/dist/features/studio/components/ProjectMenu.js +1 -1
  44. package/dist/features/studio/components/UserButton.js +1 -1
  45. package/dist/features/studio/routes.js +7 -0
  46. package/dist/features/studio/useTheme.js +67 -33
  47. package/dist/features/vite/routeGeneration.js +68 -66
  48. package/dist/hooks/use-file-upload.js +1 -1
  49. package/dist/lib/auth.js +23 -22
  50. package/dist/lib/utils.js +1 -1
  51. package/dist/studio-overlays.css +1 -1
  52. package/dist/studio.css +1 -1
  53. package/package.json +4 -4
  54. package/dist/features/agent-chat/components/AgentChatSheet.js +0 -207
  55. package/dist/features/preview/components/AssetPickerGrid.js +0 -236
  56. package/dist/features/preview/components/PageContentSheet.js +0 -608
  57. package/dist/features/preview/components/PageMetadataModal.js +0 -908
  58. package/dist/features/preview/components/PreviewSideSheet.js +0 -76
@@ -1,608 +0,0 @@
1
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
2
- import { previewStore, selectionBlockId, selectionField, selectionItemId } from "../previewStore.js";
3
- import { PreviewSideSheet, Sheet } from "./PreviewSideSheet.js";
4
- import { actionsStore } from "../../provider/actionsStore.js";
5
- import { blockMutations, blockQueries, fileQueries, repeatableItemMutations } from "../../../lib/queries.js";
6
- import { cn } from "../../../lib/utils.js";
7
- import { isFileMarker } from "../../../lib/normalized-data.js";
8
- import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
9
- import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
10
- import { fieldTypesDictionary } from "../../../core/lib/fieldTypes.js";
11
- import { SingleAssetFieldEditor } from "./AssetFieldEditor.js";
12
- import { useRepeatableItemActions } from "./useRepeatableItemActions.js";
13
- import { ItemFieldsEditor, formatFieldName } from "./ItemFieldsEditor.js";
14
- import { LinkFieldEditor } from "./LinkFieldEditor.js";
15
- import { MultipleAssetFieldEditor } from "./MultipleAssetFieldEditor.js";
16
- import { Label } from "@camox/ui/label";
17
- import { useMutation, useQueries, useQuery } from "@tanstack/react-query";
18
- import { useSelector } from "@xstate/store-react";
19
- import * as React from "react";
20
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
21
- import { Button } from "@camox/ui/button";
22
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@camox/ui/dropdown-menu";
23
- import { Switch } from "@camox/ui/switch";
24
- import { CircleMinus, CirclePlus, CornerLeftUp } from "lucide-react";
25
- import { Spinner } from "@camox/ui/spinner";
26
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@camox/ui/select";
27
- import { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from "@camox/ui/breadcrumb";
28
-
29
- //#region src/features/preview/components/PageContentSheet.tsx
30
- const getSettingsFields = (schema) => {
31
- const properties = schema?.properties;
32
- if (!properties) return [];
33
- return Object.keys(properties).map((fieldName) => {
34
- const prop = properties[fieldName];
35
- return {
36
- name: fieldName,
37
- fieldType: prop.fieldType,
38
- label: prop.title,
39
- enumLabels: prop.enumLabels,
40
- enumValues: prop.enum
41
- };
42
- });
43
- };
44
- /**
45
- * Builds the path of fieldNames from the block root to the given item,
46
- * then walks the schema down that path to return the sub-schema for the item's fields.
47
- */
48
- const getSchemaForItem = (contentSchema, itemId, itemsMap) => {
49
- const path = [];
50
- let current = itemsMap.get(itemId);
51
- while (current) {
52
- path.unshift(current.fieldName);
53
- current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
54
- }
55
- let schema = contentSchema;
56
- for (const fieldName of path) {
57
- const prop = schema?.properties?.[fieldName];
58
- if (!prop?.items) return null;
59
- schema = prop.items;
60
- }
61
- return schema;
62
- };
63
- /**
64
- * Like `getSchemaForItem` but returns the **array** schema (one level above
65
- * the items schema), where per-item settings metadata lives.
66
- */
67
- const getArraySchemaForItem = (contentSchema, itemId, itemsMap) => {
68
- const path = [];
69
- let current = itemsMap.get(itemId);
70
- while (current) {
71
- path.unshift(current.fieldName);
72
- current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
73
- }
74
- let schema = contentSchema;
75
- for (let i = 0; i < path.length; i++) {
76
- const prop = schema?.properties?.[path[i]];
77
- if (!prop?.items) return null;
78
- if (i === path.length - 1) return prop;
79
- schema = prop.items;
80
- }
81
- return null;
82
- };
83
- /**
84
- * Builds the ancestor chain from root to this item (inclusive).
85
- * Returns items in order from root-most ancestor to the item itself.
86
- */
87
- const buildAncestorChain = (itemId, itemsMap) => {
88
- const chain = [];
89
- let current = itemsMap.get(itemId);
90
- while (current) {
91
- chain.unshift(current);
92
- current = current.parentItemId ? itemsMap.get(current.parentItemId) : void 0;
93
- }
94
- return chain;
95
- };
96
- const PageContentSheet = () => {
97
- const camoxApp = useCamoxApp();
98
- const updateContent = useMutation(blockMutations.updateContent());
99
- const updateSettings = useMutation(blockMutations.updateSettings());
100
- const updateRepeatableContent = useMutation(repeatableItemMutations.updateContent());
101
- const updateRepeatableSettings = useMutation(repeatableItemMutations.updateSettings());
102
- const requireDraft = useRequireDraftSource();
103
- const isOpen = useSelector(previewStore, (state) => state.context.isPageContentSheetOpen);
104
- const selection = useSelector(previewStore, (state_0) => state_0.context.selection);
105
- const iframeElement = useSelector(previewStore, (state_1) => state_1.context.iframeElement);
106
- const isReadOnly = useSelector(previewStore, (state_2) => state_2.context.previewSource) !== "draft";
107
- const postToIframe = React.useCallback((message) => {
108
- if (!iframeElement?.contentWindow) return;
109
- iframeElement.contentWindow.postMessage(message, "*");
110
- }, [iframeElement]);
111
- const blockId = selectionBlockId(selection);
112
- const currentItemId = selectionItemId(selection);
113
- const fieldInfo = selectionField(selection);
114
- const { data: blockBundle } = useQuery({
115
- ...blockQueries.get(blockId),
116
- enabled: blockId != null
117
- });
118
- const block = blockBundle?.block ?? null;
119
- const itemsMap = React.useMemo(() => new Map((blockBundle?.repeatableItems ?? []).map((i) => [i.id, i])), [blockBundle?.repeatableItems]);
120
- const fileIds = React.useMemo(() => (blockBundle?.files ?? []).map((f) => f.id), [blockBundle?.files]);
121
- const fileResults = useQueries({ queries: fileIds.map((id) => fileQueries.get(id)) });
122
- const filesMap = React.useMemo(() => {
123
- const map = new Map((blockBundle?.files ?? []).map((f_0) => [f_0.id, f_0]));
124
- for (let i_0 = 0; i_0 < fileIds.length; i_0++) {
125
- const data = fileResults[i_0]?.data;
126
- if (data) map.set(data.id, data);
127
- }
128
- return map;
129
- }, [
130
- blockBundle?.files,
131
- fileIds,
132
- fileResults
133
- ]);
134
- const blockDef = block ? camoxApp.getBlockById(block.type) : null;
135
- const settingsFields = React.useMemo(() => {
136
- return blockDef ? getSettingsFields(blockDef._internal.settingsSchema) : [];
137
- }, [blockDef]);
138
- const itemArraySchema = React.useMemo(() => {
139
- if (!blockDef || currentItemId == null) return null;
140
- return getArraySchemaForItem(blockDef._internal.contentSchema, currentItemId, itemsMap);
141
- }, [
142
- blockDef,
143
- currentItemId,
144
- itemsMap
145
- ]);
146
- const itemSettingsFields = React.useMemo(() => {
147
- return getSettingsFields(itemArraySchema?.itemSettingsSchema);
148
- }, [itemArraySchema]);
149
- const currentSchema = React.useMemo(() => {
150
- if (!blockDef) return null;
151
- if (currentItemId == null) return blockDef._internal.contentSchema;
152
- return getSchemaForItem(blockDef._internal.contentSchema, currentItemId, itemsMap);
153
- }, [
154
- blockDef,
155
- currentItemId,
156
- itemsMap
157
- ]);
158
- const currentItem = currentItemId != null ? itemsMap.get(currentItemId) : null;
159
- const isItemLoading = currentItemId != null && !currentItem;
160
- const siblingCount = React.useMemo(() => {
161
- if (!currentItem) return 0;
162
- let count = 0;
163
- for (const it of itemsMap.values()) if (it.fieldName === currentItem.fieldName && it.parentItemId === currentItem.parentItemId) count++;
164
- return count;
165
- }, [currentItem, itemsMap]);
166
- const { canAdd: canAddSibling, addItem: addSibling, canRemove: canRemoveCurrent, removeItem: removeCurrent } = useRepeatableItemActions({
167
- blockId: block?.id ?? -1,
168
- fieldName: currentItem?.fieldName ?? "",
169
- parentItemId: currentItem?.parentItemId ?? null,
170
- arraySchema: itemArraySchema,
171
- siblingCount
172
- });
173
- const rawCurrentData = currentItem ? currentItem.content : block?.content ?? {};
174
- const currentData = React.useMemo(() => {
175
- const resolveFile = (marker) => {
176
- const file = filesMap.get(marker._fileId);
177
- return file ? {
178
- url: file.url,
179
- alt: file.alt,
180
- filename: file.filename,
181
- mimeType: file.mimeType,
182
- _fileId: marker._fileId
183
- } : {
184
- url: "",
185
- alt: "",
186
- filename: "",
187
- mimeType: ""
188
- };
189
- };
190
- const resolveValue = (value) => {
191
- if (isFileMarker(value)) return resolveFile(value);
192
- if (Array.isArray(value)) return value.map(resolveValue);
193
- if (value && typeof value === "object" && !Array.isArray(value)) {
194
- const obj = value;
195
- const resolved = {};
196
- for (const [k, v] of Object.entries(obj)) resolved[k] = resolveValue(v);
197
- return resolved;
198
- }
199
- return value;
200
- };
201
- const resolved_0 = {};
202
- for (const [key, value_0] of Object.entries(rawCurrentData)) resolved_0[key] = resolveValue(value_0);
203
- return resolved_0;
204
- }, [rawCurrentData, filesMap]);
205
- const isViewingLink = fieldInfo?.fieldType === "Link";
206
- const linkFieldName = isViewingLink ? fieldInfo.fieldName : null;
207
- const isViewingImage = fieldInfo?.fieldType === "Image";
208
- const imageFieldName = isViewingImage ? fieldInfo.fieldName : null;
209
- const isViewingFile = fieldInfo?.fieldType === "File";
210
- const fileFieldName = isViewingFile ? fieldInfo.fieldName : null;
211
- const isViewingAsset = isViewingImage || isViewingFile;
212
- const assetFieldName = imageFieldName ?? fileFieldName;
213
- const assetType = isViewingImage ? "Image" : "File";
214
- const isMultipleAsset = React.useMemo(() => {
215
- if (!isViewingAsset || !assetFieldName) return false;
216
- const prop = currentSchema?.properties?.[assetFieldName];
217
- return prop?.fieldType === "ImageList" || prop?.fieldType === "FileList";
218
- }, [
219
- isViewingAsset,
220
- assetFieldName,
221
- currentSchema
222
- ]);
223
- const sessionDirtyRef = React.useRef(false);
224
- const trackedOpenRef = React.useRef(false);
225
- React.useEffect(() => {
226
- if (!isOpen) {
227
- trackedOpenRef.current = false;
228
- return;
229
- }
230
- if (trackedOpenRef.current) return;
231
- if (!block) return;
232
- trackedOpenRef.current = true;
233
- sessionDirtyRef.current = false;
234
- trackClientEvent("content_sheet_opened", { blockType: block.type });
235
- }, [isOpen, block]);
236
- const fieldIdPrefix = React.useId();
237
- const autoFocusFieldName = React.useMemo(() => {
238
- if ((selection?.type === "block-field" || selection?.type === "item-field") && (selection.fieldType === "String" || selection.fieldType === "Embed")) return selection.fieldName;
239
- const properties = currentSchema?.properties;
240
- if (!properties) return null;
241
- for (const name of Object.keys(properties)) {
242
- const ft = properties[name]?.fieldType;
243
- if (ft === "String" || ft === "Embed") return name;
244
- }
245
- return null;
246
- }, [selection, currentSchema]);
247
- const getInitialFocus = React.useCallback(() => {
248
- if (!autoFocusFieldName) return null;
249
- return document.getElementById(`${fieldIdPrefix}-${autoFocusFieldName}`);
250
- }, [autoFocusFieldName, fieldIdPrefix]);
251
- React.useEffect(() => {
252
- const action = {
253
- id: "toggle-content-sheet",
254
- label: isOpen ? "Close form" : "Open in form",
255
- groupLabel: "Preview",
256
- shortcut: {
257
- key: "j",
258
- withAlt: true
259
- },
260
- checkIfAvailable: () => blockId != null,
261
- execute: () => {
262
- previewStore.send({ type: "toggleContentSheet" });
263
- }
264
- };
265
- actionsStore.send({
266
- type: "registerAction",
267
- action
268
- });
269
- return () => actionsStore.send({
270
- type: "unregisterAction",
271
- id: action.id
272
- });
273
- }, [blockId, isOpen]);
274
- const handleBlockFieldChange = React.useCallback((fieldName, value_1) => {
275
- if (!block) return;
276
- if (!requireDraft()) return;
277
- sessionDirtyRef.current = true;
278
- updateContent.mutate({
279
- id: block.id,
280
- content: { [fieldName]: value_1 }
281
- });
282
- }, [
283
- block,
284
- updateContent,
285
- requireDraft
286
- ]);
287
- const handleItemFieldChange = React.useCallback((fieldName_0, value_2) => {
288
- if (currentItemId == null) return;
289
- if (!requireDraft()) return;
290
- sessionDirtyRef.current = true;
291
- updateRepeatableContent.mutate({
292
- id: currentItemId,
293
- content: { [fieldName_0]: value_2 }
294
- });
295
- }, [
296
- currentItemId,
297
- updateRepeatableContent,
298
- requireDraft
299
- ]);
300
- const activeFieldChangeHandler = currentItemId != null ? handleItemFieldChange : handleBlockFieldChange;
301
- const handleOpenChange = (open) => {
302
- if (open) return;
303
- if (block && sessionDirtyRef.current) trackClientEvent("block_edited", {
304
- via: "content-sheet",
305
- blockType: block.type
306
- });
307
- sessionDirtyRef.current = false;
308
- if (block && autoFocusFieldName) postToIframe({
309
- type: "CAMOX_FOCUS_FIELD_END",
310
- fieldId: currentItemId != null ? `${block.id}__${currentItemId}__${autoFocusFieldName}` : `${block.id}__${autoFocusFieldName}`
311
- });
312
- if (block && currentItemId != null) postToIframe({
313
- type: "CAMOX_HOVER_REPEATER_ITEM_END",
314
- blockId: String(block.id),
315
- itemId: String(currentItemId)
316
- });
317
- previewStore.send({ type: "closeBlockContentSheet" });
318
- };
319
- const ancestorChain = React.useMemo(() => currentItemId != null ? buildAncestorChain(currentItemId, itemsMap) : [], [currentItemId, itemsMap]);
320
- if (!block || !blockDef || !currentSchema) return null;
321
- const fieldHasOwnView = fieldInfo ? fieldTypesDictionary[fieldInfo.fieldType].hasOwnView : false;
322
- const isAtBlockLevel = ancestorChain.length === 0 && !fieldHasOwnView;
323
- return /* @__PURE__ */ jsxs(PreviewSideSheet, {
324
- open: isOpen,
325
- onOpenChange: handleOpenChange,
326
- initialFocus: getInitialFocus,
327
- className: "flex flex-col gap-0",
328
- children: [/* @__PURE__ */ jsxs(Sheet.SheetHeader, {
329
- className: "border-border border-b",
330
- children: [/* @__PURE__ */ jsx(Sheet.SheetTitle, { children: block.summary }), /* @__PURE__ */ jsx(Sheet.SheetDescription, {
331
- render: /* @__PURE__ */ jsx(Breadcrumb, {}),
332
- children: /* @__PURE__ */ jsxs(BreadcrumbList, {
333
- className: "flex-nowrap",
334
- children: [
335
- /* @__PURE__ */ jsx(BreadcrumbItem, {
336
- className: "min-w-0",
337
- children: isAtBlockLevel ? /* @__PURE__ */ jsx(BreadcrumbPage, {
338
- className: "truncate",
339
- children: blockDef._internal.title
340
- }) : /* @__PURE__ */ jsx(BreadcrumbLink, {
341
- className: "cursor-pointer",
342
- onClick: () => previewStore.send({
343
- type: "setFocusedBlock",
344
- blockId: block.id
345
- }),
346
- children: blockDef._internal.title
347
- })
348
- }),
349
- ancestorChain.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
350
- ancestorChain.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
351
- className: "flex items-center gap-1",
352
- children: /* @__PURE__ */ jsx(BreadcrumbEllipsis, { className: "size-5" })
353
- }), /* @__PURE__ */ jsx(DropdownMenuContent, {
354
- align: "start",
355
- children: ancestorChain.slice(0, -1).map((ancestor) => /* @__PURE__ */ jsx(DropdownMenuItem, {
356
- onClick: () => previewStore.send({
357
- type: "selectItem",
358
- blockId: block.id,
359
- itemId: ancestor.id
360
- }),
361
- children: ancestor.summary || formatFieldName(ancestor.fieldName)
362
- }, ancestor.id))
363
- })] }) })] }),
364
- /* @__PURE__ */ jsx(BreadcrumbSeparator, {}),
365
- (() => {
366
- const lastAncestor = ancestorChain[ancestorChain.length - 1];
367
- const crumbLabel = lastAncestor.summary || formatFieldName(lastAncestor.fieldName);
368
- if (fieldHasOwnView) return /* @__PURE__ */ jsx(BreadcrumbItem, {
369
- className: "min-w-0",
370
- children: /* @__PURE__ */ jsx(BreadcrumbLink, {
371
- className: "cursor-pointer truncate",
372
- onClick: () => previewStore.send({ type: "selectParent" }),
373
- children: crumbLabel
374
- })
375
- });
376
- return /* @__PURE__ */ jsx(BreadcrumbItem, {
377
- className: "min-w-0",
378
- children: /* @__PURE__ */ jsx(BreadcrumbPage, {
379
- className: "truncate",
380
- children: crumbLabel
381
- })
382
- });
383
- })()
384
- ] }),
385
- fieldHasOwnView && fieldInfo && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(BreadcrumbSeparator, {}), /* @__PURE__ */ jsx(BreadcrumbItem, {
386
- className: "min-w-0",
387
- children: /* @__PURE__ */ jsx(BreadcrumbPage, {
388
- className: "truncate",
389
- children: currentSchema?.properties?.[fieldInfo.fieldName]?.title ?? formatFieldName(fieldInfo.fieldName)
390
- })
391
- })] })
392
- ]
393
- })
394
- })]
395
- }), /* @__PURE__ */ jsxs("div", {
396
- className: "relative flex-1 overflow-auto",
397
- children: [isReadOnly && /* @__PURE__ */ jsx("button", {
398
- type: "button",
399
- "aria-label": "Switch to draft to edit",
400
- className: "absolute inset-0 z-10 h-full w-full cursor-not-allowed",
401
- onClick: () => previewStore.send({ type: "requestDraftSwitch" })
402
- }), /* @__PURE__ */ jsx("div", {
403
- className: cn(isReadOnly && "pointer-events-none opacity-50"),
404
- children: isItemLoading ? /* @__PURE__ */ jsx("div", {
405
- className: "flex h-full items-center justify-center py-12",
406
- children: /* @__PURE__ */ jsx(Spinner, {})
407
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [
408
- currentItemId == null && !fieldHasOwnView && settingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
409
- className: "border-border space-y-4 border-b px-4 py-4",
410
- children: [/* @__PURE__ */ jsx(Label, {
411
- className: "text-muted-foreground",
412
- children: "Settings"
413
- }), settingsFields.map((field) => {
414
- const label = field.label ?? formatFieldName(field.name);
415
- const settingsValues = block.settings ?? {};
416
- if (field.fieldType === "Enum") {
417
- const value_3 = settingsValues[field.name] ?? (blockDef._internal.settingsSchema?.properties?.[field.name])?.default ?? "";
418
- return /* @__PURE__ */ jsxs("div", {
419
- className: "space-y-2",
420
- children: [/* @__PURE__ */ jsx(Label, {
421
- htmlFor: `setting-${field.name}`,
422
- children: label
423
- }), /* @__PURE__ */ jsxs(Select, {
424
- value: value_3,
425
- onValueChange: (newValue) => {
426
- if (!requireDraft()) return;
427
- sessionDirtyRef.current = true;
428
- updateSettings.mutate({
429
- id: block.id,
430
- settings: { [field.name]: newValue }
431
- });
432
- },
433
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
434
- id: `setting-${field.name}`,
435
- children: /* @__PURE__ */ jsx(SelectValue, {})
436
- }), /* @__PURE__ */ jsx(SelectContent, { children: field.enumValues?.map((enumValue) => /* @__PURE__ */ jsx(SelectItem, {
437
- value: enumValue,
438
- children: field.enumLabels?.[enumValue] ?? enumValue
439
- }, enumValue)) })]
440
- })]
441
- }, field.name);
442
- }
443
- if (field.fieldType === "Boolean") {
444
- const checked = settingsValues[field.name] ?? (blockDef._internal.settingsSchema?.properties?.[field.name])?.default ?? false;
445
- return /* @__PURE__ */ jsxs("div", {
446
- className: "flex items-center justify-between",
447
- children: [/* @__PURE__ */ jsx(Label, {
448
- htmlFor: `setting-${field.name}`,
449
- children: label
450
- }), /* @__PURE__ */ jsx(Switch, {
451
- id: `setting-${field.name}`,
452
- checked,
453
- onCheckedChange: (newValue_0) => {
454
- if (!requireDraft()) return;
455
- sessionDirtyRef.current = true;
456
- updateSettings.mutate({
457
- id: block.id,
458
- settings: { [field.name]: newValue_0 }
459
- });
460
- }
461
- })]
462
- }, field.name);
463
- }
464
- return null;
465
- })]
466
- }),
467
- currentItemId != null && !fieldHasOwnView && itemSettingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
468
- className: "border-border space-y-4 border-b px-4 py-4",
469
- children: [/* @__PURE__ */ jsx(Label, {
470
- className: "text-muted-foreground",
471
- children: "Settings"
472
- }), itemSettingsFields.map((field_0) => {
473
- const label_0 = field_0.label ?? formatFieldName(field_0.name);
474
- const itemSettingsValues = currentItem?.settings ?? {};
475
- const itemSettingsSchemaProps = itemArraySchema?.itemSettingsSchema?.properties;
476
- if (field_0.fieldType === "Enum") {
477
- const value_4 = itemSettingsValues[field_0.name] ?? itemSettingsSchemaProps?.[field_0.name]?.default ?? "";
478
- return /* @__PURE__ */ jsxs("div", {
479
- className: "space-y-2",
480
- children: [/* @__PURE__ */ jsx(Label, {
481
- htmlFor: `item-setting-${field_0.name}`,
482
- children: label_0
483
- }), /* @__PURE__ */ jsxs(Select, {
484
- value: value_4,
485
- onValueChange: (newValue_1) => {
486
- if (!requireDraft()) return;
487
- sessionDirtyRef.current = true;
488
- updateRepeatableSettings.mutate({
489
- id: currentItemId,
490
- settings: { [field_0.name]: newValue_1 }
491
- });
492
- },
493
- children: [/* @__PURE__ */ jsx(SelectTrigger, {
494
- id: `item-setting-${field_0.name}`,
495
- children: /* @__PURE__ */ jsx(SelectValue, {})
496
- }), /* @__PURE__ */ jsx(SelectContent, { children: field_0.enumValues?.map((enumValue_0) => /* @__PURE__ */ jsx(SelectItem, {
497
- value: enumValue_0,
498
- children: field_0.enumLabels?.[enumValue_0] ?? enumValue_0
499
- }, enumValue_0)) })]
500
- })]
501
- }, field_0.name);
502
- }
503
- if (field_0.fieldType === "Boolean") {
504
- const checked_0 = itemSettingsValues[field_0.name] ?? itemSettingsSchemaProps?.[field_0.name]?.default ?? false;
505
- return /* @__PURE__ */ jsxs("div", {
506
- className: "flex items-center justify-between",
507
- children: [/* @__PURE__ */ jsx(Label, {
508
- htmlFor: `item-setting-${field_0.name}`,
509
- children: label_0
510
- }), /* @__PURE__ */ jsx(Switch, {
511
- id: `item-setting-${field_0.name}`,
512
- checked: checked_0,
513
- onCheckedChange: (newValue_2) => {
514
- if (!requireDraft()) return;
515
- sessionDirtyRef.current = true;
516
- updateRepeatableSettings.mutate({
517
- id: currentItemId,
518
- settings: { [field_0.name]: newValue_2 }
519
- });
520
- }
521
- })]
522
- }, field_0.name);
523
- }
524
- return null;
525
- })]
526
- }),
527
- isViewingAsset && assetFieldName && isMultipleAsset && /* @__PURE__ */ jsx(MultipleAssetFieldEditor, {
528
- fieldName: assetFieldName,
529
- assetType,
530
- currentData,
531
- onFieldChange: activeFieldChangeHandler
532
- }),
533
- isViewingAsset && assetFieldName && !isMultipleAsset && /* @__PURE__ */ jsx(SingleAssetFieldEditor, {
534
- fieldName: assetFieldName,
535
- assetType,
536
- currentData,
537
- onFieldChange: activeFieldChangeHandler
538
- }),
539
- !isViewingAsset && isViewingLink && linkFieldName && /* @__PURE__ */ jsx("div", {
540
- className: "px-4 py-4",
541
- children: /* @__PURE__ */ jsx(LinkFieldEditor, {
542
- fieldName: linkFieldName,
543
- linkValue: currentData[linkFieldName] ?? {
544
- type: "external",
545
- text: "",
546
- href: "",
547
- newTab: false
548
- },
549
- onSave: (fieldName_1, value_5) => {
550
- activeFieldChangeHandler(fieldName_1, value_5);
551
- }
552
- })
553
- }),
554
- !isViewingAsset && !isViewingLink && (currentItemId == null || currentItem) && /* @__PURE__ */ jsx(ItemFieldsEditor, {
555
- schema: currentSchema,
556
- data: currentData,
557
- blockId: block.id,
558
- itemId: currentItemId ?? void 0,
559
- onFieldChange: activeFieldChangeHandler,
560
- postToIframe,
561
- filesMap,
562
- itemsMap,
563
- fieldIdPrefix,
564
- autoFocusFieldName
565
- }, currentItemId ?? `block-${block.id}`),
566
- !isViewingAsset && !isViewingLink && currentItemId != null && currentItem && /* @__PURE__ */ jsxs("div", {
567
- className: "border-border flex items-center gap-1 border-t px-4 py-4",
568
- children: [
569
- canAddSibling && /* @__PURE__ */ jsxs(Button, {
570
- type: "button",
571
- variant: "ghost",
572
- size: "sm",
573
- className: "text-muted-foreground justify-start",
574
- onClick: () => {
575
- if (!requireDraft()) return;
576
- addSibling({ afterPosition: currentItem.position });
577
- },
578
- children: [/* @__PURE__ */ jsx(CirclePlus, { className: "h-4 w-4" }), "Add item"]
579
- }),
580
- canRemoveCurrent && /* @__PURE__ */ jsxs(Button, {
581
- type: "button",
582
- variant: "ghost",
583
- size: "sm",
584
- className: "text-muted-foreground justify-start",
585
- onClick: () => {
586
- if (!requireDraft()) return;
587
- removeCurrent(currentItemId, { onSuccess: () => previewStore.send({ type: "selectParent" }) });
588
- },
589
- children: [/* @__PURE__ */ jsx(CircleMinus, { className: "h-4 w-4" }), "Remove item"]
590
- }),
591
- /* @__PURE__ */ jsxs(Button, {
592
- type: "button",
593
- variant: "ghost",
594
- size: "sm",
595
- className: "text-muted-foreground justify-start",
596
- onClick: () => previewStore.send({ type: "selectParent" }),
597
- children: [/* @__PURE__ */ jsx(CornerLeftUp, { className: "h-4 w-4" }), "Select parent"]
598
- })
599
- ]
600
- })
601
- ] })
602
- })]
603
- })]
604
- });
605
- };
606
-
607
- //#endregion
608
- export { PageContentSheet };