camox 0.63.0 → 0.66.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/createApp.d.ts +28 -28
  2. package/dist/core/createLayout.d.ts +1 -1
  3. package/dist/core/derivedRoutes.js +3 -30
  4. package/dist/core/editing/createEditableBlock.d.ts +604 -604
  5. package/dist/features/canvas/CamoxCanvas.js +195 -173
  6. package/dist/features/canvas/canvasCamera.js +11 -2
  7. package/dist/features/canvas/canvasFrameCapture.js +5 -12
  8. package/dist/features/canvas/canvasFrameDocument.js +90 -29
  9. package/dist/features/canvas/canvasItems.js +22 -6
  10. package/dist/features/canvas/sidebar/ContentSidebar.js +19 -21
  11. package/dist/features/canvas/sidebar/LayoutPageOverview.js +22 -49
  12. package/dist/features/canvas/sidebar/LayoutPageSeo.js +73 -76
  13. package/dist/features/canvas/sidebar/PageInspector.js +61 -50
  14. package/dist/features/canvas/sidebar/PageInspectorSkeleton.js +4 -4
  15. package/dist/features/canvas/useCanvasCamera.js +36 -15
  16. package/dist/features/page/CuratedPageContent.js +2 -1
  17. package/dist/features/page/UnplacedBlockContent.js +52 -0
  18. package/dist/features/preview/components/PageInfo.js +103 -100
  19. package/dist/features/preview/components/PreviewPanel.js +40 -12
  20. package/dist/features/preview/components/SidebarStack.js +78 -9
  21. package/dist/features/preview/strayCaretGuard.js +34 -0
  22. package/dist/features/provider/CoreCamoxProvider.js +5 -3
  23. package/dist/features/routes/pageRuntime.d.ts +2 -0
  24. package/dist/features/routes/pageRuntime.js +8 -5
  25. package/dist/features/runtime/RuntimeChrome.js +66 -40
  26. package/dist/features/runtime/pageApp.js +111 -74
  27. package/dist/features/runtime/pageClient.js +22 -2
  28. package/dist/features/runtime/runtime.d.ts +10 -0
  29. package/dist/features/runtime/runtime.js +314 -4
  30. package/dist/features/runtime/runtimeRoutes.d.ts +5 -0
  31. package/dist/features/runtime/runtimeRoutes.js +5 -0
  32. package/dist/features/studio/components/AgentSidebar.js +3 -3
  33. package/dist/features/studio/components/ChatWidget.js +106 -75
  34. package/dist/features/studio/components/ConnectAgent.js +313 -0
  35. package/dist/features/studio/components/DraftsControl.js +172 -159
  36. package/dist/features/studio/components/Patrol.js +605 -350
  37. package/dist/features/studio/components/ReviewDraftSheet.js +566 -430
  38. package/dist/features/studio/components/Squareling.js +74 -41
  39. package/dist/features/studio/components/ThreadComposer.js +192 -107
  40. package/dist/features/studio/components/ThreadMessages.js +95 -18
  41. package/dist/features/studio/components/UnnamedDraftBar.js +349 -0
  42. package/dist/features/studio/components/clientLogoPaths.js +10 -0
  43. package/dist/features/studio/findingSentence.js +37 -0
  44. package/dist/features/studio/patrollerBio.js +40 -0
  45. package/dist/features/studio/reportSentence.js +15 -0
  46. package/dist/features/studio/studioStore.js +36 -1
  47. package/dist/features/studio/workingSentence.js +10 -7
  48. package/dist/lib/api-client.d.ts +1 -0
  49. package/dist/lib/auth.js +34 -32
  50. package/dist/lib/queries.js +9 -1
  51. package/dist/lib/revisions.js +25 -3
  52. package/dist/lib/server-auth-cookie.js +17 -4
  53. package/dist/lib/studio-reads.d.ts +1 -1
  54. package/dist/lib/studio-reads.js +5 -1
  55. package/dist/lib/use-thread.js +1 -1
  56. package/dist/package.js +1 -1
  57. package/dist/studio.css +1 -1
  58. package/package.json +15 -4
  59. package/dist/features/canvas/sidebar/DerivedPageInspector.js +0 -49
  60. package/dist/features/canvas/sidebar/SingletonPageInspector.js +0 -39
@@ -11,6 +11,7 @@ import { DebouncedFieldEditor } from "./DebouncedFieldEditor.js";
11
11
  import { Metadata, MetadataRow, formatRelativeTime } from "./Metadata.js";
