mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
fix(studio): lift block drop handling above DomEditOverlay
The DomEditOverlay sits at z-10 with pointer-events:auto over the preview, intercepting all drag events before they reach NLEPreview's viewport. Move block drop handling from NLEPreview up to the wrapper div in NLELayout that contains both the preview and the overlay, so drag-and-drop from the Catalog panel onto the preview area works regardless of inspector state.
This commit is contained in:
@@ -13,6 +13,7 @@ import type { TimelineElement } from "../../player";
|
||||
import type { BlockedTimelineEditIntent } from "../../player/components/timelineEditing";
|
||||
import { NLEPreview } from "./NLEPreview";
|
||||
import { CompositionBreadcrumb } from "./CompositionBreadcrumb";
|
||||
import { usePreviewBlockDrop } from "./usePreviewBlockDrop";
|
||||
import { useCompositionStack } from "./useCompositionStack";
|
||||
import {
|
||||
TIMELINE_TOGGLE_SHORTCUT_LABEL,
|
||||
@@ -136,6 +137,22 @@ export const NLELayout = memo(function NLELayout({
|
||||
usePlayerStore.getState().reset();
|
||||
}
|
||||
|
||||
const stageRefForDrop = useRef<HTMLDivElement | null>(null);
|
||||
const handleStageRef = useCallback((ref: React.RefObject<HTMLDivElement | null>) => {
|
||||
stageRefForDrop.current = ref.current;
|
||||
}, []);
|
||||
|
||||
const {
|
||||
isDragOver: previewDragOver,
|
||||
handleDragOver: handlePreviewDragOver,
|
||||
handleDragLeave: handlePreviewDragLeave,
|
||||
handleDrop: handlePreviewDrop,
|
||||
} = usePreviewBlockDrop({
|
||||
portrait,
|
||||
stageRef: stageRefForDrop as React.RefObject<HTMLDivElement | null>,
|
||||
onBlockDrop: onPreviewBlockDrop,
|
||||
});
|
||||
|
||||
// Lightweight reload: change iframe src instead of destroying the Player.
|
||||
// refreshPlayer() saves the seek position and appends a cache-busting _t
|
||||
// param — the Player instance stays alive so the adapter is available for
|
||||
@@ -349,7 +366,13 @@ export const NLELayout = memo(function NLELayout({
|
||||
>
|
||||
{/* Preview + player controls */}
|
||||
<div className="flex-1 min-h-0 flex flex-col">
|
||||
<div className="flex-1 min-h-0 relative" data-preview-pan-surface="true">
|
||||
<div
|
||||
className="flex-1 min-h-0 relative"
|
||||
data-preview-pan-surface="true"
|
||||
onDragOver={handlePreviewDragOver}
|
||||
onDragLeave={handlePreviewDragLeave}
|
||||
onDrop={handlePreviewDrop}
|
||||
>
|
||||
<NLEPreview
|
||||
projectId={projectId}
|
||||
iframeRef={iframeRef}
|
||||
@@ -358,8 +381,11 @@ export const NLELayout = memo(function NLELayout({
|
||||
portrait={portrait}
|
||||
directUrl={directUrl}
|
||||
suppressLoadingOverlay={hasLoadedOnceRef.current}
|
||||
onBlockDrop={onPreviewBlockDrop}
|
||||
onStageRef={handleStageRef}
|
||||
/>
|
||||
{previewDragOver && (
|
||||
<div className="absolute inset-2 z-40 rounded-lg border-2 border-dashed border-studio-accent/50 bg-studio-accent/[0.04] pointer-events-none" />
|
||||
)}
|
||||
{!isFullscreen && previewOverlay}
|
||||
</div>
|
||||
<div className="bg-neutral-950 border-t border-neutral-800/50 flex-shrink-0">
|
||||
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
type PreviewZoomState,
|
||||
} from "./previewZoom";
|
||||
import { readStudioUiPreferences, writeStudioUiPreferences } from "../../utils/studioUiPreferences";
|
||||
import { usePreviewBlockDrop } from "./usePreviewBlockDrop";
|
||||
|
||||
interface NLEPreviewProps {
|
||||
projectId: string;
|
||||
iframeRef: Ref<HTMLIFrameElement>;
|
||||
@@ -22,7 +20,7 @@ interface NLEPreviewProps {
|
||||
portrait?: boolean;
|
||||
directUrl?: string;
|
||||
suppressLoadingOverlay?: boolean;
|
||||
onBlockDrop?: (blockName: string, position: { left: number; top: number }) => void;
|
||||
onStageRef?: (ref: React.RefObject<HTMLDivElement | null>) => void;
|
||||
}
|
||||
|
||||
export function getPreviewPlayerKey({
|
||||
@@ -92,11 +90,14 @@ export const NLEPreview = memo(function NLEPreview({
|
||||
portrait,
|
||||
directUrl,
|
||||
suppressLoadingOverlay,
|
||||
onBlockDrop,
|
||||
onStageRef,
|
||||
}: NLEPreviewProps) {
|
||||
const activeKey = getPreviewPlayerKey({ projectId, directUrl });
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
const stageRef = useRef<HTMLDivElement>(null);
|
||||
useEffect(() => {
|
||||
onStageRef?.(stageRef);
|
||||
}, [onStageRef]);
|
||||
const [stageSize, setStageSize] = useState(() => resolvePreviewStageSize(0, 0, portrait));
|
||||
|
||||
const zoomRef = useRef<PreviewZoomState>(loadInitialZoom());
|
||||
@@ -367,13 +368,6 @@ export const NLEPreview = memo(function NLEPreview({
|
||||
};
|
||||
}, [applyPan]);
|
||||
|
||||
const {
|
||||
isDragOver: previewDragOver,
|
||||
handleDragOver: handlePreviewDragOver,
|
||||
handleDragLeave: handlePreviewDragLeave,
|
||||
handleDrop: handlePreviewDrop,
|
||||
} = usePreviewBlockDrop({ portrait, stageRef, onBlockDrop });
|
||||
|
||||
const initial = zoomRef.current;
|
||||
|
||||
return (
|
||||
@@ -383,9 +377,6 @@ export const NLEPreview = memo(function NLEPreview({
|
||||
className="relative flex-1 flex items-center justify-center p-2 overflow-hidden min-h-0 outline-none focus:ring-1 focus:ring-studio-accent/40 bg-neutral-700"
|
||||
tabIndex={0}
|
||||
aria-label="Composition preview"
|
||||
onDragOver={handlePreviewDragOver}
|
||||
onDragLeave={handlePreviewDragLeave}
|
||||
onDrop={handlePreviewDrop}
|
||||
>
|
||||
<div className="absolute inset-2 flex items-center justify-center pointer-events-none">
|
||||
<div
|
||||
@@ -415,9 +406,6 @@ export const NLEPreview = memo(function NLEPreview({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{previewDragOver && (
|
||||
<div className="absolute inset-2 z-40 rounded-lg border-2 border-dashed border-studio-accent/50 bg-studio-accent/[0.04] pointer-events-none" />
|
||||
)}
|
||||
<div
|
||||
ref={hudRef}
|
||||
className="pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 z-50 rounded-lg px-4 py-2 text-sm font-mono tabular-nums text-white/90 bg-black/60 backdrop-blur-sm shadow-lg"
|
||||
|
||||
Reference in New Issue
Block a user