{
@@ -38,8 +41,9 @@ function mountProbe() {
}
const host = document.createElement("div");
document.body.append(host);
- act(() => createRoot(host).render(
));
- return () => rect;
+ const root = createRoot(host);
+ act(() => root.render(
));
+ return { read: () => rect, setIframe, unmount: () => act(() => root.unmount()) };
}
function compositionFrame(box: [number, number, number, number], width: number, height: number) {
@@ -57,13 +61,13 @@ const settle = () => new Promise((r) => setTimeout(r, 400));
describe("usePreviewCompositionRect", () => {
it("reports the live preview iframe's box relative to the overlay, scaled to the composition", async () => {
- const read = mountProbe();
+ const probe = mountProbe();
const iframe = compositionFrame([110, 70, 960, 540], 1920, 1080);
await act(async () => {
- usePreviewIframeStore.getState().setIframe(iframe);
+ probe.setIframe(iframe);
await settle();
});
- expect(read()).toEqual({
+ expect(probe.read()).toEqual({
left: 100,
top: 50,
width: 960,
@@ -71,19 +75,20 @@ describe("usePreviewCompositionRect", () => {
scaleX: 0.5,
scaleY: 0.5,
});
+ probe.unmount();
});
it("follows the iframe when a reload replaces it", async () => {
- const read = mountProbe();
+ const probe = mountProbe();
await act(async () => {
- usePreviewIframeStore.getState().setIframe(compositionFrame([110, 70, 960, 540], 1920, 1080));
+ probe.setIframe(compositionFrame([110, 70, 960, 540], 1920, 1080));
await settle();
});
await act(async () => {
- usePreviewIframeStore.getState().setIframe(compositionFrame([60, 40, 500, 500], 1000, 1000));
+ probe.setIframe(compositionFrame([60, 40, 500, 500], 1000, 1000));
await settle();
});
- expect(read()).toEqual({
+ expect(probe.read()).toEqual({
left: 50,
top: 20,
width: 500,
@@ -91,5 +96,6 @@ describe("usePreviewCompositionRect", () => {
scaleX: 0.5,
scaleY: 0.5,
});
+ probe.unmount();
});
});
diff --git a/packages/studio/src/components/editor/usePreviewCompositionRect.ts b/packages/studio/src/components/editor/usePreviewCompositionRect.ts
index 16a9b9bf67..89122a5371 100644
--- a/packages/studio/src/components/editor/usePreviewCompositionRect.ts
+++ b/packages/studio/src/components/editor/usePreviewCompositionRect.ts
@@ -1,21 +1,21 @@
-import { useMemo, type RefObject } from "react";
-import { usePreviewIframeStore } from "../../player/store/previewIframeStore";
+import { useEffect, useRef, type RefObject } from "react";
+import { requestOverlayFrames } from "./overlayFrameLoop";
import { useDomEditCompositionRect } from "./useDomEditCompositionRect";
export type { DomEditCompositionRect as PreviewCompositionRect } from "./useDomEditCompositionRect";
/**
* Where the composition sits inside `overlayRef`, in overlay pixels, plus the scale from
- * composition units to pixels. Follows the live preview iframe across reloads.
+ * composition units to pixels.
*/
-export function usePreviewCompositionRect(overlayRef: RefObject
) {
- const iframeRef = useMemo>(
- () => ({
- get current() {
- return usePreviewIframeStore.getState().iframe;
- },
- }),
- [],
- );
+export function usePreviewCompositionRect(
+ overlayRef: RefObject,
+ iframe: HTMLIFrameElement | null,
+) {
+ const iframeRef = useRef(iframe);
+ iframeRef.current = iframe;
+ useEffect(() => {
+ requestOverlayFrames();
+ }, [iframe]);
return useDomEditCompositionRect({ iframeRef, overlayRef });
}
diff --git a/packages/studio/src/components/nle/PreviewOverlays.tsx b/packages/studio/src/components/nle/PreviewOverlays.tsx
index 293481c9b3..3a94ec227b 100644
--- a/packages/studio/src/components/nle/PreviewOverlays.tsx
+++ b/packages/studio/src/components/nle/PreviewOverlays.tsx
@@ -1,10 +1,11 @@
-import { useCallback, useState } from "react";
+import { useCallback } from "react";
import { CaptionOverlay } from "../../captions/components/CaptionOverlay";
import { useCaptionStore } from "../../captions/store";
import { DomEditOverlay } from "../editor/DomEditOverlay";
import { TopologyLens } from "../editor/TopologyLens";
import { MotionPathOverlay } from "../editor/MotionPathOverlay";
import { SnapToolbar } from "../editor/SnapToolbar";
+import { GridOverlay } from "../editor/GridOverlay";
import { usePreviewReadOnly } from "../editor/previewReadOnlyContext";
import { useCompositionDimensions } from "../../hooks/useCompositionDimensions";
import { useStudioPlaybackContext, useStudioShellContext } from "../../contexts/StudioContext";
@@ -12,7 +13,6 @@ import {
useDomEditActionsContext,
useDomEditSelectionContext,
} from "../../contexts/DomEditContext";
-import { readStudioUiPreferences } from "../../utils/studioUiPreferences";
import { readHfId, type DomEditSelection } from "../editor/domEditing";
import { buildStableSelector } from "../editor/domEditingDom";
import { deriveTimelineStoreKey } from "../../player/lib/timelineElementHelpers";
@@ -182,17 +182,6 @@ export function PreviewOverlays({
} = useDomEditActionsContext();
const mirrorZOrderToTimeline = useCanvasZOrderTimelineMirror();
- // fallow-ignore-next-line complexity
- const [snapPrefs, setSnapPrefs] = useState(() => {
- const p = readStudioUiPreferences();
- return {
- snapEnabled: p.snapEnabled ?? true,
- gridVisible: p.gridVisible ?? false,
- gridSpacing: p.gridSpacing ?? 50,
- snapToGrid: p.snapToGrid ?? false,
- };
- });
-
if (blockPreview) {
return (
<>
@@ -266,6 +255,7 @@ export function PreviewOverlays({
return (
<>
+
undefined);
}}
- gridVisible={snapPrefs.gridVisible}
- gridSpacing={snapPrefs.gridSpacing}
recordingState={recordingState}
onToggleRecording={onToggleRecording}
onMarqueeSelect={applyMarqueeSelection}
/>
-
+
{!readOnly && (
void) {
document.addEventListener("fullscreenchange", cb);
@@ -155,8 +156,10 @@ export function PreviewPane({
)}
-