camox 0.41.0 → 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 (60) hide show
  1. package/dist/core/components/lexical/SidebarLexicalEditor.js +42 -39
  2. package/dist/core/createApp.d.ts +16 -2
  3. package/dist/core/createBlock.js +11 -25
  4. package/dist/core/editing/BlockEditingRuntime.js +4 -4
  5. package/dist/core/editing/CompleteBlockEditingRuntime.js +5 -5
  6. package/dist/core/editing/createEditableBlock.d.ts +8 -1
  7. package/dist/core/editing/createEditableBlock.js +684 -644
  8. package/dist/core/hooks/useIsEditable.js +4 -7
  9. package/dist/core/hooks/useOverlayState.js +11 -0
  10. package/dist/core/hooks/useRequireDraftSource.js +7 -11
  11. package/dist/core/lib/fieldTypes.js +5 -5
  12. package/dist/core/lib/lexicalState.js +17 -1
  13. package/dist/features/preview/CamoxPreview.js +123 -137
  14. package/dist/features/preview/DerivedPreview.js +6 -9
  15. package/dist/features/preview/commentsEnabled.js +8 -0
  16. package/dist/features/preview/components/AddBlockSidebar.js +79 -89
  17. package/dist/features/preview/components/AssetLightbox.js +4 -11
  18. package/dist/features/preview/components/AttachedComments.js +194 -0
  19. package/dist/features/preview/components/BlockActionsPopover.js +19 -70
  20. package/dist/features/preview/components/CommentHeader.js +122 -0
  21. package/dist/features/preview/components/CommentSidebar.js +29 -0
  22. package/dist/features/preview/components/CommentTargetQuote.js +166 -0
  23. package/dist/features/preview/components/CreatePageModal.js +2 -8
  24. package/dist/features/preview/components/DerivedLayoutSidebar.js +4 -7
  25. package/dist/features/preview/components/ItemFieldsEditor.js +275 -204
  26. package/dist/features/preview/components/LeftSidebar.js +18 -18
  27. package/dist/features/preview/components/LinkFieldEditor.js +3 -4
  28. package/dist/features/preview/components/MobilePreviewDrawer.js +3 -3
  29. package/dist/features/preview/components/OverlayTracker.js +14 -20
  30. package/dist/features/preview/components/Overlays.js +28 -40
  31. package/dist/features/preview/components/PageEditorSidebar.js +231 -241
  32. package/dist/features/preview/components/PageInfoSidebar.js +126 -157
  33. package/dist/features/preview/components/PagePicker.js +13 -8
  34. package/dist/features/preview/components/PageTree.js +255 -319
  35. package/dist/features/preview/components/PreviewComments.js +56 -0
  36. package/dist/features/preview/components/PreviewPanel.js +149 -107
  37. package/dist/features/preview/components/PreviewToolbar.js +292 -246
  38. package/dist/features/preview/components/PreviewToolbarSpacer.js +43 -0
  39. package/dist/features/preview/components/PublicationRow.js +11 -24
  40. package/dist/features/preview/components/RightSidebar.js +14 -11
  41. package/dist/features/preview/components/SidebarSection.js +121 -0
  42. package/dist/features/preview/previewCommentsStore.js +115 -0
  43. package/dist/features/preview/previewSelection.js +75 -0
  44. package/dist/features/preview/previewStore.js +32 -63
  45. package/dist/features/provider/AuthenticatedCamoxProvider.js +46 -34
  46. package/dist/features/provider/components/CommandPalette.js +142 -58
  47. package/dist/features/provider/useAdminShortcuts.js +20 -8
  48. package/dist/features/routes/pageRuntime.js +0 -6
  49. package/dist/features/runtime/RuntimeChrome.js +102 -87
  50. package/dist/features/studio/CamoxStudio.js +30 -50
  51. package/dist/features/studio/components/UserButton.js +4 -4
  52. package/dist/features/vite/runtimeDev.js +4 -1
  53. package/dist/features/vite/vite.d.ts +3 -2
  54. package/dist/features/vite/vite.js +9 -5
  55. package/dist/hooks/use-file-upload.js +0 -2
  56. package/dist/studio.css +1 -1
  57. package/package.json +5 -7
  58. package/dist/features/preview/components/DraftSwitchDialog.js +0 -66
  59. package/dist/lib/telemetry-client.js +0 -66
  60. package/dist/lib/telemetry.js +0 -26