12
12
  import { useLocalizedPath } from "../../../lib/view-locale.js";
13
13
  import { PageInfoSkeleton } from "./PageInfoSkeleton.js";
14
+ import { useLatestRevision } from "../../../lib/revisions.js";
14
15
  import { useRendererAnswer } from "../../renderer/RendererFrames.js";
15
16
  import { PageLocationFieldset } from "./PageLocationFieldset.js";
16
17
  import { PageNicknameField } from "./PageNicknameField.js";
@@ -1428,62 +1429,64 @@ const SearchEnginePreview = (t0) => {
1428
1429
  return t10;
1429
1430
  };
1430
1431
  const SocialPreviewSection = (t0) => {
1431
- const $ = c(60);
1432
+ const $ = c(61);
1432
1433
  const { page, metaTitle, metaDescription } = t0;
1433
1434
  const studioCache = useStudioCache();
1434
1435
  const localized = useLocalizedPath();
1435
- const { scope } = useOptionalDraftScope();
1436
+ const { scope, draftId } = useOptionalDraftScope();
1437
+ const revision = useLatestRevision(draftId);
1436
1438
  let t1;
1437
1439
  let t2;
1438
- if ($[0] !== localized || $[1] !== page.fullPath || $[2] !== page.metaDescription || $[3] !== page.metaTitle) {
1439
- const version = new URLSearchParams({ v: `${page.metaTitle ?? ""}|${page.metaDescription ?? ""}` });
1440
- if ($[6] !== localized || $[7] !== page.fullPath) {
1440
+ if ($[0] !== localized || $[1] !== page.fullPath || $[2] !== page.metaDescription || $[3] !== page.metaTitle || $[4] !== revision) {
1441
+ const version = new URLSearchParams({ v: `${page.metaTitle ?? ""}|${page.metaDescription ?? ""}|${revision ?? ""}` });
1442
+ if ($[7] !== localized || $[8] !== page.fullPath) {
1441
1443
  t1 = pageImageUrl({
1442
1444
  origin: "",
1443
1445
  path: localized(page.fullPath)
1444
1446
  });
1445
- $[6] = localized;
1446
- $[7] = page.fullPath;
1447
- $[8] = t1;
1448
- } else t1 = $[8];
1447
+ $[7] = localized;
1448
+ $[8] = page.fullPath;
1449
+ $[9] = t1;
1450
+ } else t1 = $[9];
1449
1451
  t2 = version.toString();
1450
1452
  $[0] = localized;
1451
1453
  $[1] = page.fullPath;
1452
1454
  $[2] = page.metaDescription;
1453
1455
  $[3] = page.metaTitle;
1454
- $[4] = t1;
1455
- $[5] = t2;
1456
+ $[4] = revision;
1457
+ $[5] = t1;
1458
+ $[6] = t2;
1456
1459
  } else {
1457
- t1 = $[4];
1458
- t2 = $[5];
1460
+ t1 = $[5];
1461
+ t2 = $[6];
1459
1462
  }
1460
1463
  const generatedOgImage = `${t1}&${t2}`;
1461
1464
  let t3;
1462
- if ($[9] !== generatedOgImage || $[10] !== page.customOgImageUrl || $[11] !== scope) {
1465
+ if ($[10] !== generatedOgImage || $[11] !== page.customOgImageUrl || $[12] !== scope) {
1463
1466
  t3 = page.customOgImageUrl || (scope?.hrefFor(generatedOgImage) ?? generatedOgImage);
1464
- $[9] = generatedOgImage;
1465
- $[10] = page.customOgImageUrl;
1466
- $[11] = scope;
1467
- $[12] = t3;
1468
- } else t3 = $[12];
1467
+ $[10] = generatedOgImage;
1468
+ $[11] = page.customOgImageUrl;
1469
+ $[12] = scope;
1470
+ $[13] = t3;
1471
+ } else t3 = $[13];
1469
1472
  const ogImage = t3;
1470
1473
  const origin = typeof window !== "undefined" ? window.location.origin : "";
1471
1474
  let t4;
1472
- if ($[13] !== localized || $[14] !== page.fullPath) {
1475
+ if ($[14] !== localized || $[15] !== page.fullPath) {
1473
1476
  t4 = localized(page.fullPath);
1474
- $[13] = localized;
1475
- $[14] = page.fullPath;
1476
- $[15] = t4;
1477
- } else t4 = $[15];
1477
+ $[14] = localized;
1478
+ $[15] = page.fullPath;
1479
+ $[16] = t4;
1480
+ } else t4 = $[16];
1478
1481
  const url = `${origin}${t4}`;
1479
1482
  const fileInputRef = React.useRef(null);
1480
1483
  let t5;
1481
- if ($[16] === Symbol.for("react.memo_cache_sentinel")) {
1484
+ if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
1482
1485
  t5 = pageMutations.uploadCustomOgImage();
1483
- $[16] = t5;
1484
- } else t5 = $[16];
1486
+ $[17] = t5;
1487
+ } else t5 = $[17];
1485
1488
  let t6;
1486
- if ($[17] !== page.id || $[18] !== studioCache) {
1489
+ if ($[18] !== page.id || $[19] !== studioCache) {
1487
1490
  t6 = {
1488
1491
  ...t5,
1489
1492
  onSuccess: () => {
@@ -1491,18 +1494,18 @@ const SocialPreviewSection = (t0) => {
1491
1494
  },
1492
1495
  onError: _temp13
1493
1496
  };
1494
- $[17] = page.id;
1495
- $[18] = studioCache;
1496
- $[19] = t6;
1497
- } else t6 = $[19];
1497
+ $[18] = page.id;
1498
+ $[19] = studioCache;
1499
+ $[20] = t6;
1500
+ } else t6 = $[20];
1498
1501
  const uploadCustomOgImage = useMutation(t6);
1499
1502
  let t7;
1500
- if ($[20] === Symbol.for("react.memo_cache_sentinel")) {
1503
+ if ($[21] === Symbol.for("react.memo_cache_sentinel")) {
1501
1504
  t7 = pageMutations.deleteCustomOgImage();
1502
- $[20] = t7;
1503
- } else t7 = $[20];
1505
+ $[21] = t7;
1506
+ } else t7 = $[21];
1504
1507
  let t8;
1505
- if ($[21] !== page.id || $[22] !== studioCache) {
1508
+ if ($[22] !== page.id || $[23] !== studioCache) {
1506
1509
  t8 = {
1507
1510
  ...t7,
1508
1511
  onSuccess: () => {
@@ -1510,15 +1513,15 @@ const SocialPreviewSection = (t0) => {
1510
1513
  },
1511
1514
  onError: _temp14
1512
1515
  };
1513
- $[21] = page.id;
1514
- $[22] = studioCache;
1515
- $[23] = t8;
1516
- } else t8 = $[23];
1516
+ $[22] = page.id;
1517
+ $[23] = studioCache;
1518
+ $[24] = t8;
1519
+ } else t8 = $[24];
1517
1520
  const deleteCustomOgImage = useMutation(t8);
1518
1521
  const hasCustomImage = !!page.customOgImageUrl;
1519
1522
  const isBusy = uploadCustomOgImage.isPending || deleteCustomOgImage.isPending;
1520
1523
  let t9;
1521
- if ($[24] !== page.id || $[25] !== uploadCustomOgImage) {
1524
+ if ($[25] !== page.id || $[26] !== uploadCustomOgImage) {
1522
1525
  t9 = (files) => {
1523
1526
  const file = files[0];
1524
1527
  if (file) uploadCustomOgImage.mutate({
@@ -1526,30 +1529,30 @@ const SocialPreviewSection = (t0) => {
1526
1529
  file
1527
1530
  });
1528
1531
  };
1529
- $[24] = page.id;
1530
- $[25] = uploadCustomOgImage;
1531
- $[26] = t9;
1532
- } else t9 = $[26];
1532
+ $[25] = page.id;
1533
+ $[26] = uploadCustomOgImage;
1534
+ $[27] = t9;
1535
+ } else t9 = $[27];
1533
1536
  const handleFiles = t9;
1534
1537
  let t10;
1535
- if ($[27] === Symbol.for("react.memo_cache_sentinel")) {
1538
+ if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
1536
1539
  t10 = /* @__PURE__ */ jsx(Label, { children: "Social preview" });
1537
- $[27] = t10;
1538
- } else t10 = $[27];
1540
+ $[28] = t10;
1541
+ } else t10 = $[28];
1539
1542
  let t11;
1540
- if ($[28] === Symbol.for("react.memo_cache_sentinel")) {
1543
+ if ($[29] === Symbol.for("react.memo_cache_sentinel")) {
1541
1544
  t11 = () => fileInputRef.current?.click();
1542
- $[28] = t11;
1543
- } else t11 = $[28];
1545
+ $[29] = t11;
1546
+ } else t11 = $[29];
1544
1547
  let t12;
1545
- if ($[29] !== uploadCustomOgImage.isPending) {
1548
+ if ($[30] !== uploadCustomOgImage.isPending) {
1546
1549
  t12 = uploadCustomOgImage.isPending ? /* @__PURE__ */ jsx(Spinner, {}) : /* @__PURE__ */ jsx(Upload, { className: "size-3.5" });
1547
- $[29] = uploadCustomOgImage.isPending;
1548
- $[30] = t12;
1549
- } else t12 = $[30];
1550
+ $[30] = uploadCustomOgImage.isPending;
1551
+ $[31] = t12;
1552
+ } else t12 = $[31];
1550
1553
  const t13 = hasCustomImage ? "Replace custom image" : "Upload custom image";
1551
1554
  let t14;
1552
- if ($[31] !== isBusy || $[32] !== t12 || $[33] !== t13) {
1555
+ if ($[32] !== isBusy || $[33] !== t12 || $[34] !== t13) {
1553
1556
  t14 = /* @__PURE__ */ jsxs(Button, {
1554
1557
  type: "button",
1555
1558
  variant: "secondary",
@@ -1558,13 +1561,13 @@ const SocialPreviewSection = (t0) => {
1558
1561
  onClick: t11,
1559
1562
  children: [t12, t13]
1560
1563
  });
1561
- $[31] = isBusy;
1562
- $[32] = t12;
1563
- $[33] = t13;
1564
- $[34] = t14;
1565
- } else t14 = $[34];
1564
+ $[32] = isBusy;
1565
+ $[33] = t12;
1566
+ $[34] = t13;
1567
+ $[35] = t14;
1568
+ } else t14 = $[35];
1566
1569
  let t15;
1567
- if ($[35] !== deleteCustomOgImage || $[36] !== hasCustomImage || $[37] !== isBusy || $[38] !== page.id) {
1570
+ if ($[36] !== deleteCustomOgImage || $[37] !== hasCustomImage || $[38] !== isBusy || $[39] !== page.id) {
1568
1571
  t15 = hasCustomImage && /* @__PURE__ */ jsxs(Button, {
1569
1572
  type: "button",
1570
1573
  variant: "ghost",
@@ -1577,14 +1580,14 @@ const SocialPreviewSection = (t0) => {
1577
1580
  "Clear"
1578
1581
  ]
1579
1582
  });
1580
- $[35] = deleteCustomOgImage;
1581
- $[36] = hasCustomImage;
1582
- $[37] = isBusy;
1583
- $[38] = page.id;
1584
- $[39] = t15;
1585
- } else t15 = $[39];
1583
+ $[36] = deleteCustomOgImage;
1584
+ $[37] = hasCustomImage;
1585
+ $[38] = isBusy;
1586
+ $[39] = page.id;
1587
+ $[40] = t15;
1588
+ } else t15 = $[40];
1586
1589
  let t16;
1587
- if ($[40] !== handleFiles) {
1590
+ if ($[41] !== handleFiles) {
1588
1591
  t16 = /* @__PURE__ */ jsx("input", {
1589
1592
  type: "file",
1590
1593
  ref: fileInputRef,
@@ -1595,11 +1598,11 @@ const SocialPreviewSection = (t0) => {
1595
1598
  e.target.value = "";
1596
1599
  }
1597
1600
  });
1598
- $[40] = handleFiles;
1599
- $[41] = t16;
1600
- } else t16 = $[41];
1601
+ $[41] = handleFiles;
1602
+ $[42] = t16;
1603
+ } else t16 = $[42];
1601
1604
  let t17;
1602
- if ($[42] !== t14 || $[43] !== t15 || $[44] !== t16) {
1605
+ if ($[43] !== t14 || $[44] !== t15 || $[45] !== t16) {
1603
1606
  t17 = /* @__PURE__ */ jsxs("div", {
1604
1607
  className: "flex items-center gap-2",
1605
1608
  children: [
@@ -1608,47 +1611,47 @@ const SocialPreviewSection = (t0) => {
1608
1611
  t16
1609
1612
  ]
1610
1613
  });
1611
- $[42] = t14;
1612
- $[43] = t15;
1613
- $[44] = t16;
1614
- $[45] = t17;
1615
- } else t17 = $[45];
1614
+ $[43] = t14;
1615
+ $[44] = t15;
1616
+ $[45] = t16;
1617
+ $[46] = t17;
1618
+ } else t17 = $[46];
1616
1619
  const t18 = hasCustomImage ? "Drop image to replace" : "Drop image to upload";
1617
1620
  let t19;
1618
- if ($[46] !== ogImage) {
1621
+ if ($[47] !== ogImage) {
1619
1622
  t19 = /* @__PURE__ */ jsx(SocialPreviewImage, { src: ogImage });
1620
- $[46] = ogImage;
1621
- $[47] = t19;
1622
- } else t19 = $[47];
1623
+ $[47] = ogImage;
1624
+ $[48] = t19;
1625
+ } else t19 = $[48];
1623
1626
  let t20;
1624
- if ($[48] !== handleFiles || $[49] !== t18 || $[50] !== t19) {
1627
+ if ($[49] !== handleFiles || $[50] !== t18 || $[51] !== t19) {
1625
1628
  t20 = /* @__PURE__ */ jsx(UploadDropZone, {
1626
1629
  onDrop: handleFiles,
1627
1630
  label: t18,
1628
1631
  className: "block",
1629
1632
  children: t19
1630
1633
  });
1631
- $[48] = handleFiles;
1632
- $[49] = t18;
1633
- $[50] = t19;
1634
- $[51] = t20;
1635
- } else t20 = $[51];
1634
+ $[49] = handleFiles;
1635
+ $[50] = t18;
1636
+ $[51] = t19;
1637
+ $[52] = t20;
1638
+ } else t20 = $[52];
1636
1639
  let t21;
1637
- if ($[52] !== metaDescription || $[53] !== metaTitle || $[54] !== t20 || $[55] !== url) {
1640
+ if ($[53] !== metaDescription || $[54] !== metaTitle || $[55] !== t20 || $[56] !== url) {
1638
1641
  t21 = /* @__PURE__ */ jsx(SocialPreviewCard, {
1639
1642
  image: t20,
1640
1643
  metaTitle,
1641
1644
  metaDescription,
1642
1645
  url
1643
1646
  });
1644
- $[52] = metaDescription;
1645
- $[53] = metaTitle;
1646
- $[54] = t20;
1647
- $[55] = url;
1648
- $[56] = t21;
1649
- } else t21 = $[56];
1647
+ $[53] = metaDescription;
1648
+ $[54] = metaTitle;
1649
+ $[55] = t20;
1650
+ $[56] = url;
1651
+ $[57] = t21;
1652
+ } else t21 = $[57];
1650
1653
  let t22;
1651
- if ($[57] !== t17 || $[58] !== t21) {
1654
+ if ($[58] !== t17 || $[59] !== t21) {
1652
1655
  t22 = /* @__PURE__ */ jsxs("div", {
1653
1656
  className: "space-y-2 pt-2",
1654
1657
  children: [
@@ -1657,10 +1660,10 @@ const SocialPreviewSection = (t0) => {
1657
1660
  t21
1658
1661
  ]
1659
1662
  });
1660
- $[57] = t17;
1661
- $[58] = t21;
1662
- $[59] = t22;
1663
- } else t22 = $[59];
1663
+ $[58] = t17;
1664
+ $[59] = t21;
1665
+ $[60] = t22;
1666
+ } else t22 = $[60];
1664
1667
  return t22;
1665
1668
  };
1666
1669
  const SocialPreviewImage = (t0) => {
@@ -11,6 +11,7 @@ import { previewPageIframeProps, usePreviewPageFrame } from "../previewPageFrame
11
11
  import { adoptCanvasDocument, pauseCanvasDocument } from "../../canvas/canvasFrameDocument.js";
12
12
  import { forwardCanvasWheel, useCanvasFrameInput } from "../../canvas/useCanvasFrameInput.js";
13
13
  import { useActionShortcuts } from "../../provider/useAdminShortcuts.js";
14
+ import { guardStrayCaret } from "../strayCaretGuard.js";
14
15
  import { useBlockActionsShortcuts } from "./BlockActionsPopover.js";
15
16
  import { FieldOverlayStyles } from "./FieldOverlayStyles.js";
16
17
  import { MobilePreviewDrawer } from "./MobilePreviewDrawer.js";
@@ -60,6 +61,7 @@ const PreviewFrameEffects = () => {
60
61
  t0 = /* @__PURE__ */ jsxs(Fragment, { children: [
61
62
  /* @__PURE__ */ jsx(FieldOverlayStyles, {}),
62
63
  /* @__PURE__ */ jsx(KeyDownForwarder, {}),
64
+ /* @__PURE__ */ jsx(StrayCaretGuard, {}),
63
65
  /* @__PURE__ */ jsx(OverlayTracker, {})
64
66
  ] });
65
67
  $[0] = t0;
@@ -72,6 +74,27 @@ const KeyDownForwarder = () => {
72
74
  useActionShortcuts(inIframe ? iframeWindow : null);
73
75
  return null;
74
76
  };
77
+ const StrayCaretGuard = () => {
78
+ const $ = c(3);
79
+ const { window: iframeWindow } = useFrame();
80
+ let t0;
81
+ let t1;
82
+ if ($[0] !== iframeWindow) {
83
+ t0 = () => {
84
+ if (!iframeWindow) return;
85
+ return guardStrayCaret(iframeWindow.document);
86
+ };
87
+ t1 = [iframeWindow];
88
+ $[0] = iframeWindow;
89
+ $[1] = t0;
90
+ $[2] = t1;
91
+ } else {
92
+ t0 = $[1];
93
+ t1 = $[2];
94
+ }
95
+ React.useEffect(t0, t1);
96
+ return null;
97
+ };
75
98
  /** The preview's read-only tree is never editable, whether or not the Canvas shows. */
76
99
  const READ_ONLY_ARTIFACT_STUDIO = {
77
100
  editing: false,
@@ -91,7 +114,7 @@ function CuratedBlockShortcuts() {
91
114
  * when used, pauses with the camera, and draws its editing overlays.
92
115
  */
93
116
  function PreviewPageCanvasEffects(t0) {
94
- const $ = c(30);
117
+ const $ = c(31);
95
118
  const { owner } = t0;
96
119
  const { window: frameWindow, iframeElement } = useFrame();
97
120
  const { frame, slot, inCanvas } = usePreviewPageFrame();
@@ -225,33 +248,38 @@ function PreviewPageCanvasEffects(t0) {
225
248
  if (!placed) return null;
226
249
  let t11;
227
250
  let t12;
251
+ let t13;
228
252
  if ($[24] === Symbol.for("react.memo_cache_sentinel")) {
229
253
  t11 = /* @__PURE__ */ jsx(FieldOverlayStyles, {});
230
- t12 = /* @__PURE__ */ jsx(OverlayTracker, {});
254
+ t12 = /* @__PURE__ */ jsx(StrayCaretGuard, {});
255
+ t13 = /* @__PURE__ */ jsx(OverlayTracker, {});
231
256
  $[24] = t11;
232
257
  $[25] = t12;
258
+ $[26] = t13;
233
259
  } else {
234
260
  t11 = $[24];
235
261
  t12 = $[25];
262
+ t13 = $[26];
236
263
  }
237
- const t13 = owner?.kind === "page";
238
- let t14;
239
- if ($[26] !== iframeElement || $[27] !== owner || $[28] !== t13) {
240
- t14 = /* @__PURE__ */ jsxs(Fragment, { children: [
264
+ const t14 = owner?.kind === "page";
265
+ let t15;
266
+ if ($[27] !== iframeElement || $[28] !== owner || $[29] !== t14) {
267
+ t15 = /* @__PURE__ */ jsxs(Fragment, { children: [
241
268
  t11,
242
269
  t12,
270
+ t13,
243
271
  /* @__PURE__ */ jsx(Overlays, {
244
272
  frame: iframeElement,
245
273
  owner,
246
- canAddBlocks: t13
274
+ canAddBlocks: t14
247
275
  })
248
276
  ] });
249
- $[26] = iframeElement;
250
- $[27] = owner;
251
- $[28] = t13;
277
+ $[27] = iframeElement;
278
+ $[28] = owner;
252
279
  $[29] = t14;
253
- } else t14 = $[29];
254
- return t14;
280
+ $[30] = t15;
281
+ } else t15 = $[30];
282
+ return t15;
255
283
  }
256
284
  function _temp(event) {
257
285
  if (event.target?.closest?.("a")) event.preventDefault();
@@ -143,6 +143,8 @@ function SidebarStack(t0) {
143
143
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
144
144
  t1 = {
145
145
  ready: false,
146
+ boxes: /* @__PURE__ */ new Map(),
147
+ observer: null,
146
148
  front: null,
147
149
  behind: null,
148
150
  inFront: null
@@ -156,8 +158,16 @@ function SidebarStack(t0) {
156
158
  t2 = () => {
157
159
  const current = motion.current;
158
160
  current.ready = true;
161
+ if (typeof ResizeObserver !== "undefined") {
162
+ const observer = new ResizeObserver(() => measureCards(current));
163
+ current.observer = observer;
164
+ for (const card of current.boxes.keys()) observer.observe(card);
165
+ if (current.inFront?.parentElement) observer.observe(current.inFront.parentElement);
166
+ }
159
167
  return () => {
160
168
  current.ready = false;
169
+ current.observer?.disconnect();
170
+ current.observer = null;
161
171
  };
162
172
  };
163
173
  t3 = [];
@@ -233,20 +243,57 @@ function SidebarStack(t0) {
233
243
  } else t9 = $[12];
234
244
  return t9;
235
245
  }
236
- /** A still copy of a card, where it was, so it can move away once the card is gone. */
237
- function copyCard(card, layer) {
238
- const layerRect = layer.getBoundingClientRect();
246
+ /**
247
+ * Where a card is laid out relative to `stack`, whose box its layers fill. Offsets leave out the
248
+ * transforms that move cards as they come.
249
+ */
250
+ function layoutBox(card, stack) {
251
+ let left = 0;
252
+ let top = 0;
253
+ let node = card;
254
+ while (node && node !== stack) {
255
+ left += node.offsetLeft;
256
+ top += node.offsetTop;
257
+ const parent = node.offsetParent;
258
+ if (parent && parent !== stack) {
259
+ left += parent.clientLeft;
260
+ top += parent.clientTop;
261
+ }
262
+ node = parent;
263
+ }
264
+ if (node === stack) return {
265
+ left,
266
+ top,
267
+ width: card.offsetWidth,
268
+ height: card.offsetHeight
269
+ };
270
+ const stackRect = stack.getBoundingClientRect();
239
271
  const rect = card.getBoundingClientRect();
272
+ return {
273
+ left: rect.left - stackRect.left,
274
+ top: rect.top - stackRect.top,
275
+ width: rect.width,
276
+ height: rect.height
277
+ };
278
+ }
279
+ /** Notes where each card of the stack is laid out now. */
280
+ function measureCards(motion) {
281
+ const stack = motion.inFront?.parentElement;
282
+ if (!stack) return;
283
+ for (const card of motion.boxes.keys()) if (card.isConnected) motion.boxes.set(card, layoutBox(card, stack));
284
+ }
285
+ /** A still copy of a card, at `box`, so it can move away once the card is gone. */
286
+ function copyCard(card, box) {
240
287
  const copy = card.cloneNode(true);
241
288
  copy.setAttribute("aria-hidden", "true");
242
289
  copy.setAttribute("inert", "");
243
290
  Object.assign(copy.style, {
244
291
  position: "absolute",
245
292
  margin: "0",
246
- left: `${rect.left - layerRect.left}px`,
247
- top: `${rect.top - layerRect.top}px`,
248
- width: `${rect.width}px`,
249
- height: `${rect.height}px`
293
+ left: `${box.left}px`,
294
+ top: `${box.top}px`,
295
+ width: `${box.width}px`,
296
+ height: `${box.height}px`
250
297
  });
251
298
  const scrolled = [];
252
299
  const walk = (node, path) => {
@@ -276,6 +323,13 @@ function useStackCard(ref, depth, isView) {
276
323
  const card = ref.current;
277
324
  const motion = stack?.current;
278
325
  if (!card || !motion || depth == null) return;
326
+ if (!motion.boxes.has(card)) motion.boxes.set(card, {
327
+ left: 0,
328
+ top: 0,
329
+ width: 0,
330
+ height: 0
331
+ });
332
+ motion.observer?.observe(card);
279
333
  const previousFront = motion.front;
280
334
  if (isView) motion.front = depth;
281
335
  if (motion.ready && previousFront != null && prefersMotion()) {
@@ -289,10 +343,21 @@ function useStackCard(ref, depth, isView) {
289
343
  }
290
344
  return () => {
291
345
  const { behind, inFront } = motion;
292
- if (!motion.ready || !behind || !inFront || !prefersMotion()) return;
293
- const { copy, restoreScroll } = copyCard(card, inFront);
346
+ const box = motion.boxes.get(card);
347
+ const forget = () => {
348
+ motion.boxes.delete(card);
349
+ motion.observer?.unobserve(card);
350
+ };
351
+ if (!motion.ready || !behind || !inFront || !box || !prefersMotion()) {
352
+ queueMicrotask(() => {
353
+ if (!card.isConnected) forget();
354
+ });
355
+ return;
356
+ }
357
+ const { copy, restoreScroll } = copyCard(card, box);
294
358
  queueMicrotask(() => {
295
359
  if (card.isConnected) return;
360
+ forget();
296
361
  const how = motionFor(depth, motion.front ?? depth);
297
362
  (how === "front" ? inFront : behind).append(copy);
298
363
  restoreScroll();
@@ -303,6 +368,10 @@ function useStackCard(ref, depth, isView) {
303
368
  });
304
369
  };
305
370
  }, []);
371
+ React.useLayoutEffect(() => {
372
+ const motion = stack?.current;
373
+ if (motion) measureCards(motion);
374
+ });
306
375
  }
307
376
  /**
308
377
  * Eases a header's card and content from where they were laid out before `shape` changed to
@@ -0,0 +1,34 @@
1
+ //#region src/features/preview/strayCaretGuard.ts
2
+ /** Where the browser would put the caret for a click at this point. */
3
+ function caretNodeAt(doc, x, y) {
4
+ if (typeof doc.caretPositionFromPoint === "function") return doc.caretPositionFromPoint(x, y)?.offsetNode ?? null;
5
+ return doc.caretRangeFromPoint?.(x, y)?.startContainer ?? null;
6
+ }
7
+ function isEditable(node) {
8
+ return (node?.nodeType === 1 ? node : node?.parentElement ?? null)?.closest("[contenteditable=\"\"], [contenteditable=\"true\"]") != null;
9
+ }
10
+ /**
11
+ * Keep a click beside an editable field from landing in it. On a click over
12
+ * non-editable content, browsers put the caret at the nearest text, and when that
13
+ * text is in a field, they focus it: clicking a block's padding next to a heading
14
+ * starts editing the heading instead of selecting the block. Such a click now only
15
+ * leaves the field being edited, as a click on content without text would.
16
+ */
17
+ function guardStrayCaret(doc) {
18
+ const onMouseDown = (event) => {
19
+ if (event.button !== 0) return;
20
+ const target = event.target;
21
+ if (!target || isEditable(target)) return;
22
+ if (target.closest?.("input, textarea, select, button")) return;
23
+ if (!isEditable(caretNodeAt(doc, event.clientX, event.clientY))) return;
24
+ event.preventDefault();
25
+ const active = doc.activeElement;
26
+ if (active?.isContentEditable) active.blur();
27
+ doc.getSelection()?.removeAllRanges();
28
+ };
29
+ doc.addEventListener("mousedown", onMouseDown, true);
30
+ return () => doc.removeEventListener("mousedown", onMouseDown, true);
31
+ }
32
+
33
+ //#endregion
34
+ export { guardStrayCaret };
@@ -9,7 +9,7 @@ import { jsx } from "react/jsx-runtime";
9
9
  import { replaceEqualDeep, useQueryClient } from "@tanstack/react-query";
10
10
 
11
11
  //#region src/features/provider/CoreCamoxProvider.tsx
12
- function CoreCamoxProvider({ apiUrl, authenticationUrl, camoxApp, children, projectUuid, initialAuthenticated = false, initialProject }) {
12
+ function CoreCamoxProvider({ apiUrl, authenticationUrl, camoxApp, children, projectUuid, initialAuthenticated = false, initialProject, sessionless = false }) {
13
13
  const queryClient = useQueryClient();
14
14
  const authClient = React.useMemo(() => createCamoxAuthClient(apiUrl), [apiUrl]);
15
15
  const providedScope = React.useContext(DraftScopeContext);
@@ -48,14 +48,16 @@ function CoreCamoxProvider({ apiUrl, authenticationUrl, camoxApp, children, proj
48
48
  apiUrl,
49
49
  projectUuid,
50
50
  initialAuthenticated,
51
- exchangingToken
51
+ exchangingToken,
52
+ sessionless
52
53
  }), [
53
54
  authClient,
54
55
  authenticationUrl,
55
56
  apiUrl,
56
57
  projectUuid,
57
58
  initialAuthenticated,
58
- exchangingToken
59
+ exchangingToken,
60
+ sessionless
59
61
  ]);
60
62
  const [isPreviewHandoff, setIsPreviewHandoff] = React.useState(false);
61
63
  React.useEffect(() => {
@@ -46,6 +46,8 @@ export interface DraftRead {
46
46
  }
47
47
  export declare function createServerApiClient(apiUrl: string, options?: {
48
48
  authCookieHeader?: string;
49
+ /** A look token, which reads the draft it was signed for without a session (ADR 0032). */
50
+ lookToken?: string;
49
51
  draftId?: string;
50
52
  locale?: LocaleView;
51
53
  }): RouterClient<Router>;