camox 0.41.1 → 0.42.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 (49) hide show
  1. package/dist/core/components/lexical/SidebarLexicalEditor.js +42 -39
  2. package/dist/core/createApp.d.ts +18 -4
  3. package/dist/core/createLayout.d.ts +1 -1
  4. package/dist/core/editing/createEditableBlock.d.ts +8 -1
  5. package/dist/core/editing/createEditableBlock.js +636 -459
  6. package/dist/core/hooks/useOverlayState.js +11 -0
  7. package/dist/core/lib/fieldTypes.js +5 -5
  8. package/dist/core/lib/lexicalState.js +17 -1
  9. package/dist/features/preview/CamoxPreview.js +80 -73
  10. package/dist/features/preview/commentsEnabled.js +8 -0
  11. package/dist/features/preview/components/AddBlockSidebar.js +79 -89
  12. package/dist/features/preview/components/AssetLightbox.js +4 -11
  13. package/dist/features/preview/components/AttachedComments.js +194 -0
  14. package/dist/features/preview/components/BlockActionsPopover.js +13 -64
  15. package/dist/features/preview/components/CommentHeader.js +122 -0
  16. package/dist/features/preview/components/CommentSidebar.js +29 -0
  17. package/dist/features/preview/components/CommentTargetQuote.js +166 -0
  18. package/dist/features/preview/components/CreatePageModal.js +2 -8
  19. package/dist/features/preview/components/ItemFieldsEditor.js +275 -204
  20. package/dist/features/preview/components/LeftSidebar.js +18 -18
  21. package/dist/features/preview/components/OverlayTracker.js +14 -20
  22. package/dist/features/preview/components/Overlays.js +26 -35
  23. package/dist/features/preview/components/PageEditorSidebar.js +89 -90
  24. package/dist/features/preview/components/PageInfoSidebar.js +126 -157
  25. package/dist/features/preview/components/PagePicker.js +13 -8
  26. package/dist/features/preview/components/PageTree.js +158 -156
  27. package/dist/features/preview/components/PreviewComments.js +56 -0
  28. package/dist/features/preview/components/PreviewPanel.js +122 -78
  29. package/dist/features/preview/components/PreviewToolbar.js +280 -231
  30. package/dist/features/preview/components/PublicationRow.js +4 -11
  31. package/dist/features/preview/components/RightSidebar.js +14 -11
  32. package/dist/features/preview/components/SidebarSection.js +121 -0
  33. package/dist/features/preview/previewCommentsStore.js +115 -0
  34. package/dist/features/preview/previewSelection.js +75 -0
  35. package/dist/features/preview/previewStore.js +19 -39
  36. package/dist/features/provider/AuthenticatedCamoxProvider.js +46 -34
  37. package/dist/features/provider/components/CommandPalette.js +142 -58
  38. package/dist/features/provider/useAdminShortcuts.js +19 -8
  39. package/dist/features/routes/pageRuntime.js +0 -6
  40. package/dist/features/runtime/RuntimeChrome.js +40 -37
  41. package/dist/features/studio/CamoxStudio.js +30 -50
  42. package/dist/features/vite/runtimeDev.js +4 -1
  43. package/dist/features/vite/vite.d.ts +3 -2
  44. package/dist/features/vite/vite.js +9 -5
  45. package/dist/hooks/use-file-upload.js +0 -2
  46. package/dist/studio.css +1 -1
  47. package/package.json +5 -7
  48. package/dist/lib/telemetry-client.js +0 -66
  49. package/dist/lib/telemetry.js +0 -26
@@ -8,9 +8,9 @@ import { useSelector } from "@xstate/store-react";
8
8
  //#region src/features/preview/components/LeftSidebar.tsx