@@ -3,7 +3,6 @@ import { useProjectSlug } from "../../../lib/auth.js";
3
3
  import { usePageBlocks } from "../../../lib/normalized-data.js";
4
4
  import { blockMutations, blockQueries, projectQueries } from "../../../lib/queries.js";
5
5
  import { useCamoxApp } from "../../provider/components/CamoxAppContext.js";
6
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
7
6
  import { previewStore } from "../previewStore.js";
8
7
  import { useRequireDraftSource } from "../../../core/hooks/useRequireDraftSource.js";
9
8
  import { BlockThumbnail } from "./BlockThumbnail.js";
@@ -23,10 +22,10 @@ import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, Command
23
22
 
24
23
  //#region src/features/preview/components/AddBlockSidebar.tsx
25
24
  const AddBlockSidebar = () => {
26
- const $ = c(58);
27
- if ($[0] !== "0a9bbf9c6eddd22fc242436657c914b17db692a3ab0e958a7f9451a343536838") {
28
- for (let $i = 0; $i < 58; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
29
- $[0] = "0a9bbf9c6eddd22fc242436657c914b17db692a3ab0e958a7f9451a343536838";
25
+ const $ = c(57);
26
+ if ($[0] !== "4c8d55ba83f686c7bfc04ce464d348e236b6ed16fb43d0305b13b93cf8de061f") {
27
+ for (let $i = 0; $i < 57; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
28
+ $[0] = "4c8d55ba83f686c7bfc04ce464d348e236b6ed16fb43d0305b13b93cf8de061f";
30
29
  }
31
30
  const [highlightedValue, setHighlightedValue] = React.useState("");
32
31
  const queryClient = useQueryClient();
@@ -167,9 +166,8 @@ const AddBlockSidebar = () => {
167
166
  } else t8 = $[16];
168
167
  const pageCounts = t8;
169
168
  const peekedBlockPosition = useSelector(previewStore, _temp3);
170
- const addBlockSource = useSelector(previewStore, _temp4);
171
169
  let t9;
172
- if ($[17] !== addBlockSource || $[18] !== createBlock || $[19] !== page || $[20] !== pageBlocks_0 || $[21] !== peekedBlockPosition || $[22] !== requireDraft) {
170
+ if ($[17] !== createBlock || $[18] !== page || $[19] !== pageBlocks_0 || $[20] !== peekedBlockPosition || $[21] !== requireDraft) {
173
171
  t9 = async (block_0) => {
174
172
  if (!page) return;
175
173
  if (!requireDraft()) return;
@@ -183,27 +181,22 @@ const AddBlockSidebar = () => {
183
181
  afterPosition: afterPosition_0,
184
182
  repeatableItems: bundle.repeatableItems
185
183
  });
186
- trackClientEvent("block_added", {
187
- blockType: block_0._internal.id,
188
- via: addBlockSource ?? "unknown"
189
- });
190
184
  previewStore.send({
191
185
  type: "focusCreatedBlock",
192
186
  blockId
193
187
  });
194
188
  previewStore.send({ type: "exitPeekedBlock" });
195
189
  };
196
- $[17] = addBlockSource;
197
- $[18] = createBlock;
198
- $[19] = page;
199
- $[20] = pageBlocks_0;
200
- $[21] = peekedBlockPosition;
201
- $[22] = requireDraft;
202
- $[23] = t9;
203
- } else t9 = $[23];
190
+ $[17] = createBlock;
191
+ $[18] = page;
192
+ $[19] = pageBlocks_0;
193
+ $[20] = peekedBlockPosition;
194
+ $[21] = requireDraft;
195
+ $[22] = t9;
196
+ } else t9 = $[22];
204
197
  const handleAddBlock = t9;
205
198
  let t10;
206
- if ($[24] !== pageBlocks_0 || $[25] !== peekedBlockPosition) {
199
+ if ($[23] !== pageBlocks_0 || $[24] !== peekedBlockPosition) {
207
200
  t10 = (block_1) => {
208
201
  const afterPosition_1 = peekedBlockPosition === "" ? "" : peekedBlockPosition ?? pageBlocks_0[pageBlocks_0.length - 1]?.position;
209
202
  previewStore.send({
@@ -212,10 +205,10 @@ const AddBlockSidebar = () => {
212
205
  afterPosition: afterPosition_1
213
206
  });
214
207
  };
215
- $[24] = pageBlocks_0;
216
- $[25] = peekedBlockPosition;
217
- $[26] = t10;
218
- } else t10 = $[26];
208
+ $[23] = pageBlocks_0;
209
+ $[24] = peekedBlockPosition;
210
+ $[25] = t10;
211
+ } else t10 = $[25];
219
212
  const handlePreviewBlock = t10;
220
213
  const handleValueChange = (value) => {
221
214
  setHighlightedValue(value);
@@ -224,62 +217,62 @@ const AddBlockSidebar = () => {
224
217
  else previewStore.send({ type: "clearPeekedBlock" });
225
218
  };
226
219
  let t11;
227
- if ($[27] !== pageCounts || $[28] !== totalCounts) {
220
+ if ($[26] !== pageCounts || $[27] !== totalCounts) {
228
221
  t11 = (blockId_0) => {
229
222
  const total = totalCounts[blockId_0] ?? 0;
230
223
  if (total === 0) return "Never used";
231
224
  const page_0 = pageCounts[blockId_0] ?? "none";
232
225
  return `${total} use${total > 1 ? "s" : ""} (${page_0} here)`;
233
226
  };
234
- $[27] = pageCounts;
235
- $[28] = totalCounts;
236
- $[29] = t11;
237
- } else t11 = $[29];
227
+ $[26] = pageCounts;
228
+ $[27] = totalCounts;
229
+ $[28] = t11;
230
+ } else t11 = $[28];
238
231
  const displayCount = t11;
239
232
  let t12;
240
- if ($[30] === Symbol.for("react.memo_cache_sentinel")) {
233
+ if ($[29] === Symbol.for("react.memo_cache_sentinel")) {
241
234
  t12 = /* @__PURE__ */ jsx("div", {
242
- className: "px-2 pt-4",
235
+ className: "px-2 pt-2",
243
236
  children: /* @__PURE__ */ jsxs(Button, {
244
237
  variant: "ghost",
245
238
  className: "w-full justify-start",
246
- onClick: _temp5,
239
+ onClick: _temp4,
247
240
  children: [/* @__PURE__ */ jsx(ArrowLeft, { className: "text-muted-foreground" }), "Add new block"]
248
241
  })
249
242
  });
250
- $[30] = t12;
251
- } else t12 = $[30];
243
+ $[29] = t12;
244
+ } else t12 = $[29];
252
245
  const T0 = PanelContent;
253
- const t13 = "flex grow basis-0 flex-col overflow-auto px-2 py-2";
246
+ const t13 = "flex min-h-0 grow basis-0 flex-col overflow-hidden px-2 pt-2";
254
247
  const T1 = Command;
255
- const t14 = "overflow-visible rounded-none! bg-transparent! p-0!";
256
- const t15 = _temp6;
248
+ const t14 = "h-0 min-h-0 flex-1 rounded-none! bg-transparent! p-0!";
249
+ const t15 = _temp5;
257
250
  let t16;
258
- if ($[31] === Symbol.for("react.memo_cache_sentinel")) {
251
+ if ($[30] === Symbol.for("react.memo_cache_sentinel")) {
259
252
  t16 = /* @__PURE__ */ jsx(CommandInput, {
260
253
  placeholder: "Search blocks...",
261
254
  className: "px-0 pt-0",
262
255
  autoFocus: true
263
256
  });
264
- $[31] = t16;
265
- } else t16 = $[31];
257
+ $[30] = t16;
258
+ } else t16 = $[30];
266
259
  const T2 = CommandList;
267
- const t17 = "mt-2 max-h-full";
260
+ const t17 = "mt-2 max-h-none min-h-0 flex-1 pb-2";
268
261
  let t18;
269
- if ($[32] === Symbol.for("react.memo_cache_sentinel")) {
262
+ if ($[31] === Symbol.for("react.memo_cache_sentinel")) {
270
263
  t18 = /* @__PURE__ */ jsx(CommandEmpty, { children: "No blocks found." });
271
- $[32] = t18;
272
- } else t18 = $[32];
264
+ $[31] = t18;
265
+ } else t18 = $[31];
273
266
  const T3 = CommandGroup;
274
267
  const t19 = "p-0";
275
268
  let t20;
276
- if ($[33] !== totalCounts) {
269
+ if ($[32] !== totalCounts) {
277
270
  t20 = (a, b_3) => (totalCounts[b_3._internal.id] ?? 0) - (totalCounts[a._internal.id] ?? 0);
278
- $[33] = totalCounts;
279
- $[34] = t20;
280
- } else t20 = $[34];
271
+ $[32] = totalCounts;
272
+ $[33] = t20;
273
+ } else t20 = $[33];
281
274
  let t21;
282
- if ($[35] !== displayCount || $[36] !== handleAddBlock) {
275
+ if ($[34] !== displayCount || $[35] !== handleAddBlock) {
283
276
  t21 = (block_3) => /* @__PURE__ */ jsxs(CommandItem, {
284
277
  value: block_3._internal.title,
285
278
  keywords: [block_3._internal.description ?? ""],
@@ -287,7 +280,7 @@ const AddBlockSidebar = () => {
287
280
  onSelect: () => {
288
281
  handleAddBlock(block_3);
289
282
  },
290
- className: "group bg-card data-[selected=true]:border-primary data-[selected=true]:after:border-primary mb-3 flex flex-col items-stretch gap-0 overflow-hidden rounded-lg border p-0 after:pointer-events-none after:absolute after:inset-0 after:z-10 after:rounded-[inherit] last:mb-0 data-[selected=true]:after:border",
283
+ className: "group bg-card data-[selected=true]:border-primary mb-3 flex flex-col items-stretch gap-0 overflow-hidden rounded-lg border-2 p-0 last:mb-0",
291
284
  children: [/* @__PURE__ */ jsx(BlockThumbnail, { block: block_3 }), /* @__PURE__ */ jsxs("div", {
292
285
  className: "border-border flex flex-col gap-1 border-t px-3 py-2",
293
286
  children: [/* @__PURE__ */ jsxs("div", {
@@ -306,34 +299,34 @@ const AddBlockSidebar = () => {
306
299
  })]
307
300
  })]
308
301
  }, block_3._internal.id);
309
- $[35] = displayCount;
310
- $[36] = handleAddBlock;
311
- $[37] = t21;
312
- } else t21 = $[37];
302
+ $[34] = displayCount;
303
+ $[35] = handleAddBlock;
304
+ $[36] = t21;
305
+ } else t21 = $[36];
313
306
  const t22 = availableBlocks.sort(t20).map(t21);
314
307
  let t23;
315
- if ($[38] !== T3 || $[39] !== t22) {
308
+ if ($[37] !== T3 || $[38] !== t22) {
316
309
  t23 = /* @__PURE__ */ jsx(T3, {
317
310
  className: t19,
318
311
  children: t22
319
312
  });
320
- $[38] = T3;
321
- $[39] = t22;
322
- $[40] = t23;
323
- } else t23 = $[40];
313
+ $[37] = T3;
314
+ $[38] = t22;
315
+ $[39] = t23;
316
+ } else t23 = $[39];
324
317
  let t24;
325
- if ($[41] !== T2 || $[42] !== t18 || $[43] !== t23) {
318
+ if ($[40] !== T2 || $[41] !== t18 || $[42] !== t23) {
326
319
  t24 = /* @__PURE__ */ jsxs(T2, {
327
320
  className: t17,
328
321
  children: [t18, t23]
329
322
  });
330
- $[41] = T2;
331
- $[42] = t18;
332
- $[43] = t23;
333
- $[44] = t24;
334
- } else t24 = $[44];
323
+ $[40] = T2;
324
+ $[41] = t18;
325
+ $[42] = t23;
326
+ $[43] = t24;
327
+ } else t24 = $[43];
335
328
  let t25;
336
- if ($[45] !== T1 || $[46] !== handleValueChange || $[47] !== highlightedValue || $[48] !== t15 || $[49] !== t16 || $[50] !== t24) {
329
+ if ($[44] !== T1 || $[45] !== handleValueChange || $[46] !== highlightedValue || $[47] !== t15 || $[48] !== t16 || $[49] !== t24) {
337
330
  t25 = /* @__PURE__ */ jsxs(T1, {
338
331
  value: highlightedValue,
339
332
  onValueChange: handleValueChange,
@@ -341,31 +334,31 @@ const AddBlockSidebar = () => {
341
334
  onKeyDown: t15,
342
335
  children: [t16, t24]
343
336
  });
344
- $[45] = T1;
345
- $[46] = handleValueChange;
346
- $[47] = highlightedValue;
347
- $[48] = t15;
348
- $[49] = t16;
349
- $[50] = t24;
350
- $[51] = t25;
351
- } else t25 = $[51];
337
+ $[44] = T1;
338
+ $[45] = handleValueChange;
339
+ $[46] = highlightedValue;
340
+ $[47] = t15;
341
+ $[48] = t16;
342
+ $[49] = t24;
343
+ $[50] = t25;
344
+ } else t25 = $[50];
352
345
  let t26;
353
- if ($[52] !== T0 || $[53] !== t25) {
346
+ if ($[51] !== T0 || $[52] !== t25) {
354
347
  t26 = /* @__PURE__ */ jsx(T0, {
355
348
  className: t13,
356
349
  children: t25
357
350
  });
358
- $[52] = T0;
359
- $[53] = t25;
360
- $[54] = t26;
361
- } else t26 = $[54];
351
+ $[51] = T0;
352
+ $[52] = t25;
353
+ $[53] = t26;
354
+ } else t26 = $[53];
362
355
  let t27;
363
- if ($[55] !== t12 || $[56] !== t26) {
356
+ if ($[54] !== t12 || $[55] !== t26) {
364
357
  t27 = /* @__PURE__ */ jsxs(Fragment, { children: [t12, t26] });
365
- $[55] = t12;
366
- $[56] = t26;
367
- $[57] = t27;
368
- } else t27 = $[57];
358
+ $[54] = t12;
359
+ $[55] = t26;
360
+ $[56] = t27;
361
+ } else t27 = $[56];
369
362
  return t27;
370
363
  };
371
364
  function _temp(b) {
@@ -377,13 +370,10 @@ function _temp2(b_1) {
377
370
  function _temp3(state) {
378
371
  return state.context.peekedBlockPosition;
379
372
  }
380
- function _temp4(state_0) {
381
- return state_0.context.addBlockSource;
382
- }
383
- function _temp5() {
373
+ function _temp4() {
384
374
  return previewStore.send({ type: "closeAddBlockSidebar" });
385
375
  }
386
- function _temp6(e) {
376
+ function _temp5(e) {
387
377
  if (e.key === "Escape") previewStore.send({ type: "closeAddBlockSidebar" });
388
378
  }
389
379
 
@@ -2,7 +2,6 @@ import { getAuthCookieHeader, getAuthRequestCredentials } from "../../../lib/aut
2
2
  import { getApiUrl, getEnvironmentName } from "../../../lib/api-client.js";
3
3
  import { isRasterImage, transformImageUrl } from "../../../core/lib/imageTransform.js";
4
4
  import { fileMutations, fileQueries } from "../../../lib/queries.js";
5
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
6
5
  import { UploadDropZone } from "../../content/components/UploadDropZone.js";
7
6
  import { DebouncedFieldEditor } from "./DebouncedFieldEditor.js";
8
7
  import { Metadata, MetadataRow, formatRelativeTime } from "./Metadata.js";
@@ -22,9 +21,9 @@ import { Switch } from "@camox/ui/switch";
22
21
  //#region src/features/preview/components/AssetLightbox.tsx
23
22
  function DeliveredSize(t0) {
24
23
  const $ = c(16);
25
- if ($[0] !== "1dc3a839581aee4dce763fdadc5f599293f7d6288e481a0914cf562382a66ab9") {
24
+ if ($[0] !== "974fbfa56da78c6c8e188316efcb7f5517bffbf74578eecb8288c82aad4e9b63") {
26
25
  for (let $i = 0; $i < 16; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
27
- $[0] = "1dc3a839581aee4dce763fdadc5f599293f7d6288e481a0914cf562382a66ab9";
26
+ $[0] = "974fbfa56da78c6c8e188316efcb7f5517bffbf74578eecb8288c82aad4e9b63";
28
27
  }
29
28
  const { bytes, raw } = t0;
30
29
  if (bytes == null) {
@@ -93,9 +92,9 @@ function DeliveredSize(t0) {
93
92
  }
94
93
  function DeliveredLabel(t0) {
95
94
  const $ = c(4);
96
- if ($[0] !== "1dc3a839581aee4dce763fdadc5f599293f7d6288e481a0914cf562382a66ab9") {
95
+ if ($[0] !== "974fbfa56da78c6c8e188316efcb7f5517bffbf74578eecb8288c82aad4e9b63") {
97
96
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
98
- $[0] = "1dc3a839581aee4dce763fdadc5f599293f7d6288e481a0914cf562382a66ab9";
97
+ $[0] = "974fbfa56da78c6c8e188316efcb7f5517bffbf74578eecb8288c82aad4e9b63";
99
98
  }
100
99
  const { children } = t0;
101
100
  let t1;
@@ -460,12 +459,6 @@ const AssetLightbox = ({ open, onOpenChange, fileId }) => {
460
459
  id: fileId,
461
460
  enabled: checked
462
461
  });
463
- trackClientEvent("ai_metadata_toggled", {
464
- target: "file",
465
- enabled: checked,
466
- fileId,
467
- mimeType: file.mimeType
468
- });
469
462
  }
470
463
  }), /* @__PURE__ */ jsx(Label, {
471
464
  htmlFor: "ai-metadata",
@@ -0,0 +1,194 @@
1
+ import { useAuthContext } from "../../../lib/auth.js";
2
+ import { previewStore } from "../previewStore.js";
3
+ import { previewCommentsStore, revealCommentTarget } from "../previewCommentsStore.js";
4
+ import { CommentHeader } from "./CommentHeader.js";
5
+ import { CommentTargetQuote } from "./CommentTargetQuote.js";
6
+ import { SidebarSection, SidebarSectionContent, SidebarSectionHeader } from "./SidebarSection.js";
7
+ import * as React from "react";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
+ import { useSelector } from "@xstate/store-react";
10
+ import { Button } from "@camox/ui/button";
11
+ import { ArrowUp, X } from "lucide-react";
12
+ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@camox/ui/input-group";
13
+
14
+ //#region src/features/preview/components/AttachedComments.tsx
15
+ function resizeComposer(element) {
16
+ element.style.height = "auto";
17
+ element.style.height = `${element.scrollHeight}px`;
18
+ }
19
+ /** Shared comment list and composer for editors and the Feedback sidebar. */
20
+ function AttachedComments({ pageId, blockId, itemId, fieldName, fieldType, allPageComments = false }) {
21
+ const { authClient } = useAuthContext();
22
+ const { data: session } = authClient.useSession();
23
+ const { comments, draft, activeId, focusTarget } = useSelector(previewCommentsStore, (state) => state.context);
24
+ const matches = (entry) => entry.pageId === pageId && (allPageComments || entry.target.blockId === blockId && entry.target.itemId === itemId && entry.target.fieldName === fieldName);
25
+ const attached = comments.filter(matches);
26
+ const currentDraft = draft && matches(draft) ? draft : null;
27
+ const selected = attached.find((comment) => comment.id === activeId);
28
+ const textarea = React.useRef(null);
29
+ const activeComment = React.useRef(null);
30
+ const draftTarget = currentDraft?.target;
31
+ const message = currentDraft?.message ?? "";
32
+ React.useLayoutEffect(() => {
33
+ if (textarea.current) resizeComposer(textarea.current);
34
+ }, [message, pageId]);
35
+ React.useEffect(() => {
36
+ const element = textarea.current;
37
+ if (!element) return;
38
+ let width = element.clientWidth;
39
+ const observer = new ResizeObserver(() => {
40
+ if (element.clientWidth === width) return;
41
+ width = element.clientWidth;
42
+ resizeComposer(element);
43
+ });
44
+ observer.observe(element);
45
+ return () => observer.disconnect();
46
+ }, [pageId]);
47
+ const submit = () => {
48
+ if (!message.trim()) return;
49
+ previewCommentsStore.send({
50
+ type: "postComment",
51
+ id: crypto.randomUUID(),
52
+ author: {
53
+ name: session?.user.name || "You",
54
+ image: session?.user.image ?? null
55
+ },
56
+ createdAt: Date.now()
57
+ });
58
+ textarea.current?.focus({ preventScroll: true });
59
+ };
60
+ React.useEffect(() => {
61
+ if (!draftTarget || focusTarget !== draftTarget || !textarea.current) return;
62
+ textarea.current?.scrollIntoView({ block: "nearest" });
63
+ textarea.current?.focus({ preventScroll: true });
64
+ previewCommentsStore.send({ type: "composerFocused" });
65
+ }, [draftTarget, focusTarget]);
66
+ React.useEffect(() => {
67
+ if (!selected) return;
68
+ activeComment.current?.scrollIntoView({ block: "nearest" });
69
+ }, [selected]);
70
+ if (pageId == null) return null;
71
+ return /* @__PURE__ */ jsxs(SidebarSection, {
72
+ "aria-label": allPageComments ? "Feedback" : blockId == null ? "Page comments" : fieldName ? `Comments on ${fieldName}` : itemId == null ? "Block comments" : "Item comments",
73
+ divider: allPageComments ? "none" : "top",
74
+ children: [allPageComments ? /* @__PURE__ */ jsxs("div", {
75
+ className: "flex items-center justify-between gap-2",
76
+ children: [/* @__PURE__ */ jsx("h2", {
77
+ className: "text-base font-semibold",
78
+ children: "Feedback"
79
+ }), /* @__PURE__ */ jsx(Button, {
80
+ type: "button",
81
+ variant: "ghost",
82
+ size: "icon-sm",
83
+ "aria-label": "End comment mode",
84
+ onClick: () => previewStore.send({
85
+ type: "setCommentMode",
86
+ enabled: false
87
+ }),
88
+ children: /* @__PURE__ */ jsx(X, { className: "text-muted-foreground" })
89
+ })]
90
+ }) : /* @__PURE__ */ jsx(SidebarSectionHeader, { children: "Feedback" }), /* @__PURE__ */ jsxs(SidebarSectionContent, { children: [
91
+ allPageComments && attached.length === 0 && /* @__PURE__ */ jsx("p", {
92
+ className: "text-muted-foreground text-sm",
93
+ children: "No feedback yet. Select something on the page to comment on it."
94
+ }),
95
+ attached.map((comment_0) => /* @__PURE__ */ jsxs("div", {
96
+ ref: comment_0.id === activeId ? activeComment : void 0,
97
+ ...allPageComments && {
98
+ role: "button",
99
+ tabIndex: 0,
100
+ className: "hover:bg-card focus-visible:ring-ring rounded-md p-1 outline-none focus-visible:ring-2",
101
+ onClick: () => {
102
+ previewCommentsStore.send({
103
+ type: "selectComment",
104
+ id: comment_0.id
105
+ });
106
+ revealCommentTarget(comment_0.target);
107
+ },
108
+ onKeyDown: (event) => {
109
+ if (event.key !== "Enter" && event.key !== " ") return;
110
+ event.preventDefault();
111
+ event.currentTarget.click();
112
+ }
113
+ },
114
+ children: [/* @__PURE__ */ jsx(CommentHeader, {
115
+ author: comment_0.author,
116
+ createdAt: comment_0.createdAt
117
+ }), /* @__PURE__ */ jsxs("div", {
118
+ className: "pl-8",
119
+ children: [allPageComments && /* @__PURE__ */ jsx(CommentTargetQuote, {
120
+ pageId,
121
+ target: comment_0.target
122
+ }), /* @__PURE__ */ jsx("p", {
123
+ className: "text-sm wrap-break-word whitespace-pre-wrap",
124
+ children: comment_0.message
125
+ })]
126
+ })]
127
+ }, comment_0.id)),
128
+ allPageComments && /* @__PURE__ */ jsx(Button, {
129
+ type: "button",
130
+ variant: "secondary",
131
+ className: "w-full",
132
+ disabled: attached.length === 0,
133
+ children: "Send feedback to agent..."
134
+ }),
135
+ !allPageComments && /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupTextarea, {
136
+ ref: textarea,
137
+ "aria-label": "Comment text",
138
+ placeholder: "Add a comment",
139
+ className: "block field-sizing-fixed min-h-0 flex-none overflow-hidden leading-6",
140
+ rows: 1,
141
+ value: message,
142
+ onKeyDown: (event_0) => {
143
+ if (event_0.key !== "Enter" || event_0.shiftKey || event_0.nativeEvent.isComposing) return;
144
+ event_0.preventDefault();
145
+ event_0.stopPropagation();
146
+ submit();
147
+ },
148
+ onChange: (event_1) => {
149
+ if (!currentDraft) {
150
+ const fieldId = [
151
+ blockId,
152
+ itemId,
153
+ fieldName
154
+ ].filter((part) => part != null).join("__");
155
+ previewCommentsStore.send({
156
+ type: "startComment",
157
+ pageId,
158
+ target: {
159
+ blockId,
160
+ itemId,
161
+ fieldName,
162
+ fieldType,
163
+ selector: blockId == null ? "body" : fieldName != null ? `[data-camox-field-id="${CSS.escape(fieldId)}"]` : itemId != null ? `[data-camox-repeater-item-id="${itemId}"]` : `[data-camox-block-id="${blockId}"]`,
164
+ label: blockId == null ? `Page · ${pageId}` : fieldName != null ? `Field · ${fieldName}` : itemId != null ? `Item · ${itemId}` : `Block · ${blockId}`,
165
+ x: .5,
166
+ y: .5
167
+ }
168
+ });
169
+ }
170
+ previewCommentsStore.send({
171
+ type: "setMessage",
172
+ message: event_1.target.value
173
+ });
174
+ }
175
+ }), /* @__PURE__ */ jsx(InputGroupAddon, {
176
+ align: "block-end",
177
+ className: "justify-end",
178
+ children: /* @__PURE__ */ jsx(InputGroupButton, {
179
+ type: "button",
180
+ size: "icon-sm",
181
+ variant: "default",
182
+ className: "rounded-full",
183
+ "aria-label": "Post comment",
184
+ disabled: !message.trim(),
185
+ onClick: submit,
186
+ children: /* @__PURE__ */ jsx(ArrowUp, { size: 16 })
187
+ })
188
+ })] })
189
+ ] })]
190
+ });
191
+ }
192
+
193
+ //#endregion
194
+ export { AttachedComments };