camox 0.52.2 → 0.53.1
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.
- package/dist/core/editing/createEditableBlock.js +1 -1
- package/dist/features/canvas/CamoxCanvas.js +103 -83
- package/dist/features/canvas/CanvasPageFrame.js +1 -1
- package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -1
- package/dist/features/canvas/canvasCamera.js +3 -3
- package/dist/features/canvas/sidebar/CanvasInspector.js +4 -159
- package/dist/features/canvas/sidebar/CanvasNavigator.js +41 -85
- package/dist/features/canvas/sidebar/CanvasSidebar.js +54 -32
- package/dist/features/canvas/sidebar/CanvasSidebarFrame.js +4 -3
- package/dist/features/canvas/sidebar/CanvasSidebarSkeleton.js +14 -6
- package/dist/features/canvas/sidebar/CanvasViewHeader.js +50 -0
- package/dist/features/canvas/sidebar/DerivedPageInspector.js +30 -18
- package/dist/features/canvas/sidebar/LayoutPageOverview.js +28 -11
- package/dist/features/canvas/sidebar/LayoutPageSeo.js +356 -0
- package/dist/features/canvas/sidebar/PageInspector.js +118 -80
- package/dist/features/canvas/sidebar/PageOverview.js +6 -1
- package/dist/features/canvas/sidebar/SingletonPageInspector.js +22 -14
- package/dist/features/canvas/useCanvasCamera.js +36 -39
- package/dist/features/preview/CamoxPreview.js +1 -1
- package/dist/features/preview/components/BlockActionsPopover.js +1 -1
- package/dist/features/preview/components/BlockThumbnail.js +1 -1
- package/dist/features/preview/components/CanvasPreview.js +1 -1
- package/dist/features/preview/components/CreatePageModal.js +1 -1
- package/dist/features/preview/components/ItemFieldsEditor.js +1 -1
- package/dist/features/preview/components/OverlayTracker.js +1 -1
- package/dist/features/preview/components/PageInfo.js +345 -228
- package/dist/features/preview/components/PageTree.js +1 -1
- package/dist/features/preview/components/PreviewPanel.js +1 -1
- package/dist/features/preview/components/PreviewToolbar.js +2 -2
- package/dist/features/preview/components/RepeatableItemsList.js +1 -1
- package/dist/features/preview/components/SelectionEditor.js +645 -655
- package/dist/features/preview/components/SidebarStack.js +553 -0
- package/dist/features/preview/components/StudioEditingFallback.js +2 -2
- package/dist/features/renderer/RendererFrames.js +34 -27
- package/dist/features/runtime/RuntimeChrome.js +1 -1
- package/dist/features/runtime/runtime.js +84 -26
- package/dist/features/studio/components/ChatSidebar.js +27 -19
- package/dist/features/studio/components/Navbar.js +1 -1
- package/dist/features/studio/components/UserButton.js +1 -1
- package/dist/lib/studio-reads.js +18 -0
- package/dist/package.js +1 -1
- package/dist/studio.css +1 -1
- package/package.json +4 -4
|
@@ -45,6 +45,12 @@ function isTextEntry(target) {
|
|
|
45
45
|
function rescaleY(camera, scale) {
|
|
46
46
|
return camera.y > 0 ? camera.y : camera.y * scale / camera.scale;
|
|
47
47
|
}
|
|
48
|
+
const NO_INSETS = {
|
|
49
|
+
top: 0,
|
|
50
|
+
right: 0,
|
|
51
|
+
bottom: 0,
|
|
52
|
+
left: 0
|
|
53
|
+
};
|
|
48
54
|
/** Animate only the camera's CSS properties; page trees never rerender on pan/zoom. */
|
|
49
55
|
function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
50
56
|
const continuity = React.useContext(ViewportContinuityContext);
|
|
@@ -102,20 +108,22 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
102
108
|
capture: true,
|
|
103
109
|
passive: false
|
|
104
110
|
});
|
|
105
|
-
let
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
let insets = rowRef.current?.insets ?? NO_INSETS;
|
|
112
|
+
const measureViewport = () => {
|
|
113
|
+
insets = rowRef.current?.insets ?? NO_INSETS;
|
|
114
|
+
return {
|
|
115
|
+
width: Math.max(0, viewport.clientWidth - insets.left - insets.right),
|
|
116
|
+
height: Math.max(0, viewport.clientHeight - insets.top - insets.bottom)
|
|
117
|
+
};
|
|
108
118
|
};
|
|
119
|
+
let viewportSize = measureViewport();
|
|
109
120
|
const measureContent = () => ({
|
|
110
121
|
width: rowRef.current?.width ?? content.offsetWidth,
|
|
111
122
|
height: content.offsetHeight
|
|
112
123
|
});
|
|
113
124
|
let contentSize = measureContent();
|
|
114
125
|
let minimumScale = canvasMinimumScale(viewportSize, contentSize);
|
|
115
|
-
const updateGeometry = (nextViewport = {
|
|
116
|
-
width: viewport.clientWidth,
|
|
117
|
-
height: viewport.clientHeight
|
|
118
|
-
}, nextContent = measureContent()) => {
|
|
126
|
+
const updateGeometry = (nextViewport = measureViewport(), nextContent = measureContent()) => {
|
|
119
127
|
viewportSize = nextViewport;
|
|
120
128
|
contentSize = nextContent;
|
|
121
129
|
minimumScale = canvasMinimumScale(viewportSize, contentSize);
|
|
@@ -128,7 +136,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
128
136
|
const targetOf = (key) => key == null ? void 0 : targets().find((candidate) => candidate.key === key);
|
|
129
137
|
let stretch;
|
|
130
138
|
let zoomEnd = 0;
|
|
131
|
-
let landing;
|
|
132
139
|
const constrain = (next, stretched = !!stretch) => constrainCanvasCamera(next, viewportSize, contentSize, canvasMaximumScale(viewportSize, targets(), minimumScale), stretched);
|
|
133
140
|
const saved = canvasStore.getSnapshot().context.views[workspaceKey];
|
|
134
141
|
const savedCamera = saved && !saved.fitted ? saved.camera : void 0;
|
|
@@ -194,16 +201,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
194
201
|
y: anchored.y + translation.y
|
|
195
202
|
};
|
|
196
203
|
if (!candidate || !fit || !isCanvasPageScale(snapped, fit.scale)) return next;
|
|
197
|
-
const entered = selection !== candidate.key;
|
|
198
|
-
if (entered) landing = {
|
|
199
|
-
key: candidate.key,
|
|
200
|
-
stretched
|
|
201
|
-
};
|
|
202
|
-
else if (stretched && landing && !landing.stretched) {
|
|
203
|
-
landing.stretched = true;
|
|
204
|
-
rowRef.current?.onSnapStretched?.();
|
|
205
|
-
}
|
|
206
|
-
if (entered && !stretched) rowRef.current?.onSnap?.();
|
|
207
204
|
select(candidate.key);
|
|
208
205
|
return {
|
|
209
206
|
...next,
|
|
@@ -236,7 +233,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
236
233
|
if (!candidate || !fit || fit.scale < minimumScale) return intended;
|
|
237
234
|
const held = isCanvasCameraSnapped(base, viewportSize, candidate);
|
|
238
235
|
if (!isInCanvasSnapWindow(intended, viewportSize, candidate, held)) return intended;
|
|
239
|
-
if (selection !== candidate.key) rowRef.current?.onSnap?.();
|
|
240
236
|
select(candidate.key);
|
|
241
237
|
gesture.intendedX += (candidate.left + candidate.width / 2) * (intended.scale - fit.scale);
|
|
242
238
|
return constrain({
|
|
@@ -254,8 +250,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
254
250
|
markMoving();
|
|
255
251
|
applyCamera(next);
|
|
256
252
|
}
|
|
257
|
-
if (landing?.stretched && landing.key === selection) rowRef.current?.onSnap?.();
|
|
258
|
-
landing = void 0;
|
|
259
253
|
};
|
|
260
254
|
const pointers = /* @__PURE__ */ new Map();
|
|
261
255
|
let spaceHeld = false;
|
|
@@ -317,8 +311,8 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
317
311
|
if (!wasMoving) setMoving(true);
|
|
318
312
|
};
|
|
319
313
|
const paintElement = (element) => {
|
|
320
|
-
element.style.setProperty("--canvas-x", `${camera.x}px`);
|
|
321
|
-
element.style.setProperty("--canvas-y", `${camera.y}px`);
|
|
314
|
+
element.style.setProperty("--canvas-x", `${camera.x + insets.left}px`);
|
|
315
|
+
element.style.setProperty("--canvas-y", `${camera.y + insets.top}px`);
|
|
322
316
|
element.style.setProperty("--canvas-zoom", String(camera.scale));
|
|
323
317
|
element.style.setProperty("--canvas-pixel-ratio", String(ownerWindow.devicePixelRatio));
|
|
324
318
|
};
|
|
@@ -413,7 +407,6 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
413
407
|
gesture = void 0;
|
|
414
408
|
ownerWindow.clearTimeout(zoomEnd);
|
|
415
409
|
stretch = void 0;
|
|
416
|
-
landing = void 0;
|
|
417
410
|
updateGeometry();
|
|
418
411
|
camera = constrain(camera, true);
|
|
419
412
|
target = constrain(destinationCamera());
|
|
@@ -435,7 +428,7 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
435
428
|
const frame = element.ownerDocument.defaultView?.frameElement;
|
|
436
429
|
if (!frame || flight && !flight.pan || pointers.size) return;
|
|
437
430
|
const rect = element.getBoundingClientRect();
|
|
438
|
-
const worldTop = (frame.getBoundingClientRect().top - viewport.getBoundingClientRect().top + rect.top * camera.scale - camera.y) / camera.scale;
|
|
431
|
+
const worldTop = (frame.getBoundingClientRect().top - viewport.getBoundingClientRect().top - insets.top + rect.top * camera.scale - camera.y) / camera.scale;
|
|
439
432
|
const delta = revealScrollDelta({
|
|
440
433
|
top: target.y + worldTop * target.scale,
|
|
441
434
|
bottom: target.y + (worldTop + rect.height) * target.scale
|
|
@@ -483,7 +476,7 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
483
476
|
const held = flight ? void 0 : targetOf(selection);
|
|
484
477
|
const element = held && Array.from(content.querySelectorAll("[data-canvas-page]")).find((element) => element.dataset.canvasPage === held.key);
|
|
485
478
|
const doc = element ? canvasPageIframe(element)?.contentDocument : void 0;
|
|
486
|
-
const anchor = doc && element ? captureViewportAnchor(doc, Math.max(0, (viewport.getBoundingClientRect().top - element.getBoundingClientRect().top) / camera.scale)) : void 0;
|
|
479
|
+
const anchor = doc && element ? captureViewportAnchor(doc, Math.max(0, (viewport.getBoundingClientRect().top + insets.top - element.getBoundingClientRect().top) / camera.scale)) : void 0;
|
|
487
480
|
return {
|
|
488
481
|
camera: { ...camera },
|
|
489
482
|
pathname: element ? element.dataset.canvasPathname : void 0,
|
|
@@ -505,7 +498,7 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
505
498
|
} : fit;
|
|
506
499
|
if (anchor && doc) {
|
|
507
500
|
const y = resolveViewportAnchor(doc, anchor);
|
|
508
|
-
const frameOffsetY = page ? (page.getBoundingClientRect().top - viewport.getBoundingClientRect().top - camera.y) / camera.scale : 0;
|
|
501
|
+
const frameOffsetY = page ? (page.getBoundingClientRect().top - viewport.getBoundingClientRect().top - insets.top - camera.y) / camera.scale : 0;
|
|
509
502
|
next = placeCanvasPageAnchor(viewportSize, destination, y, fit.scale, frameOffsetY);
|
|
510
503
|
}
|
|
511
504
|
fittingInitialPage = false;
|
|
@@ -515,12 +508,10 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
515
508
|
};
|
|
516
509
|
if (continuity) continuity.canvas = continuityBinding;
|
|
517
510
|
const resize = new ResizeObserver(() => {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
height: viewport.clientHeight
|
|
521
|
-
};
|
|
511
|
+
const previousInsets = insets;
|
|
512
|
+
const nextViewport = measureViewport();
|
|
522
513
|
const nextContent = measureContent();
|
|
523
|
-
if (nextViewport.width === viewportSize.width && nextViewport.height === viewportSize.height && nextContent.width === contentSize.width && nextContent.height === contentSize.height) return;
|
|
514
|
+
if (insets.left === previousInsets.left && insets.top === previousInsets.top && nextViewport.width === viewportSize.width && nextViewport.height === viewportSize.height && nextContent.width === contentSize.width && nextContent.height === contentSize.height) return;
|
|
524
515
|
const wasFitted = isOverview(target);
|
|
525
516
|
gesture = void 0;
|
|
526
517
|
const held = nextViewport.width !== viewportSize.width && !flight && !fittingInitialPage ? targetOf(selection) : void 0;
|
|
@@ -559,14 +550,14 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
559
550
|
const localPoint = (x, y) => {
|
|
560
551
|
const rect = viewport.getBoundingClientRect();
|
|
561
552
|
return {
|
|
562
|
-
x: x - rect.left,
|
|
563
|
-
y: y - rect.top
|
|
553
|
+
x: x - rect.left - insets.left,
|
|
554
|
+
y: y - rect.top - insets.top
|
|
564
555
|
};
|
|
565
556
|
};
|
|
566
557
|
const onWheel = (event) => {
|
|
567
558
|
event.preventDefault();
|
|
568
|
-
const dx = canvasWheelDelta(event.deltaX, event.deltaMode,
|
|
569
|
-
const dy = canvasWheelDelta(event.deltaY, event.deltaMode,
|
|
559
|
+
const dx = canvasWheelDelta(event.deltaX, event.deltaMode, viewportSize.width);
|
|
560
|
+
const dy = canvasWheelDelta(event.deltaY, event.deltaMode, viewportSize.height);
|
|
570
561
|
if (!dx && !dy) return;
|
|
571
562
|
rowRef.current?.onEditorMove?.();
|
|
572
563
|
cancelCameraFlight();
|
|
@@ -664,7 +655,13 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
664
655
|
const onFocusIn = (event) => {
|
|
665
656
|
if (!isControl(event.target)) return;
|
|
666
657
|
const rect = event.target.getBoundingClientRect();
|
|
667
|
-
const
|
|
658
|
+
const viewportRect = viewport.getBoundingClientRect();
|
|
659
|
+
const bounds = {
|
|
660
|
+
left: viewportRect.left + insets.left,
|
|
661
|
+
top: viewportRect.top + insets.top,
|
|
662
|
+
right: viewportRect.left + insets.left + viewportSize.width,
|
|
663
|
+
bottom: viewportRect.top + insets.top + viewportSize.height
|
|
664
|
+
};
|
|
668
665
|
const dx = Math.max(0, bounds.left + 16 - rect.left) - Math.max(0, rect.right - bounds.right + 16);
|
|
669
666
|
const dy = Math.max(0, bounds.top + 16 - rect.top) - Math.max(0, rect.bottom - bounds.bottom + 16);
|
|
670
667
|
if (!dx && !dy) return;
|
|
@@ -689,8 +686,8 @@ function useCanvasCamera(workspaceKey, initialTarget, row) {
|
|
|
689
686
|
"ArrowDown"
|
|
690
687
|
].includes(event.key) || event.shiftKey && event.code === "Digit1") cancelCameraFlight();
|
|
691
688
|
const center = {
|
|
692
|
-
x:
|
|
693
|
-
y:
|
|
689
|
+
x: viewportSize.width / 2,
|
|
690
|
+
y: viewportSize.height / 2
|
|
694
691
|
};
|
|
695
692
|
const factor = event.key === "+" || event.key === "=" ? 1.25 : event.key === "-" ? .8 : event.key === "0" ? 1 / target.scale : void 0;
|
|
696
693
|
if (factor) {
|
|
@@ -12,10 +12,10 @@ import { usePageDestinations } from "../../hooks/use-page-destinations.js";
|
|
|
12
12
|
import { useLocalePath, useLocalizedPath } from "../../lib/view-locale.js";
|
|
13
13
|
import { CanvasLoadingScreen } from "../canvas/CanvasLoadingScreen.js";
|
|
14
14
|
import { canvasStore } from "../canvas/canvasStore.js";
|
|
15
|
+
import { previewStore, selectIsCanvasShown } from "./previewStore.js";
|
|
15
16
|
import { SHOW_WHOLE_CANVAS_SHORTCUT, TOGGLE_CANVAS_SHORTCUT } from "./previewConstants.js";
|
|
16
17
|
import { CanvasSidebarSkeleton } from "../canvas/sidebar/CanvasSidebarSkeleton.js";
|
|
17
18
|
import { takeShowCanvasRequest } from "../provider/signInShortcut.js";
|
|
18
|
-
import { previewStore, selectIsCanvasShown } from "./previewStore.js";
|
|
19
19
|
import { PreviewEditingOwnerContext } from "./previewSelection.js";
|
|
20
20
|
import { RendererFramesProvider, RendererSlot, useRendererHost, useRendererStatus } from "../renderer/RendererFrames.js";
|
|
21
21
|
import { STUDIO_CANVAS_PATH } from "../studio/routes.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { actionsStore } from "../../provider/actionsStore.js";
|
|
2
2
|
import { usePageBlocks } from "../../../lib/normalized-data.js";
|
|
3
3
|
import { blockMutations, repeatableItemMutations } from "../../../lib/queries.js";
|
|
4
|
-
import { formatShortcut } from "../../../lib/shortcuts.js";
|
|
5
4
|
import { isBlockSelection, previewStore, selectionForPage, selectionItemId } from "../previewStore.js";
|
|
5
|
+
import { formatShortcut } from "../../../lib/shortcuts.js";
|
|
6
6
|
import { entityName } from "../entityName.js";
|
|
7
7
|
import { useUpdateBlockPosition } from "./useUpdateBlockPosition.js";
|
|
8
8
|
import { usePreviewedPage } from "../CamoxPreview.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
|
-
import { useRendererHost } from "../../renderer/RendererFrames.js";
|
|
3
2
|
import { useEditingFrame } from "../editingFrame.js";
|
|
3
|
+
import { useRendererHost } from "../../renderer/RendererFrames.js";
|
|
4
4
|
import { EMPTY_PREVIEW_DOCUMENT, isSiteStyle } from "./previewStyles.js";
|
|
5
5
|
import { FrameContext } from "./Frame.js";
|
|
6
6
|
import { c } from "react/compiler-runtime";
|
|
@@ -203,7 +203,7 @@ function CanvasPreview({ enabled, pathname, pagePathname, runtimeBasePath, place
|
|
|
203
203
|
className: "relative flex min-h-0 flex-1",
|
|
204
204
|
"data-preview-surface": true,
|
|
205
205
|
children: [
|
|
206
|
-
enabled && phase
|
|
206
|
+
enabled && phase === "preparing" && placeholder,
|
|
207
207
|
/* @__PURE__ */ jsxs("div", {
|
|
208
208
|
className: "relative flex min-h-0 min-w-0 flex-1 flex-col",
|
|
209
209
|
"data-read-only-preview": true,
|
|
@@ -4,9 +4,9 @@ import { reads, useReadQuery } from "../../../lib/studio-reads.js";
|
|
|
4
4
|
import { pageMutations } from "../../../lib/queries.js";
|
|
5
5
|
import { useLayoutDefinitions } from "../../../lib/studio-definitions.js";
|
|
6
6
|
import { useLocalizedPath } from "../../../lib/view-locale.js";
|
|
7
|
-
import { PageNicknameField } from "./PageNicknameField.js";
|
|
8
7
|
import { previewStore } from "../previewStore.js";
|
|
9
8
|
import { PageLocationFieldset } from "./PageLocationFieldset.js";
|
|
9
|
+
import { PageNicknameField } from "./PageNicknameField.js";
|
|
10
10
|
import { c } from "react/compiler-runtime";
|
|
11
11
|
import { useEffect } from "react";
|
|
12
12
|
import { useSelector } from "@xstate/store-react";
|
|
@@ -5,8 +5,8 @@ import { DrillRow } from "./DrillRow.js";
|
|
|
5
5
|
import { ReferenceFieldEditor } from "./ReferenceFieldEditor.js";
|
|
6
6
|
import { ReferenceListFieldEditor } from "./ReferenceListFieldEditor.js";
|
|
7
7
|
import { previewStore } from "../previewStore.js";
|
|
8
|
-
import { PreviewEditingOwnerContext } from "../previewSelection.js";
|
|
9
8
|
import { overlayFieldId, recordPlacementId } from "../overlayMessages.js";
|
|
9
|
+
import { PreviewEditingOwnerContext } from "../previewSelection.js";
|
|
10
10
|
import { SidebarLexicalEditor } from "../../../core/components/lexical/SidebarLexicalEditor.js";
|
|
11
11
|
import { IconFieldEditor } from "./IconFieldEditor.js";
|
|
12
12
|
import { RepeatableItemsList } from "./RepeatableItemsList.js";
|