summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-drag-clip.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-07-06 20:45:29 +0200
committerMaze Winther <mazewinther@gmail.com>2025-07-06 20:45:29 +0200
commit40c7fbb4f86130c83fbd9029e83c5e7550e3219d (patch)
tree054d918d282358c084f4fc08462913833de644a5 /apps/web/src/hooks/use-drag-clip.ts
parent0e32c732ddc335d35e6a7f8547f4af68bfd9c369 (diff)
downloadopencut-40c7fbb4f86130c83fbd9029e83c5e7550e3219d.tar.gz
refactor: move to a typed-tracks system and add support for text
Diffstat (limited to 'apps/web/src/hooks/use-drag-clip.ts')
-rw-r--r--apps/web/src/hooks/use-drag-clip.ts89
1 files changed, 50 insertions, 39 deletions
diff --git a/apps/web/src/hooks/use-drag-clip.ts b/apps/web/src/hooks/use-drag-clip.ts
index eb4d7435..1d38343b 100644
--- a/apps/web/src/hooks/use-drag-clip.ts
+++ b/apps/web/src/hooks/use-drag-clip.ts
@@ -3,23 +3,24 @@ import { useTimelineStore } from "@/stores/timeline-store";
interface DragState {
isDragging: boolean;
- clipId: string | null;
+ elementId: string | null;
trackId: string | null;
startMouseX: number;
- startClipTime: number;
+ startElementTime: number;
clickOffsetTime: number;
currentTime: number;
}
export function useDragClip(zoomLevel: number) {
- const { tracks, updateClipStartTime, moveClipToTrack } = useTimelineStore();
+ const { tracks, updateElementStartTime, moveElementToTrack } =
+ useTimelineStore();
const [dragState, setDragState] = useState<DragState>({
isDragging: false,
- clipId: null,
+ elementId: null,
trackId: null,
startMouseX: 0,
- startClipTime: 0,
+ startElementTime: 0,
clickOffsetTime: 0,
currentTime: 0,
});
@@ -33,9 +34,9 @@ export function useDragClip(zoomLevel: number) {
const startDrag = useCallback(
(
e: React.MouseEvent,
- clipId: string,
+ elementId: string,
trackId: string,
- clipStartTime: number,
+ elementStartTime: number,
clickOffsetTime: number
) => {
e.preventDefault();
@@ -43,12 +44,12 @@ export function useDragClip(zoomLevel: number) {
setDragState({
isDragging: true,
- clipId,
+ elementId,
trackId,
startMouseX: e.clientX,
- startClipTime: clipStartTime,
+ startElementTime: elementStartTime,
clickOffsetTime,
- currentTime: clipStartTime,
+ currentTime: elementStartTime,
});
},
[]
@@ -76,7 +77,7 @@ export function useDragClip(zoomLevel: number) {
const endDrag = useCallback(
(targetTrackId?: string) => {
- if (!dragState.isDragging || !dragState.clipId || !dragState.trackId)
+ if (!dragState.isDragging || !dragState.elementId || !dragState.trackId)
return;
const finalTrackId = targetTrackId || dragState.trackId;
@@ -85,71 +86,81 @@ export function useDragClip(zoomLevel: number) {
// Check for overlaps
const sourceTrack = tracks.find((t) => t.id === dragState.trackId);
const targetTrack = tracks.find((t) => t.id === finalTrackId);
- const movingClip = sourceTrack?.clips.find(
- (c) => c.id === dragState.clipId
+ const movingElement = sourceTrack?.elements.find(
+ (e) => e.id === dragState.elementId
);
- if (!movingClip || !targetTrack) {
+ if (!movingElement || !targetTrack) {
setDragState((prev) => ({ ...prev, isDragging: false }));
return;
}
- const movingClipDuration =
- movingClip.duration - movingClip.trimStart - movingClip.trimEnd;
- const movingClipEnd = finalTime + movingClipDuration;
+ const movingElementDuration =
+ movingElement.duration -
+ movingElement.trimStart -
+ movingElement.trimEnd;
+ const movingElementEnd = finalTime + movingElementDuration;
- const hasOverlap = targetTrack.clips.some((existingClip) => {
- // Skip the clip being moved if it's on the same track
+ const hasOverlap = targetTrack.elements.some((existingElement) => {
+ // Skip the element being moved if it's on the same track
if (
dragState.trackId === finalTrackId &&
- existingClip.id === dragState.clipId
+ existingElement.id === dragState.elementId
) {
return false;
}
- const existingStart = existingClip.startTime;
+ const existingStart = existingElement.startTime;
const existingEnd =
- existingClip.startTime +
- (existingClip.duration -
- existingClip.trimStart -
- existingClip.trimEnd);
+ existingElement.startTime +
+ (existingElement.duration -
+ existingElement.trimStart -
+ existingElement.trimEnd);
- return finalTime < existingEnd && movingClipEnd > existingStart;
+ return finalTime < existingEnd && movingElementEnd > existingStart;
});
if (!hasOverlap) {
if (dragState.trackId === finalTrackId) {
// Moving within same track
- updateClipStartTime(finalTrackId, dragState.clipId!, finalTime);
+ updateElementStartTime(finalTrackId, dragState.elementId!, finalTime);
} else {
// Moving to different track
- moveClipToTrack(dragState.trackId!, finalTrackId, dragState.clipId!);
+ moveElementToTrack(
+ dragState.trackId!,
+ finalTrackId,
+ dragState.elementId!
+ );
requestAnimationFrame(() => {
- updateClipStartTime(finalTrackId, dragState.clipId!, finalTime);
+ updateElementStartTime(
+ finalTrackId,
+ dragState.elementId!,
+ finalTime
+ );
});
}
}
setDragState({
isDragging: false,
- clipId: null,
+ elementId: null,
trackId: null,
startMouseX: 0,
- startClipTime: 0,
+ startElementTime: 0,
clickOffsetTime: 0,
currentTime: 0,
});
},
- [dragState, tracks, updateClipStartTime, moveClipToTrack]
+ [dragState, tracks, updateElementStartTime, moveElementToTrack]
);
const cancelDrag = useCallback(() => {
setDragState({
isDragging: false,
- clipId: null,
+ elementId: null,
trackId: null,
startMouseX: 0,
- startClipTime: 0,
+ startElementTime: 0,
clickOffsetTime: 0,
currentTime: 0,
});
@@ -176,12 +187,12 @@ export function useDragClip(zoomLevel: number) {
};
}, [dragState.isDragging, updateDrag, endDrag, cancelDrag]);
- const getDraggedClipPosition = useCallback(
- (clipId: string) => {
+ const getDraggedElementPosition = useCallback(
+ (elementId: string) => {
// Use ref to get current state, not stale closure
const currentDragState = dragStateRef.current;
const isMatch =
- currentDragState.isDragging && currentDragState.clipId === clipId;
+ currentDragState.isDragging && currentDragState.elementId === elementId;
if (isMatch) {
return currentDragState.currentTime;
@@ -209,7 +220,7 @@ export function useDragClip(zoomLevel: number) {
return {
// State
isDragging: dragState.isDragging,
- draggedClipId: dragState.clipId,
+ draggedElementId: dragState.elementId,
currentDragTime: dragState.currentTime,
clickOffsetTime: dragState.clickOffsetTime,
@@ -217,7 +228,7 @@ export function useDragClip(zoomLevel: number) {
startDrag,
endDrag,
cancelDrag,
- getDraggedClipPosition,
+ getDraggedElementPosition,
isValidDropTarget,
// Refs