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
@@ -1,7 +1,6 @@
1
1
  import { actionsStore } from "../../provider/actionsStore.js";
2
2
  import { getApiClient } from "../../../lib/api-client.js";
3
- import { trackClientEvent } from "../../../lib/telemetry-client.js";
4
- import { previewStore } from "../previewStore.js";
3
+ import { previewStore, selectPreviewSource } from "../previewStore.js";
5
4
  import { buildPublicationPlan, getPublicationCapabilities, getPublicationRequest } from "../publication.js";
6
5
  import { PublishDialog } from "./PublishDialog.js";
7
6
  import { c } from "react/compiler-runtime";
@@ -20,9 +19,9 @@ import { ButtonGroup } from "@camox/ui/button-group";
20
19
  //#region src/features/preview/components/PublicationRow.tsx
21
20
  function PublicationRow(t0) {
22
21
  const $ = c(4);
23
- if ($[0] !== "bef0702fd89aac7465952e09d43979741129da566cd392625f8739ebc2b0b2f9") {
22
+ if ($[0] !== "523b5f62d51c452de4fc84846c3eb3bd79ec8b996291e394294cbc9a83e20848") {
24
23
  for (let $i = 0; $i < 4; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
25
- $[0] = "bef0702fd89aac7465952e09d43979741129da566cd392625f8739ebc2b0b2f9";
24
+ $[0] = "523b5f62d51c452de4fc84846c3eb3bd79ec8b996291e394294cbc9a83e20848";
26
25
  }
27
26
  const { target } = t0;
28
27
  const identity = target ? `${target.kind}:${target.kind === "page" ? target.page.id : target.layout.id}` : "loading";
@@ -37,12 +36,12 @@ function PublicationRow(t0) {
37
36
  }
38
37
  function PublicationControls(t0) {
39
38
  const $ = c(78);
40
- if ($[0] !== "bef0702fd89aac7465952e09d43979741129da566cd392625f8739ebc2b0b2f9") {
39
+ if ($[0] !== "523b5f62d51c452de4fc84846c3eb3bd79ec8b996291e394294cbc9a83e20848") {
41
40
  for (let $i = 0; $i < 78; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
42
- $[0] = "bef0702fd89aac7465952e09d43979741129da566cd392625f8739ebc2b0b2f9";
41
+ $[0] = "523b5f62d51c452de4fc84846c3eb3bd79ec8b996291e394294cbc9a83e20848";
43
42
  }
44
43
  const { target } = t0;
45
- const source = useSelector(previewStore, _temp);
44
+ const source = useSelector(previewStore, selectPreviewSource);
46
45
  const queryClient = useQueryClient();
47
46
  const [action, setAction] = React.useState(null);
48
47
  let t1;
@@ -74,10 +73,6 @@ function PublicationControls(t0) {
74
73
  return;
75
74
  }
76
75
  await api.pages.publish(request.input);
77
- trackClientEvent("page_published", {
78
- pageId: request.input.id,
79
- ...request.input.alsoPublishLayout ? { alsoPublishedLayout: true } : {}
80
- });
81
76
  return;
82
77
  }
83
78
  if (target.kind === "layout") {
@@ -86,11 +81,9 @@ function PublicationControls(t0) {
86
81
  }
87
82
  if (operation === "discard") {
88
83
  await api.pages.discardChanges({ id: target.page.id });
89
- trackClientEvent("page_changes_discarded", { pageId: target.page.id });
90
84
  return;
91
85
  }
92
86
  await api.pages.unpublish({ id: target.page.id });
93
- trackClientEvent("page_unpublished", { pageId: target.page.id });
94
87
  };
95
88
  $[6] = capabilities;
96
89
  $[7] = target;
@@ -100,10 +93,7 @@ function PublicationControls(t0) {
100
93
  if ($[9] !== queryClient) {
101
94
  t4 = async (_, t5) => {
102
95
  const { operation: operation_0 } = t5;
103
- if (operation_0 !== "publish") previewStore.send({
104
- type: "setPreviewSource",
105
- source: "draft"
106
- });
96
+ if (operation_0 !== "publish") previewStore.send({ type: "viewDraftPage" });
107
97
  setAction(null);
108
98
  toast.success(operation_0 === "publish" ? "Published selected changes" : operation_0 === "unpublish" ? "Unpublished successfully" : "Discarded draft changes");
109
99
  await Promise.all([
@@ -130,7 +120,7 @@ function PublicationControls(t0) {
130
120
  t5 = {
131
121
  mutationFn: t3,
132
122
  onSuccess: t4,
133
- onError: _temp2
123
+ onError: _temp
134
124
  };
135
125
  $[11] = t3;
136
126
  $[12] = t4;
@@ -180,7 +170,7 @@ function PublicationControls(t0) {
180
170
  });
181
171
  return () => actionsStore.send({
182
172
  type: "unregisterManyActions",
183
- ids: actions.map(_temp3)
173
+ ids: actions.map(_temp2)
184
174
  });
185
175
  };
186
176
  t7 = [
@@ -417,15 +407,12 @@ function PublicationControls(t0) {
417
407
  } else t33 = $[77];
418
408
  return t33;
419
409
  }
420
- function _temp3(item) {
410
+ function _temp2(item) {
421
411
  return item.id;
422
412
  }
423
- function _temp2() {
413
+ function _temp() {
424
414
  return toast.error("Could not complete this action. Please try again.");
425
415
  }
426
- function _temp(state) {
427
- return state.context.previewSource;
428
- }
429
416
 
430
417
  //#endregion
431
418
  export { PublicationRow };
@@ -1,7 +1,8 @@
1
- import { previewStore, selectionBlockId } from "../previewStore.js";
1
+ import { previewStore, selectIsCommentMode, selectionBlockId } from "../previewStore.js";
2
2
  import { AddBlockSidebar } from "./AddBlockSidebar.js";
3
3
  import { PageEditorSidebar } from "./PageEditorSidebar.js";
4
4
  import { PageInfoSidebar } from "./PageInfoSidebar.js";
5
+ import { CommentSidebar } from "./CommentSidebar.js";
5
6
  import { DerivedPageInfoSidebar } from "./DerivedPageInfoSidebar.js";
6
7
  import { c } from "react/compiler-runtime";
7
8
  import { jsx } from "react/jsx-runtime";
@@ -9,14 +10,15 @@ import { useSelector } from "@xstate/store-react";
9
10
 
10
11
  //#region src/features/preview/components/RightSidebar.tsx
11
12
  const RightSidebar = (t0) => {
12
- const $ = c(9);
13
- if ($[0] !== "d71e54add8a0890703a029e4ca30b5b8fa7b144767455a2e03c5c0c217ac64a0") {
14
- for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
15
- $[0] = "d71e54add8a0890703a029e4ca30b5b8fa7b144767455a2e03c5c0c217ac64a0";
13
+ const $ = c(10);
14
+ if ($[0] !== "3a6f3cf40d082faeaea258269c927ca17e318c22f0c389df569e2bea3318461a") {
15
+ for (let $i = 0; $i < 10; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
16
+ $[0] = "3a6f3cf40d082faeaea258269c927ca17e318c22f0c389df569e2bea3318461a";
16
17
  }
17
18
  const { pageId, derivedLayoutId } = t0;
18
19
  const selection = useSelector(previewStore, _temp);
19
20
  const isAddBlockSidebarOpen = useSelector(previewStore, _temp2);
21
+ const isCommentMode = useSelector(previewStore, selectIsCommentMode);
20
22
  let t1;
21
23
  if ($[1] !== selection) {
22
24
  t1 = selectionBlockId(selection);
@@ -31,18 +33,19 @@ const RightSidebar = (t0) => {
31
33
  $[3] = t2;
32
34
  } else t2 = $[3];
33
35
  let t3;
34
- if ($[4] !== derivedLayoutId || $[5] !== isAddBlockSidebarOpen || $[6] !== pageId || $[7] !== selectedBlockId) {
36
+ if ($[4] !== derivedLayoutId || $[5] !== isAddBlockSidebarOpen || $[6] !== isCommentMode || $[7] !== pageId || $[8] !== selectedBlockId) {
35
37
  t3 = /* @__PURE__ */ jsx("aside", {
36
38
  className: "bg-background relative flex shrink-0 flex-col border-l-2",
37
39
  style: t2,
38
- children: pageId != null && isAddBlockSidebarOpen ? /* @__PURE__ */ jsx(AddBlockSidebar, {}) : selectedBlockId != null ? /* @__PURE__ */ jsx(PageEditorSidebar, {}) : pageId != null ? /* @__PURE__ */ jsx(PageInfoSidebar, { pageId }) : /* @__PURE__ */ jsx(DerivedPageInfoSidebar, { layoutId: derivedLayoutId })
40
+ children: pageId != null && isCommentMode ? /* @__PURE__ */ jsx(CommentSidebar, { pageId }, pageId) : pageId != null && isAddBlockSidebarOpen ? /* @__PURE__ */ jsx(AddBlockSidebar, {}) : selectedBlockId != null ? /* @__PURE__ */ jsx(PageEditorSidebar, { pageId }) : pageId != null ? /* @__PURE__ */ jsx(PageInfoSidebar, { pageId }) : /* @__PURE__ */ jsx(DerivedPageInfoSidebar, { layoutId: derivedLayoutId })
39
41
  });
40
42
  $[4] = derivedLayoutId;
41
43
  $[5] = isAddBlockSidebarOpen;
42
- $[6] = pageId;
43
- $[7] = selectedBlockId;
44
- $[8] = t3;
45
- } else t3 = $[8];
44
+ $[6] = isCommentMode;
45
+ $[7] = pageId;
46
+ $[8] = selectedBlockId;
47
+ $[9] = t3;
48
+ } else t3 = $[9];
46
49
  return t3;
47
50
  };
48
51
  function _temp(state) {
@@ -0,0 +1,121 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { c } from "react/compiler-runtime";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region src/features/preview/components/SidebarSection.tsx
6
+ function SidebarSection(t0) {
7
+ const $ = c(12);
8
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
9
+ for (let $i = 0; $i < 12; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
10
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
11
+ }
12
+ let className;
13
+ let props;
14
+ let t1;
15
+ if ($[1] !== t0) {
16
+ ({divider: t1, className, ...props} = t0);
17
+ $[1] = t0;
18
+ $[2] = className;
19
+ $[3] = props;
20
+ $[4] = t1;
21
+ } else {
22
+ className = $[2];
23
+ props = $[3];
24
+ t1 = $[4];
25
+ }
26
+ const divider = t1 === void 0 ? "none" : t1;
27
+ const t2 = divider === "top" && "border-t";
28
+ const t3 = divider === "bottom" && "border-b";
29
+ let t4;
30
+ if ($[5] !== className || $[6] !== t2 || $[7] !== t3) {
31
+ t4 = cn("border-border space-y-4 px-2 py-4", t2, t3, className);
32
+ $[5] = className;
33
+ $[6] = t2;
34
+ $[7] = t3;
35
+ $[8] = t4;
36
+ } else t4 = $[8];
37
+ let t5;
38
+ if ($[9] !== props || $[10] !== t4) {
39
+ t5 = /* @__PURE__ */ jsx("section", {
40
+ className: t4,
41
+ ...props
42
+ });
43
+ $[9] = props;
44
+ $[10] = t4;
45
+ $[11] = t5;
46
+ } else t5 = $[11];
47
+ return t5;
48
+ }
49
+ function SidebarSectionHeader(t0) {
50
+ const $ = c(9);
51
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
52
+ for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
53
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
54
+ }
55
+ let className;
56
+ let props;
57
+ if ($[1] !== t0) {
58
+ ({className, ...props} = t0);
59
+ $[1] = t0;
60
+ $[2] = className;
61
+ $[3] = props;
62
+ } else {
63
+ className = $[2];
64
+ props = $[3];
65
+ }
66
+ let t1;
67
+ if ($[4] !== className) {
68
+ t1 = cn("text-muted-foreground flex items-center gap-2 text-sm leading-none font-medium", className);
69
+ $[4] = className;
70
+ $[5] = t1;
71
+ } else t1 = $[5];
72
+ let t2;
73
+ if ($[6] !== props || $[7] !== t1) {
74
+ t2 = /* @__PURE__ */ jsx("h3", {
75
+ className: t1,
76
+ ...props
77
+ });
78
+ $[6] = props;
79
+ $[7] = t1;
80
+ $[8] = t2;
81
+ } else t2 = $[8];
82
+ return t2;
83
+ }
84
+ function SidebarSectionContent(t0) {
85
+ const $ = c(9);
86
+ if ($[0] !== "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f") {
87
+ for (let $i = 0; $i < 9; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
88
+ $[0] = "938a82e9b8a6fb2a869fbfc9e5e1c7b223dbe304de2e86e65be966943dbe5b5f";
89
+ }
90
+ let className;
91
+ let props;
92
+ if ($[1] !== t0) {
93
+ ({className, ...props} = t0);
94
+ $[1] = t0;
95
+ $[2] = className;
96
+ $[3] = props;
97
+ } else {
98
+ className = $[2];
99
+ props = $[3];
100
+ }
101
+ let t1;
102
+ if ($[4] !== className) {
103
+ t1 = cn("space-y-4", className);
104
+ $[4] = className;
105
+ $[5] = t1;
106
+ } else t1 = $[5];
107
+ let t2;
108
+ if ($[6] !== props || $[7] !== t1) {
109
+ t2 = /* @__PURE__ */ jsx("div", {
110
+ className: t1,
111
+ ...props
112
+ });
113
+ $[6] = props;
114
+ $[7] = t1;
115
+ $[8] = t2;
116
+ } else t2 = $[8];
117
+ return t2;
118
+ }
119
+
120
+ //#endregion
121
+ export { SidebarSection, SidebarSectionContent, SidebarSectionHeader };
@@ -0,0 +1,115 @@
1
+ import { previewStore } from "./previewStore.js";
2
+ import { createStore } from "@xstate/store-react";
3
+
4
+ //#region src/features/preview/previewCommentsStore.ts
5
+ function revealCommentTarget(target) {
6
+ previewStore.send({
7
+ type: "setCommentMode",
8
+ enabled: false
9
+ });
10
+ previewStore.send({ type: "closeAddBlockSidebar" });
11
+ previewStore.send({ type: "clearPeekedBlock" });
12
+ if (target.blockId == null) {
13
+ previewStore.send({
14
+ type: "setSelection",
15
+ selection: null
16
+ });
17
+ return;
18
+ }
19
+ if (target.fieldName != null) {
20
+ previewStore.send({
21
+ type: "setSelection",
22
+ selection: target.itemId == null ? {
23
+ type: "block-field",
24
+ blockId: target.blockId,
25
+ fieldName: target.fieldName,
26
+ fieldType: target.fieldType ?? "String"
27
+ } : {
28
+ type: "item-field",
29
+ blockId: target.blockId,
30
+ itemId: target.itemId,
31
+ fieldName: target.fieldName,
32
+ fieldType: target.fieldType ?? "String"
33
+ }
34
+ });
35
+ return;
36
+ }
37
+ previewStore.send({
38
+ type: "setSelection",
39
+ selection: target.itemId == null ? {
40
+ type: "block",
41
+ blockId: target.blockId
42
+ } : {
43
+ type: "item",
44
+ blockId: target.blockId,
45
+ itemId: target.itemId
46
+ }
47
+ });
48
+ }
49
+ /** UI prototype only: comments live in memory, scoped to their originating page. */
50
+ const previewCommentsStore = createStore({
51
+ context: {
52
+ comments: [],
53
+ draft: null,
54
+ activeId: null,
55
+ focusTarget: null
56
+ },
57
+ on: {
58
+ startComment: (context, event) => ({
59
+ ...context,
60
+ draft: {
61
+ pageId: event.pageId,
62
+ target: event.target,
63
+ message: ""
64
+ },
65
+ activeId: null,
66
+ focusTarget: event.focusComposer ? event.target : null
67
+ }),
68
+ composerFocused: (context) => ({
69
+ ...context,
70
+ focusTarget: null
71
+ }),
72
+ setMessage: (context, event) => ({
73
+ ...context,
74
+ draft: context.draft ? {
75
+ ...context.draft,
76
+ message: event.message
77
+ } : null
78
+ }),
79
+ postComment: (context, event) => {
80
+ const draft = context.draft;
81
+ if (!draft?.message.trim()) return context;
82
+ return {
83
+ ...context,
84
+ comments: [...context.comments, {
85
+ ...draft,
86
+ id: event.id,
87
+ message: draft.message.trim(),
88
+ author: event.author,
89
+ createdAt: event.createdAt
90
+ }],
91
+ draft: null,
92
+ activeId: event.id,
93
+ focusTarget: null
94
+ };
95
+ },
96
+ selectComment: (context, event) => ({
97
+ ...context,
98
+ activeId: event.id
99
+ }),
100
+ cancelDraft: (context) => ({
101
+ ...context,
102
+ draft: null,
103
+ focusTarget: null
104
+ }),
105
+ clearSelection: (context) => ({
106
+ ...context,
107
+ draft: null,
108
+ activeId: null,
109
+ focusTarget: null
110
+ })
111
+ }
112
+ });
113
+
114
+ //#endregion
115
+ export { previewCommentsStore, revealCommentTarget };
@@ -0,0 +1,75 @@
1
+ import { previewStore, selectIsCommentMode, selectIsEditMode } from "./previewStore.js";
2
+ import { previewCommentsStore, revealCommentTarget } from "./previewCommentsStore.js";
3
+ import { c } from "react/compiler-runtime";
4
+ import { createContext, useContext } from "react";
5
+
6
+ //#region src/features/preview/previewSelection.ts
7
+ const PreviewPageContext = createContext(null);
8
+ /** Both editing and commenting use the target already known by the editable component. */
9
+ function selectPreviewTarget(selection, pageId, event) {
10
+ const snapshot = previewStore.getSnapshot();
11
+ if (!selectIsEditMode(snapshot)) return;
12
+ if (!selectIsCommentMode(snapshot)) {
13
+ if (selection.type === "block") {
14
+ previewStore.send({
15
+ type: "setFocusedBlock",
16
+ blockId: selection.blockId
17
+ });
18
+ return;
19
+ }
20
+ previewStore.send({
21
+ type: "setSelection",
22
+ selection
23
+ });
24
+ return;
25
+ }
26
+ if (!event) return;
27
+ event.preventDefault();
28
+ event.stopPropagation();
29
+ if (pageId === null) return;
30
+ const element = event.currentTarget;
31
+ const rect = element.getBoundingClientRect();
32
+ const field = selection.type === "block-field" || selection.type === "item-field";
33
+ const itemId = "itemId" in selection ? selection.itemId : void 0;
34
+ const attribute = field ? "data-camox-field-id" : selection.type === "item" ? "data-camox-repeater-item-id" : element.hasAttribute("data-camox-comment-block-id") ? "data-camox-comment-block-id" : "data-camox-block-id";
35
+ const id = field ? [
36
+ selection.blockId,
37
+ itemId,
38
+ selection.fieldName
39
+ ].filter((part) => part != null).join("__") : String(itemId ?? selection.blockId);
40
+ const target = {
41
+ blockId: selection.blockId,
42
+ itemId,
43
+ fieldName: field ? selection.fieldName : void 0,
44
+ fieldType: field ? selection.fieldType : void 0,
45
+ selector: `[${attribute}="${CSS.escape(id)}"]`,
46
+ label: field ? `Field · ${selection.fieldName}` : `${selection.type === "item" ? "Item" : "Block"} · ${id}`,
47
+ x: event.clientX == null ? .5 : Math.max(0, Math.min(1, (event.clientX - rect.left) / (rect.width || 1))),
48
+ y: event.clientY == null ? .5 : Math.max(0, Math.min(1, (event.clientY - rect.top) / (rect.height || 1)))
49
+ };
50
+ previewCommentsStore.send({
51
+ type: "startComment",
52
+ pageId,
53
+ target,
54
+ focusComposer: true
55
+ });
56
+ revealCommentTarget(target);
57
+ }
58
+ function usePreviewSelection() {
59
+ const $ = c(3);
60
+ if ($[0] !== "5c1128621012a50122fc348fb93c4181c8f52e6cf8c887d22b4d96421b55a5a6") {
61
+ for (let $i = 0; $i < 3; $i += 1) $[$i] = Symbol.for("react.memo_cache_sentinel");
62
+ $[0] = "5c1128621012a50122fc348fb93c4181c8f52e6cf8c887d22b4d96421b55a5a6";
63
+ }
64
+ const pageId = useContext(PreviewPageContext);
65
+ let t0;
66
+ if ($[1] !== pageId) {
67
+ t0 = (selection, event) => selectPreviewTarget(selection, pageId, event);
68
+ $[1] = pageId;
69
+ $[2] = t0;
70
+ } else t0 = $[2];
71
+ return t0;
72
+ }
73
+
74
+ //#endregion
75
+ export { PreviewPageContext, usePreviewSelection };
@@ -1,4 +1,4 @@
1
- import { trackClientEvent } from "../../lib/telemetry-client.js";
1
+ import { areCommentsEnabled } from "./commentsEnabled.js";
2
2
  import { createStore } from "@xstate/store-react";
3
3
  import { toast } from "@camox/ui/toaster";
4
4
 
@@ -22,43 +22,46 @@ function selectionField(sel) {
22
22
  };
23
23
  return null;
24
24
  }
25
+ const selectIsCommentMode = (state) => state.context.mode === "commenting-draft";
26
+ /** Commenting is a draft-only editing submode. */
27
+ const selectIsEditMode = (state) => state.context.mode === "editing-draft" || selectIsCommentMode(state);
28
+ const selectPreviewSource = (state) => state.context.mode === "previewing-live" ? "live" : "draft";
25
29
  const previewStore = createStore({
26
30
  context: {
27
- isEditMode: false,
31
+ mode: "previewing-draft",
28
32
  isToolbarHidden: false,
29
- isPageEditorSidebarOpen: false,
30
33
  isAddBlockSidebarOpen: false,
31
- addBlockSource: null,
32
34
  isCreatePageModalOpen: false,
33
35
  editingPageId: null,
34
- isDraftSwitchDialogOpen: false,
35
36
  viewportMode: "full",
36
37
  peekedBlock: null,
37
38
  peekedBlockPosition: null,
38
39
  skipPeekedBlockExitAnimation: false,
39
40
  selection: null,
40
- iframeElement: null,
41
- previewSource: "draft"
41
+ iframeElement: null
42
42
  },
43
43
  on: {
44
- exitEditMode: (context, _, enqueue) => {
45
- if (!context.isEditMode) return context;
46
- enqueue.effect(() => {
47
- trackClientEvent("edit_mode_toggled", { enabled: false });
48
- });
44
+ setCommentMode: (context, event) => {
45
+ if (!selectIsEditMode({ context })) return context;
46
+ const commenting = areCommentsEnabled() && event.enabled;
49
47
  return {
50
48
  ...context,
51
- isEditMode: false
49
+ mode: commenting ? "commenting-draft" : "editing-draft",
50
+ selection: commenting ? null : context.selection
52
51
  };
53
52
  },
54
- enterEditMode: (context, _, enqueue) => {
55
- if (context.isEditMode) return context;
56
- enqueue.effect(() => {
57
- trackClientEvent("edit_mode_toggled", { enabled: true });
58
- });
53
+ exitEditMode: (context) => {
54
+ if (!selectIsEditMode({ context })) return context;
59
55
  return {
60
56
  ...context,
61
- isEditMode: true,
57
+ mode: "previewing-draft"
58
+ };
59
+ },
60
+ enterEditMode: (context) => {
61
+ if (selectIsEditMode({ context })) return context;
62
+ return {
63
+ ...context,
64
+ mode: "editing-draft",
62
65
  isToolbarHidden: false
63
66
  };
64
67
  },
@@ -68,14 +71,12 @@ const previewStore = createStore({
68
71
  }),
69
72
  viewLivePage: (context, _, enqueue) => {
70
73
  enqueue.effect(() => {
71
- if (context.isEditMode) trackClientEvent("edit_mode_toggled", { enabled: false });
72
74
  toast("Viewing live version of the site");
73
75
  });
74
76
  return {
75
77
  ...context,
76
- isEditMode: false,
77
- isToolbarHidden: true,
78
- previewSource: "live"
78
+ mode: "previewing-live",
79
+ isToolbarHidden: true
79
80
  };
80
81
  },
81
82
  setViewportMode: (context, event) => {
@@ -186,14 +187,12 @@ const previewStore = createStore({
186
187
  openAddBlockSidebar: (context, event) => ({
187
188
  ...context,
188
189
  isAddBlockSidebarOpen: true,
189
- addBlockSource: event.via ?? null,
190
190
  peekedBlock: null,
191
191
  peekedBlockPosition: event.afterPosition ?? null
192
192
  }),
193
193
  closeAddBlockSidebar: (context) => ({
194
194
  ...context,
195
195
  isAddBlockSidebarOpen: false,
196
- addBlockSource: null,
197
196
  peekedBlock: null,
198
197
  peekedBlockPosition: null
199
198
  }),
@@ -212,25 +211,6 @@ const previewStore = createStore({
212
211
  ...context,
213
212
  skipPeekedBlockExitAnimation: false
214
213
  }),
215
- toggleContentSheet: (context) => ({
216
- ...context,
217
- isPageEditorSidebarOpen: false
218
- }),
219
- openBlockContentSheet: (context, event) => {
220
- const currentBlockMatches = context.selection?.blockId === event.blockId;
221
- return {
222
- ...context,
223
- isPageEditorSidebarOpen: false,
224
- selection: currentBlockMatches ? context.selection : {
225
- type: "block",
226
- blockId: event.blockId
227
- }
228
- };
229
- },
230
- closeBlockContentSheet: (context) => ({
231
- ...context,
232
- isPageEditorSidebarOpen: false
233
- }),
234
214
  openCreatePageModal: (context) => ({
235
215
  ...context,
236
216
  isCreatePageModalOpen: true
@@ -239,9 +219,8 @@ const previewStore = createStore({
239
219
  ...context,
240
220
  isCreatePageModalOpen: false
241
221
  }),
242
- openEditPageModal: (context, event, enqueue) => {
222
+ openEditPageModal: (context, event) => {
243
223
  if (context.editingPageId === event.pageId) return context;
244
- enqueue.effect(() => trackClientEvent("page_editor_opened", { pageId: event.pageId }));
245
224
  return {
246
225
  ...context,
247
226
  editingPageId: event.pageId
@@ -255,29 +234,19 @@ const previewStore = createStore({
255
234
  ...context,
256
235
  iframeElement: event.element
257
236
  }),
258
- setPreviewSource: (context, event, enqueue) => {
259
- if (event.source === context.previewSource) return context;
237
+ viewDraftPage: (context, _, enqueue) => {
238
+ if (context.mode !== "previewing-live") return context;
260
239
  enqueue.effect(() => {
261
- toast(event.source === "draft" ? "Previewing draft content" : "Previewing live content", { duration: 2500 });
240
+ toast("Previewing draft content", { duration: 2500 });
262
241
  });
263
242
  return {
264
243
  ...context,
265
- previewSource: event.source
266
- };
267
- },
268
- requestDraftSwitch: (context) => {
269
- if (context.previewSource === "draft") return context;
270
- return {
271
- ...context,
272
- isDraftSwitchDialogOpen: true
244
+ mode: "previewing-draft",
245
+ isToolbarHidden: false
273
246
  };
274
- },
275
- dismissDraftSwitch: (context) => ({
276
- ...context,
277
- isDraftSwitchDialogOpen: false
278
- })
247
+ }
279
248
  }
280
249
  });
281
250
 
282
251
  //#endregion
283
- export { previewStore, selectionBlockId, selectionField, selectionItemId };
252
+ export { previewStore, selectIsCommentMode, selectIsEditMode, selectPreviewSource, selectionBlockId, selectionField, selectionItemId };