summaryrefslogtreecommitdiff
path: root/apps/web/src/preview/components
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/preview/components')
-rw-r--r--apps/web/src/preview/components/context-menu.tsx6
-rw-r--r--apps/web/src/preview/components/index.tsx26
-rw-r--r--apps/web/src/preview/components/preview-viewport.tsx16
-rw-r--r--apps/web/src/preview/components/text-edit-overlay.tsx1
4 files changed, 25 insertions, 24 deletions
diff --git a/apps/web/src/preview/components/context-menu.tsx b/apps/web/src/preview/components/context-menu.tsx
index fca55d71..a0f1bc5c 100644
--- a/apps/web/src/preview/components/context-menu.tsx
+++ b/apps/web/src/preview/components/context-menu.tsx
@@ -13,12 +13,12 @@ import { toast } from "sonner";
export function PreviewContextMenu({
onToggleFullscreen,
- containerRef,
+ container,
overlayControls,
onOverlayVisibilityChange,
}: {
onToggleFullscreen: () => void;
- containerRef: React.RefObject<HTMLElement | null>;
+ container: HTMLElement | null;
overlayControls: PreviewOverlayControl[];
onOverlayVisibilityChange: (params: {
overlayId: string;
@@ -51,7 +51,7 @@ export function PreviewContextMenu({
};
return (
- <ContextMenuContent className="w-56" container={containerRef.current}>
+ <ContextMenuContent className="w-56" container={container}>
<ContextMenuItem onClick={viewport.fitToScreen} inset>
Fit to screen
</ContextMenuItem>
diff --git a/apps/web/src/preview/components/index.tsx b/apps/web/src/preview/components/index.tsx
index e8f5c572..894eec78 100644
--- a/apps/web/src/preview/components/index.tsx
+++ b/apps/web/src/preview/components/index.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useCallback, useEffect, useMemo, useRef } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import useDeepCompareEffect from "use-deep-compare-effect";
import { useEditor } from "@/editor/use-editor";
import { useRafLoop } from "@/hooks/use-raf-loop";
@@ -68,15 +68,20 @@ export function PreviewPanel({
}) => void;
}) {
const containerRef = useRef<HTMLDivElement>(null);
+ const [container, setContainer] = useState<HTMLDivElement | null>(null);
const { toggleFullscreen } = useFullscreen({ containerRef });
+ const handleContainerRef = useCallback((node: HTMLDivElement | null) => {
+ containerRef.current = node;
+ setContainer(node);
+ }, []);
return (
<div
- ref={containerRef}
+ ref={handleContainerRef}
className="panel bg-background relative flex size-full min-h-0 min-w-0 flex-col rounded-sm border"
>
<PreviewCanvas
- containerRef={containerRef}
+ container={container}
onToggleFullscreen={toggleFullscreen}
overlayControls={overlayControls}
overlayInstances={overlayInstances}
@@ -117,13 +122,13 @@ function RenderTreeController() {
}
function PreviewCanvas({
- containerRef,
+ container,
onToggleFullscreen,
overlayControls,
overlayInstances,
onOverlayVisibilityChange,
}: {
- containerRef: React.RefObject<HTMLElement | null>;
+ container: HTMLElement | null;
onToggleFullscreen: () => void;
overlayControls: PreviewOverlayControl[];
overlayInstances: PreviewOverlayInstance[];
@@ -149,6 +154,7 @@ function PreviewCanvas({
viewportRef,
viewportWidth: viewportSize.width,
});
+ const { canPan, panByScreenDelta, scaleZoom } = viewport;
const renderer = useMemo(() => {
return new CanvasRenderer({
@@ -240,7 +246,7 @@ function PreviewCanvas({
Math.min(Math.abs(pendingZoomDelta), 30);
const zoomFactor = Math.exp(-cappedDelta / 300);
- viewport.scaleZoom({ factor: zoomFactor });
+ scaleZoom({ factor: zoomFactor });
pendingZoomDelta = 0;
zoomRafId = null;
});
@@ -249,7 +255,7 @@ function PreviewCanvas({
return;
}
- if (!viewport.canPan) {
+ if (!canPan) {
return;
}
@@ -263,7 +269,7 @@ function PreviewCanvas({
if (panRafId === null) {
panRafId = requestAnimationFrame(() => {
- viewport.panByScreenDelta({
+ panByScreenDelta({
deltaX: pendingPanDeltaX,
deltaY: pendingPanDeltaY,
});
@@ -290,7 +296,7 @@ function PreviewCanvas({
cancelAnimationFrame(panRafId);
}
};
- }, [viewport.canPan, viewport.panByScreenDelta, viewport.scaleZoom]);
+ }, [canPan, panByScreenDelta, scaleZoom]);
return (
<PreviewViewportProvider value={viewport}>
@@ -329,7 +335,7 @@ function PreviewCanvas({
</ContextMenuTrigger>
<PreviewContextMenu
onToggleFullscreen={onToggleFullscreen}
- containerRef={containerRef}
+ container={container}
overlayControls={overlayControls}
onOverlayVisibilityChange={onOverlayVisibilityChange}
/>
diff --git a/apps/web/src/preview/components/preview-viewport.tsx b/apps/web/src/preview/components/preview-viewport.tsx
index 6dc9f084..be261adc 100644
--- a/apps/web/src/preview/components/preview-viewport.tsx
+++ b/apps/web/src/preview/components/preview-viewport.tsx
@@ -9,6 +9,7 @@ import {
useRef,
useState,
} from "react";
+import { useCommittedRef } from "@/hooks/use-committed-ref";
import {
canvasToOverlay,
getDisplayScale,
@@ -219,8 +220,7 @@ export function usePreviewViewportState({
}));
const [isPanning, setIsPanning] = useState(false);
const panSessionRef = useRef<PanSession | null>(null);
- const centerRef = useRef(center);
- centerRef.current = center;
+ const centerRef = useCommittedRef(center);
const fitScale = useMemo(
() =>
@@ -409,10 +409,10 @@ export function usePreviewViewportState({
pointerId: event.pointerId,
};
setIsPanning(true);
- (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);
+ event.currentTarget.setPointerCapture(event.pointerId);
return true;
},
- [zoom],
+ [centerRef, zoom],
);
const handlePanPointerMove = useCallback(
@@ -451,13 +451,9 @@ export function usePreviewViewportState({
}
if (
- (event.currentTarget as HTMLElement).hasPointerCapture(
- panSession.pointerId,
- )
+ event.currentTarget.hasPointerCapture(panSession.pointerId)
) {
- (event.currentTarget as HTMLElement).releasePointerCapture(
- panSession.pointerId,
- );
+ event.currentTarget.releasePointerCapture(panSession.pointerId);
}
panSessionRef.current = null;
diff --git a/apps/web/src/preview/components/text-edit-overlay.tsx b/apps/web/src/preview/components/text-edit-overlay.tsx
index 1d599b3b..dd6364d6 100644
--- a/apps/web/src/preview/components/text-edit-overlay.tsx
+++ b/apps/web/src/preview/components/text-edit-overlay.tsx
@@ -120,7 +120,6 @@ export function TextEditOverlay({
transformOrigin: "center center",
}}
>
- {/* biome-ignore lint/a11y/useSemanticElements: contenteditable required for multiline, IME, paste */}
<div
ref={divRef}
contentEditable