9
9
  const LeftSidebar = (t0) => {
10
10
  const $ = c(13);
11
- if ($[0] !== "c0b8051f9d03df681e369c0b2954359f21e672e526188e45d0de7a395154e9cc") {
11
+ if ($[0] !== "37ec3b3a552e4e78e19e0a065e3326f676f367215b0ebda4b733ddd4a69ab079") {
12
12
  for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
13
- $[0] = "c0b8051f9d03df681e369c0b2954359f21e672e526188e45d0de7a395154e9cc";
13
+ $[0] = "37ec3b3a552e4e78e19e0a065e3326f676f367215b0ebda4b733ddd4a69ab079";
14
14
  }
15
15
  const { page, derivedLayout } = t0;
16
16
  const isAddBlockSidebarOpen = useSelector(previewStore, _temp);
@@ -37,28 +37,28 @@ const LeftSidebar = (t0) => {
37
37
  $[6] = t2;
38
38
  $[7] = t3;
39
39
  } else t3 = $[7];
40
- let t4;
41
- if ($[8] !== isAddBlockSidebarOpen) {
42
- t4 = isAddBlockSidebarOpen && /* @__PURE__ */ jsx("div", {
43
- className: "absolute inset-0 z-20 cursor-not-allowed",
44
- style: { background: "rgba(0, 0, 0, 0.5)" },
40
+ const t4 = `absolute inset-0 z-20 bg-black/50 transition-opacity duration-200 motion-reduce:transition-none ${isAddBlockSidebarOpen ? "cursor-not-allowed opacity-100" : "pointer-events-none opacity-0"}`;
41
+ let t5;
42
+ if ($[8] !== t4) {
43
+ t5 = /* @__PURE__ */ jsx("div", {
44
+ className: t4,
45
45
  "aria-hidden": "true"
46
46
  });
47
- $[8] = isAddBlockSidebarOpen;
48
- $[9] = t4;
49
- } else t4 = $[9];
50
- let t5;
51
- if ($[10] !== t3 || $[11] !== t4) {
52
- t5 = /* @__PURE__ */ jsxs("aside", {
47
+ $[8] = t4;
48
+ $[9] = t5;
49
+ } else t5 = $[9];
50
+ let t6;
51
+ if ($[10] !== t3 || $[11] !== t5) {
52
+ t6 = /* @__PURE__ */ jsxs("aside", {
53
53
  className: "relative flex shrink-0 flex-col border-r-2",
54
54
  style: t1,
55
- children: [t3, t4]
55
+ children: [t3, t5]
56
56
  });
57
57
  $[10] = t3;
58
- $[11] = t4;
59
- $[12] = t5;
60
- } else t5 = $[12];
61
- return t5;
58
+ $[11] = t5;
59
+ $[12] = t6;
60
+ } else t6 = $[12];
61
+ return t6;
62
62
  };
63
63
  function _temp(state) {
64
64
  return state.context.isAddBlockSidebarOpen;
@@ -11,20 +11,19 @@ import { useSelector } from "@xstate/store-react";
11
11
  * Listening for focus commands from parent (for sidebar-triggered focus)
12
12
  */
13
13
  const OverlayTracker = () => {
14
- const $ = c(9);
15
- if ($[0] !== "e0ea417a1efc597e2017b6de423987462b3c414f4a8241a5bd4f2de04d2dd29e") {
16
- for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
17
- $[0] = "e0ea417a1efc597e2017b6de423987462b3c414f4a8241a5bd4f2de04d2dd29e";
14
+ const $ = c(8);
15
+ if ($[0] !== "ebfece21400ea0599bf93e9f81b5244a330a6049bfb4c02fcc51a02e95e8e214") {
16
+ for (let $i = 0; $i < 8; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
17
+ $[0] = "ebfece21400ea0599bf93e9f81b5244a330a6049bfb4c02fcc51a02e95e8e214";
18
18
  }
19
19
  const { window: iframeWindow } = useFrame();
20
- const isPageEditorSidebarOpen = useSelector(previewStore, _temp);
21
- const isAddBlockSidebarOpen = useSelector(previewStore, _temp2);
20
+ const isAddBlockSidebarOpen = useSelector(previewStore, _temp);
22
21
  let t0;
23
22
  let t1;
24
23
  if ($[1] !== iframeWindow || $[2] !== isAddBlockSidebarOpen) {
25
24
  t0 = () => {
26
25
  if (!iframeWindow || !isAddBlockSidebarOpen) return;
27
- const handleClick = _temp3;
26
+ const handleClick = _temp2;
28
27
  iframeWindow.document.addEventListener("click", handleClick);
29
28
  return () => iframeWindow.document.removeEventListener("click", handleClick);
30
29
  };
@@ -40,14 +39,13 @@ const OverlayTracker = () => {
40
39
  React.useEffect(t0, t1);
41
40
  let t2;
42
41
  let t3;
43
- if ($[5] !== iframeWindow || $[6] !== isPageEditorSidebarOpen) {
42
+ if ($[5] !== iframeWindow) {
44
43
  t2 = () => {
45
44
  if (!iframeWindow) return;
46
45
  const handleMessage = (event) => {
47
46
  if (!isOverlayMessage(event.data)) return;
48
47
  const { type } = event.data;
49
48
  if (type === "CAMOX_FOCUS_FIELD") {
50
- if (isPageEditorSidebarOpen) return;
51
49
  const { fieldId } = event.data;
52
50
  const element = iframeWindow.document.querySelector(`[data-camox-field-id="${fieldId}"]`);
53
51
  if (element) element.focus();
@@ -56,25 +54,21 @@ const OverlayTracker = () => {
56
54
  iframeWindow.addEventListener("message", handleMessage);
57
55
  return () => iframeWindow.removeEventListener("message", handleMessage);
58
56
  };
59
- t3 = [iframeWindow, isPageEditorSidebarOpen];
57
+ t3 = [iframeWindow];
60
58
  $[5] = iframeWindow;
61
- $[6] = isPageEditorSidebarOpen;
62
- $[7] = t2;
63
- $[8] = t3;
59
+ $[6] = t2;
60
+ $[7] = t3;
64
61
  } else {
65
- t2 = $[7];
66
- t3 = $[8];
62
+ t2 = $[6];
63
+ t3 = $[7];
67
64
  }
68
65
  React.useEffect(t2, t3);
69
66
  return null;
70
67
  };
71
68
  function _temp(state) {
72
- return state.context.isPageEditorSidebarOpen;
69
+ return state.context.isAddBlockSidebarOpen;
73
70
  }
74
- function _temp2(state_0) {
75
- return state_0.context.isAddBlockSidebarOpen;
76
- }
77
- function _temp3() {
71
+ function _temp2() {
78
72
  previewStore.send({ type: "exitPeekedBlock" });
79
73
  }
80
74
 
@@ -10,9 +10,9 @@ import { useSelector } from "@xstate/store-react";
10
10
  //#region src/features/preview/components/Overlays.tsx
11
11
  function CuratedAddBlockListener() {
12
12
  const $ = c(4);
13
- if ($[0] !== "4124232297ed208895aa29251e0b658d39227311caca40cca61d1b2baedf5559") {
13
+ if ($[0] !== "6fe49b666f3f81b9063fd01dd7ea74a4df9732064d2b113c5ce2770c9992f6b4") {
14
14
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
15
- $[0] = "4124232297ed208895aa29251e0b658d39227311caca40cca61d1b2baedf5559";
15
+ $[0] = "6fe49b666f3f81b9063fd01dd7ea74a4df9732064d2b113c5ce2770c9992f6b4";
16
16
  }
17
17
  const { pageBlocks } = usePageBlocks(usePreviewedPage());
18
18
  let t0;
@@ -35,8 +35,7 @@ function CuratedAddBlockListener() {
35
35
  }
36
36
  previewStore.send({
37
37
  type: "openAddBlockSidebar",
38
- afterPosition,
39
- via: "overlay"
38
+ afterPosition
40
39
  });
41
40
  }
42
41
  };
@@ -55,20 +54,18 @@ function CuratedAddBlockListener() {
55
54
  return null;
56
55
  }
57
56
  const Overlays = (t0) => {
58
- const $ = c(13);
59
- if ($[0] !== "4124232297ed208895aa29251e0b658d39227311caca40cca61d1b2baedf5559") {
60
- for (let $i = 0; $i < 13; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
61
- $[0] = "4124232297ed208895aa29251e0b658d39227311caca40cca61d1b2baedf5559";
57
+ const $ = c(11);
58
+ if ($[0] !== "6fe49b666f3f81b9063fd01dd7ea74a4df9732064d2b113c5ce2770c9992f6b4") {
59
+ for (let $i = 0; $i < 11; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
60
+ $[0] = "6fe49b666f3f81b9063fd01dd7ea74a4df9732064d2b113c5ce2770c9992f6b4";
62
61
  }
63
62
  const { iframeElement, canAddBlocks: t1 } = t0;
64
63
  const canAddBlocks = t1 === void 0 ? false : t1;
65
- const isPageEditorSidebarOpen = useSelector(previewStore, _temp);
66
- const selection = useSelector(previewStore, _temp2);
67
- const peekedBlock = useSelector(previewStore, _temp3);
64
+ const selection = useSelector(previewStore, _temp);
65
+ const peekedBlock = useSelector(previewStore, _temp2);
68
66
  let t2;
69
- if ($[1] !== iframeElement?.contentWindow || $[2] !== isPageEditorSidebarOpen || $[3] !== peekedBlock || $[4] !== selection) {
67
+ if ($[1] !== iframeElement?.contentWindow || $[2] !== peekedBlock || $[3] !== selection) {
70
68
  t2 = () => {
71
- if (isPageEditorSidebarOpen) return;
72
69
  if (peekedBlock) return;
73
70
  if (!selection) return;
74
71
  if (selection.type !== "block-field" && selection.type !== "item-field") return;
@@ -82,42 +79,36 @@ const Overlays = (t0) => {
82
79
  iframeElement?.contentWindow?.postMessage(message, "*");
83
80
  };
84
81
  $[1] = iframeElement?.contentWindow;
85
- $[2] = isPageEditorSidebarOpen;
86
- $[3] = peekedBlock;
87
- $[4] = selection;
88
- $[5] = t2;
89
- } else t2 = $[5];
82
+ $[2] = peekedBlock;
83
+ $[3] = selection;
84
+ $[4] = t2;
85
+ } else t2 = $[4];
90
86
  let t3;
91
- if ($[6] !== iframeElement || $[7] !== isPageEditorSidebarOpen || $[8] !== peekedBlock || $[9] !== selection) {
87
+ if ($[5] !== iframeElement || $[6] !== peekedBlock || $[7] !== selection) {
92
88
  t3 = [
93
89
  selection,
94
- isPageEditorSidebarOpen,
95
90
  peekedBlock,
96
91
  iframeElement
97
92
  ];
98
- $[6] = iframeElement;
99
- $[7] = isPageEditorSidebarOpen;
100
- $[8] = peekedBlock;
101
- $[9] = selection;
102
- $[10] = t3;
103
- } else t3 = $[10];
93
+ $[5] = iframeElement;
94
+ $[6] = peekedBlock;
95
+ $[7] = selection;
96
+ $[8] = t3;
97
+ } else t3 = $[8];
104
98
  React.useEffect(t2, t3);
105
99
  let t4;
106
- if ($[11] !== canAddBlocks) {
100
+ if ($[9] !== canAddBlocks) {
107
101
  t4 = canAddBlocks ? /* @__PURE__ */ jsx(CuratedAddBlockListener, {}) : null;
108
- $[11] = canAddBlocks;
109
- $[12] = t4;
110
- } else t4 = $[12];
102
+ $[9] = canAddBlocks;
103
+ $[10] = t4;
104
+ } else t4 = $[10];
111
105
  return t4;
112
106
  };
113
107
  function _temp(state) {
114
- return state.context.isPageEditorSidebarOpen;
108
+ return state.context.selection;
115
109
  }
116
110
  function _temp2(state_0) {
117
- return state_0.context.selection;
118
- }
119
- function _temp3(state_1) {
120
- return state_1.context.peekedBlock;
111
+ return state_0.context.peekedBlock;
121
112
  }
122
113
 
123
114
  //#endregion
@@ -2,11 +2,13 @@ import { isFileMarker } from "../../../lib/normalized-data.js";
2
2
  import { blockMutations, blockQueries, fileQueries, repeatableItemMutations } from "../../../lib/queries.js";
3
3
  import { cn } from "../../../lib/utils.js";
4
4
  import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
5
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
5
+ import { areCommentsEnabled } from "../commentsEnabled.js";
6
6
  import { previewStore, selectionBlockId, selectionField, selectionItemId } from "../previewStore.js";
7
7
  import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
8
8
  import { fieldTypesDictionary } from "../../../core/lib/fieldTypes.js";
9
9
  import { SingleAssetFieldEditor } from "./AssetFieldEditor.js";
10
+ import { SidebarSection, SidebarSectionContent, SidebarSectionHeader } from "./SidebarSection.js";
11
+ import { AttachedComments } from "./AttachedComments.js";
10
12
  import { useRepeatableItemActions } from "./useRepeatableItemActions.js";
11
13
  import { ItemFieldsEditor, formatFieldName } from "./ItemFieldsEditor.js";
12
14
  import { LinkFieldEditor } from "./LinkFieldEditor.js";
@@ -16,10 +18,11 @@ import * as React from "react";
16
18
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
19
  import { useSelector } from "@xstate/store-react";
18
20
  import { Button } from "@camox/ui/button";
19
- import { CircleMinus, CirclePlus, CornerLeftUp } from "lucide-react";
21
+ import { CirclePlus, Trash2 } from "lucide-react";
20
22
  import { Spinner } from "@camox/ui/spinner";
21
23
  import { Label } from "@camox/ui/label";
22
24
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@camox/ui/select";
25
+ import { ButtonGroup } from "@camox/ui/button-group";
23
26
  import { Switch } from "@camox/ui/switch";
24
27
 
25
28
  //#region src/features/preview/components/PageEditorSidebar.tsx
@@ -89,7 +92,7 @@ const buildAncestorChain = (itemId, itemsMap) => {
89
92
  }
90
93
  return chain;
91
94
  };
92
- const PageEditorSidebar = () => {
95
+ const PageEditorSidebar = ({ pageId }) => {
93
96
  const camoxApp = useCamoxApp();
94
97
  const updateContent = useMutation(blockMutations.updateContent());
95
98
  const updateSettings = useMutation(blockMutations.updateSettings());
@@ -104,7 +107,7 @@ const PageEditorSidebar = () => {
104
107
  }, [iframeElement]);
105
108
  const blockId = selectionBlockId(selection);
106
109
  const currentItemId = selectionItemId(selection);
107
- const fieldInfo = selectionField(selection);
110
+ const selectedField = selectionField(selection);
108
111
  const { data: blockBundle } = useQuery({
109
112
  ...blockQueries.get(blockId),
110
113
  enabled: blockId != null
@@ -196,11 +199,15 @@ const PageEditorSidebar = () => {
196
199
  for (const [key, value_0] of Object.entries(rawCurrentData)) resolved_0[key] = resolveValue(value_0);
197
200
  return resolved_0;
198
201
  }, [rawCurrentData, filesMap]);
202
+ const fieldInfo = selectedField ? {
203
+ ...selectedField,
204
+ fieldType: currentSchema?.properties?.[selectedField.fieldName]?.fieldType ?? selectedField.fieldType
205
+ } : null;
199
206
  const isViewingLink = fieldInfo?.fieldType === "Link";
200
207
  const linkFieldName = isViewingLink ? fieldInfo.fieldName : null;
201
- const isViewingImage = fieldInfo?.fieldType === "Image";
208
+ const isViewingImage = fieldInfo?.fieldType === "Image" || fieldInfo?.fieldType === "ImageList";
202
209
  const imageFieldName = isViewingImage ? fieldInfo.fieldName : null;
203
- const isViewingFile = fieldInfo?.fieldType === "File";
210
+ const isViewingFile = fieldInfo?.fieldType === "File" || fieldInfo?.fieldType === "FileList";
204
211
  const fileFieldName = isViewingFile ? fieldInfo.fieldName : null;
205
212
  const isViewingAsset = isViewingImage || isViewingFile;
206
213
  const assetFieldName = imageFieldName ?? fileFieldName;
@@ -214,34 +221,10 @@ const PageEditorSidebar = () => {
214
221
  assetFieldName,
215
222
  currentSchema
216
223
  ]);
217
- const sessionDirtyRef = React.useRef(false);
218
- const trackedBlockIdRef = React.useRef(null);
219
- React.useEffect(() => {
220
- if (!block) {
221
- trackedBlockIdRef.current = null;
222
- return;
223
- }
224
- if (trackedBlockIdRef.current === block.id) return;
225
- trackedBlockIdRef.current = block.id;
226
- sessionDirtyRef.current = false;
227
- trackClientEvent("page_editor_sidebar_opened", { blockType: block.type });
228
- }, [block]);
229
- React.useEffect(() => {
230
- if (!block) return;
231
- return () => {
232
- if (!sessionDirtyRef.current) return;
233
- trackClientEvent("block_edited", {
234
- via: "page-editor-sidebar",
235
- blockType: block.type
236
- });
237
- sessionDirtyRef.current = false;
238
- };
239
- }, [block]);
240
224
  const fieldIdPrefix = React.useId();
241
225
  const handleBlockFieldChange = React.useCallback((fieldName, value_1) => {
242
226
  if (!block) return;
243
227
  if (!requireDraft()) return;
244
- sessionDirtyRef.current = true;
245
228
  updateContent.mutate({
246
229
  id: block.id,
247
230
  content: { [fieldName]: value_1 }
@@ -254,7 +237,6 @@ const PageEditorSidebar = () => {
254
237
  const handleItemFieldChange = React.useCallback((fieldName_0, value_2) => {
255
238
  if (currentItemId == null) return;
256
239
  if (!requireDraft()) return;
257
- sessionDirtyRef.current = true;
258
240
  updateRepeatableContent.mutate({
259
241
  id: currentItemId,
260
242
  content: { [fieldName_0]: value_2 }
@@ -287,16 +269,35 @@ const PageEditorSidebar = () => {
287
269
  blockId: block.id
288
270
  })
289
271
  },
290
- ...ancestorChain.map((ancestor) => ({
291
- key: `item-${ancestor.id}`,
272
+ ...ancestorChain.flatMap((ancestor) => [{
273
+ key: `repeater-${ancestor.id}`,
292
274
  label: getArraySchemaForItem(blockDef._internal.contentSchema, ancestor.id, itemsMap)?.title ?? formatFieldName(ancestor.fieldName),
275
+ isCurrent: false,
276
+ onClick: () => previewStore.send({
277
+ type: "setSelection",
278
+ selection: ancestor.parentItemId == null ? {
279
+ type: "block-field",
280
+ blockId: block.id,
281
+ fieldName: ancestor.fieldName,
282
+ fieldType: "Repeater"
283
+ } : {
284
+ type: "item-field",
285
+ blockId: block.id,
286
+ itemId: ancestor.parentItemId,
287
+ fieldName: ancestor.fieldName,
288
+ fieldType: "Repeater"
289
+ }
290
+ })
291
+ }, {
292
+ key: `item-${ancestor.id}`,
293
+ label: ancestor.summary || "Item",
293
294
  isCurrent: ancestor.id === currentItemId && !fieldHasOwnView && ancestor.id === ancestorChain[ancestorChain.length - 1]?.id,
294
295
  onClick: () => previewStore.send({
295
296
  type: "selectItem",
296
297
  blockId: block.id,
297
298
  itemId: ancestor.id
298
299
  })
299
- })),
300
+ }]),
300
301
  ...fieldHasOwnView && fieldInfo ? [{
301
302
  key: `field-${fieldInfo.fieldName}`,
302
303
  label: currentSchema?.properties?.[fieldInfo.fieldName]?.title ?? formatFieldName(fieldInfo.fieldName),
@@ -304,8 +305,8 @@ const PageEditorSidebar = () => {
304
305
  onClick: void 0
305
306
  }] : []
306
307
  ];
307
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
308
- className: "border-border flex flex-col gap-1.5 border-b px-2 py-4",
308
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(SidebarSection, {
309
+ divider: "bottom",
309
310
  children: /* @__PURE__ */ jsx("nav", {
310
311
  "aria-label": "Selection path",
311
312
  className: "text-muted-foreground text-sm",
@@ -359,17 +360,43 @@ const PageEditorSidebar = () => {
359
360
  })
360
361
  })
361
362
  }), /* @__PURE__ */ jsx("div", {
362
- className: "relative flex-1 overflow-auto",
363
+ className: "relative min-w-0 flex-1 overflow-x-hidden overflow-y-auto",
363
364
  children: /* @__PURE__ */ jsx("div", { children: isItemLoading ? /* @__PURE__ */ jsx("div", {
364
365
  className: "flex h-full items-center justify-center py-12",
365
366
  children: /* @__PURE__ */ jsx(Spinner, {})
366
367
  }) : /* @__PURE__ */ jsxs(Fragment, { children: [
367
- currentItemId == null && !fieldHasOwnView && settingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
368
- className: "border-border space-y-4 border-b px-2 py-4",
369
- children: [/* @__PURE__ */ jsx(Label, {
370
- className: "text-muted-foreground",
371
- children: "Settings"
372
- }), settingsFields.map((field) => {
368
+ !fieldHasOwnView && currentItemId != null && currentItem && /* @__PURE__ */ jsxs(SidebarSection, {
369
+ divider: "bottom",
370
+ "aria-label": "List actions",
371
+ children: [/* @__PURE__ */ jsx(SidebarSectionHeader, { children: "List actions" }), /* @__PURE__ */ jsx(SidebarSectionContent, { children: /* @__PURE__ */ jsxs(ButtonGroup, {
372
+ "aria-label": "List actions",
373
+ children: [/* @__PURE__ */ jsxs(Button, {
374
+ type: "button",
375
+ variant: "outline",
376
+ size: "sm",
377
+ disabled: !canAddSibling,
378
+ onClick: () => {
379
+ if (!canAddSibling || !requireDraft()) return;
380
+ addSibling({ afterPosition: currentItem.position });
381
+ },
382
+ children: [/* @__PURE__ */ jsx(CirclePlus, { className: "text-muted-foreground h-4 w-4" }), "Add sibling"]
383
+ }), /* @__PURE__ */ jsxs(Button, {
384
+ type: "button",
385
+ variant: "outline",
386
+ size: "sm",
387
+ disabled: !canRemoveCurrent,
388
+ onClick: () => {
389
+ if (!canRemoveCurrent || !requireDraft()) return;
390
+ removeCurrent(currentItemId, { onSuccess: () => previewStore.send({ type: "selectParent" }) });
391
+ },
392
+ children: [/* @__PURE__ */ jsx(Trash2, { className: "text-muted-foreground h-4 w-4" }), "Delete"]
393
+ })]
394
+ }) })]
395
+ }),
396
+ currentItemId == null && !fieldHasOwnView && settingsFields.length > 0 && /* @__PURE__ */ jsxs(SidebarSection, {
397
+ divider: "bottom",
398
+ "aria-label": "Block settings",
399
+ children: [/* @__PURE__ */ jsx(SidebarSectionHeader, { children: "Settings" }), /* @__PURE__ */ jsx(SidebarSectionContent, { children: settingsFields.map((field) => {
373
400
  const label = field.label ?? formatFieldName(field.name);
374
401
  const settingsValues = block.settings ?? {};
375
402
  if (field.fieldType === "Enum") {
@@ -383,7 +410,6 @@ const PageEditorSidebar = () => {
383
410
  value: value_3,
384
411
  onValueChange: (newValue) => {
385
412
  if (!requireDraft()) return;
386
- sessionDirtyRef.current = true;
387
413
  updateSettings.mutate({
388
414
  id: block.id,
389
415
  settings: { [field.name]: newValue }
@@ -411,7 +437,6 @@ const PageEditorSidebar = () => {
411
437
  checked,
412
438
  onCheckedChange: (newValue_0) => {
413
439
  if (!requireDraft()) return;
414
- sessionDirtyRef.current = true;
415
440
  updateSettings.mutate({
416
441
  id: block.id,
417
442
  settings: { [field.name]: newValue_0 }
@@ -421,14 +446,12 @@ const PageEditorSidebar = () => {
421
446
  }, field.name);
422
447
  }
423
448
  return null;
424
- })]
449
+ }) })]
425
450
  }),
426
- currentItemId != null && !fieldHasOwnView && itemSettingsFields.length > 0 && /* @__PURE__ */ jsxs("div", {
427
- className: "border-border space-y-4 border-b px-2 py-4",
428
- children: [/* @__PURE__ */ jsx(Label, {
429
- className: "text-muted-foreground",
430
- children: "Settings"
431
- }), itemSettingsFields.map((field_0) => {
451
+ currentItemId != null && !fieldHasOwnView && itemSettingsFields.length > 0 && /* @__PURE__ */ jsxs(SidebarSection, {
452
+ divider: "bottom",
453
+ "aria-label": "Item settings",
454
+ children: [/* @__PURE__ */ jsx(SidebarSectionHeader, { children: "Settings" }), /* @__PURE__ */ jsx(SidebarSectionContent, { children: itemSettingsFields.map((field_0) => {
432
455
  const label_0 = field_0.label ?? formatFieldName(field_0.name);
433
456
  const itemSettingsValues = currentItem?.settings ?? {};
434
457
  const itemSettingsSchemaProps = itemArraySchema?.itemSettingsSchema?.properties;
@@ -443,7 +466,6 @@ const PageEditorSidebar = () => {
443
466
  value: value_4,
444
467
  onValueChange: (newValue_1) => {
445
468
  if (!requireDraft()) return;
446
- sessionDirtyRef.current = true;
447
469
  updateRepeatableSettings.mutate({
448
470
  id: currentItemId,
449
471
  settings: { [field_0.name]: newValue_1 }
@@ -471,7 +493,6 @@ const PageEditorSidebar = () => {
471
493
  checked: checked_0,
472
494
  onCheckedChange: (newValue_2) => {
473
495
  if (!requireDraft()) return;
474
- sessionDirtyRef.current = true;
475
496
  updateRepeatableSettings.mutate({
476
497
  id: currentItemId,
477
498
  settings: { [field_0.name]: newValue_2 }
@@ -481,7 +502,7 @@ const PageEditorSidebar = () => {
481
502
  }, field_0.name);
482
503
  }
483
504
  return null;
484
- })]
505
+ }) })]
485
506
  }),
486
507
  isViewingAsset && assetFieldName && isMultipleAsset && /* @__PURE__ */ jsx(MultipleAssetFieldEditor, {
487
508
  fieldName: assetFieldName,
@@ -511,6 +532,7 @@ const PageEditorSidebar = () => {
511
532
  })
512
533
  }),
513
534
  !isViewingAsset && !isViewingLink && (currentItemId == null || currentItem) && /* @__PURE__ */ jsx(ItemFieldsEditor, {
535
+ selectedFieldName: fieldInfo?.fieldName,
514
536
  schema: currentSchema,
515
537
  data: currentData,
516
538
  blockId: block.id,
@@ -520,41 +542,18 @@ const PageEditorSidebar = () => {
520
542
  filesMap,
521
543
  itemsMap,
522
544
  fieldIdPrefix
523
- }, currentItemId ?? `block-${block.id}`),
524
- !isViewingAsset && !isViewingLink && currentItemId != null && currentItem && /* @__PURE__ */ jsxs("div", {
525
- className: "border-border flex items-center gap-1 border-t px-2 py-4",
526
- children: [
527
- canAddSibling && /* @__PURE__ */ jsxs(Button, {
528
- type: "button",
529
- variant: "ghost",
530
- size: "sm",
531
- className: "text-muted-foreground justify-start",
532
- onClick: () => {
533
- if (!requireDraft()) return;
534
- addSibling({ afterPosition: currentItem.position });
535
- },
536
- children: [/* @__PURE__ */ jsx(CirclePlus, { className: "h-4 w-4" }), "Add item"]
537
- }),
538
- canRemoveCurrent && /* @__PURE__ */ jsxs(Button, {
539
- type: "button",
540
- variant: "ghost",
541
- size: "sm",
542
- className: "text-muted-foreground justify-start",
543
- onClick: () => {
544
- if (!requireDraft()) return;
545
- removeCurrent(currentItemId, { onSuccess: () => previewStore.send({ type: "selectParent" }) });
546
- },
547
- children: [/* @__PURE__ */ jsx(CircleMinus, { className: "h-4 w-4" }), "Remove item"]
548
- }),
549
- /* @__PURE__ */ jsxs(Button, {
550
- type: "button",
551
- variant: "ghost",
552
- size: "sm",
553
- className: "text-muted-foreground justify-start",
554
- onClick: () => previewStore.send({ type: "selectParent" }),
555
- children: [/* @__PURE__ */ jsx(CornerLeftUp, { className: "h-4 w-4" }), "Select parent"]
556
- })
557
- ]
545
+ }, `${block.id}-${currentItemId ?? "block"}-${fieldInfo?.fieldName ?? "fields"}`),
546
+ areCommentsEnabled() && !fieldHasOwnView && (currentItemId == null || currentItem) && /* @__PURE__ */ jsx(AttachedComments, {
547
+ pageId,
548
+ blockId: block.id,
549
+ itemId: currentItemId ?? void 0
550
+ }),
551
+ areCommentsEnabled() && fieldHasOwnView && fieldInfo && /* @__PURE__ */ jsx(AttachedComments, {
552
+ pageId,
553
+ blockId: block.id,
554
+ itemId: currentItemId ?? void 0,
555
+ fieldName: fieldInfo.fieldName,
556
+ fieldType: fieldInfo.fieldType
558
557
  })
559
558
  ] }) })
560
559
  })] });