diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-25 16:47:22 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:48:22 +0200 |
| commit | 8db3bead13441a5882d8689dfc6a9f09c82375d9 (patch) | |
| tree | e9d0cafa93904ffcbec3188c37961bcc16c6422d /apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx | |
| parent | 39ea298a9ccba3104c549c0ca079c231981811f5 (diff) | |
| download | opencut-8db3bead13441a5882d8689dfc6a9f09c82375d9.tar.gz | |
feat: masks, properties refactor, shaders, storage migrations, and more
Diffstat (limited to 'apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx')
| -rw-r--r-- | apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx | 109 |
1 files changed, 86 insertions, 23 deletions
diff --git a/apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx b/apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx index 4c33a1a1..65c11726 100644 --- a/apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx +++ b/apps/web/src/components/editor/panels/preview/preview-interaction-overlay.tsx @@ -1,54 +1,117 @@ +import { useState } from "react"; +import { usePreviewViewport } from "@/components/editor/panels/preview/preview-viewport"; import { usePreviewInteraction } from "@/hooks/use-preview-interaction"; +import type { SnapLine } from "@/lib/preview/preview-snap"; import { TransformHandles } from "./transform-handles"; +import { MaskHandles } from "./mask-handles"; import { SnapGuides } from "./snap-guides"; import { TextEditOverlay } from "./text-edit-overlay"; +import { usePropertiesStore } from "../properties/stores/properties-store"; +import { useEditor } from "@/hooks/use-editor"; + +export function PreviewInteractionOverlay() { + const [snapLines, setSnapLines] = useState<SnapLine[]>([]); + const editor = useEditor(); + const viewport = usePreviewViewport(); + const selectedElements = useEditor((e) => e.selection.getSelectedElements()); + const activeTabPerType = usePropertiesStore((s) => s.activeTabPerType); + + const selectedRef = + selectedElements.length === 1 ? selectedElements[0] : null; + const activeTrack = selectedRef + ? editor.timeline.getTrackById({ trackId: selectedRef.trackId }) + : null; + const activeElement = + activeTrack?.elements.find( + (element) => element.id === selectedRef?.elementId, + ) ?? null; + const isMaskMode = activeElement + ? activeTabPerType[activeElement.type] === "masks" + : false; -export function PreviewInteractionOverlay({ - canvasRef, - containerRef, -}: { - canvasRef: React.RefObject<HTMLCanvasElement | null>; - containerRef: React.RefObject<HTMLDivElement | null>; -}) { const { onPointerDown, onPointerMove, onPointerUp, onDoubleClick, - snapLines, editingText, commitTextEdit, - cancelTextEdit, - } = usePreviewInteraction({ canvasRef }); + } = usePreviewInteraction({ + onSnapLinesChange: setSnapLines, + isMaskMode, + }); + + const handlePointerDown = (event: React.PointerEvent) => { + if (viewport.handlePanPointerDown({ event })) { + return; + } + + onPointerDown(event); + }; + + const handlePointerMove = (event: React.PointerEvent) => { + if (viewport.handlePanPointerMove({ event })) { + return; + } + + onPointerMove(event); + }; + + const handlePointerUp = (event: React.PointerEvent) => { + if (viewport.handlePanPointerUp({ event })) { + return; + } + + onPointerUp(event); + }; + + const handleContextMenu = (e: React.MouseEvent) => { + const x = e.nativeEvent.offsetX; + const y = e.nativeEvent.offsetY; + const outsideCanvas = + x < viewport.sceneLeft || + x > viewport.sceneLeft + viewport.sceneWidth || + y < viewport.sceneTop || + y > viewport.sceneTop + viewport.sceneHeight; + if (outsideCanvas) { + e.stopPropagation(); + } + }; return ( <div className="absolute inset-0"> - {/* biome-ignore lint/a11y/noStaticElementInteractions: canvas overlay, pointer-only interaction */} <div className="absolute inset-0 pointer-events-auto" - onPointerDown={onPointerDown} - onPointerMove={onPointerMove} - onPointerUp={onPointerUp} + role="application" + aria-label="Preview canvas" + style={{ + cursor: viewport.isPanning + ? "grabbing" + : viewport.canPan + ? "default" + : undefined, + }} + onPointerDown={handlePointerDown} + onPointerMove={handlePointerMove} + onPointerUp={handlePointerUp} + onPointerCancel={handlePointerUp} onDoubleClick={onDoubleClick} + onDragStart={(e) => e.preventDefault()} + onContextMenu={handleContextMenu} /> {editingText ? ( <TextEditOverlay - canvasRef={canvasRef} - containerRef={containerRef} trackId={editingText.trackId} elementId={editingText.elementId} element={editingText.element} onCommit={commitTextEdit} - onCancel={cancelTextEdit} /> + ) : isMaskMode ? ( + <MaskHandles onSnapLinesChange={setSnapLines} /> ) : ( - <TransformHandles canvasRef={canvasRef} containerRef={containerRef} /> + <TransformHandles onSnapLinesChange={setSnapLines} /> )} - <SnapGuides - lines={snapLines} - canvasRef={canvasRef} - containerRef={containerRef} - /> + <SnapGuides lines={snapLines} /> </div> ); } |
