diff options
Diffstat (limited to 'apps/web/src/hooks/timeline/element/use-element-interaction.ts')
| -rw-r--r-- | apps/web/src/hooks/timeline/element/use-element-interaction.ts | 83 |
1 files changed, 49 insertions, 34 deletions
diff --git a/apps/web/src/hooks/timeline/element/use-element-interaction.ts b/apps/web/src/hooks/timeline/element/use-element-interaction.ts index ea01c718..fae8c527 100644 --- a/apps/web/src/hooks/timeline/element/use-element-interaction.ts +++ b/apps/web/src/hooks/timeline/element/use-element-interaction.ts @@ -18,16 +18,14 @@ import { snapTimeToFrame } from "@/lib/time"; import { computeDropTarget } from "@/lib/timeline/drop-utils"; import { getMouseTimeFromClientX } from "@/lib/timeline/drag-utils"; import { generateUUID } from "@/utils/id"; -import { - snapElementEdge, - type SnapPoint, -} from "@/lib/timeline/snap-utils"; +import { snapElementEdge, type SnapPoint } from "@/lib/timeline/snap-utils"; +import { registerCanceller } from "@/lib/cancel-interaction"; import type { DropTarget, ElementDragState, TimelineElement, TimelineTrack, -} from "@/types/timeline"; +} from "@/lib/timeline"; interface UseElementInteractionProps { zoomLevel: number; @@ -213,6 +211,20 @@ export function useElementInteraction({ setDragDropTarget(null); }, []); + const cancelCurrentDrag = useCallback(() => { + pendingDragRef.current = null; + mouseDownLocationRef.current = null; + setIsPendingDrag(false); + endDrag(); + onSnapPointChange?.(null); + }, [endDrag, onSnapPointChange]); + + useEffect(() => { + if (!dragState.isDragging && !isPendingDrag) return; + + return registerCanceller({ fn: cancelCurrentDrag }); + }, [dragState.isDragging, isPendingDrag, cancelCurrentDrag]); + const getDragSnapResult = useCallback( ({ frameSnappedTime, @@ -445,33 +457,36 @@ export function useElementInteraction({ return; } - if (dropTarget.isNewTrack) { - const newTrackId = generateUUID(); + if (dropTarget.isNewTrack) { + const newTrackId = generateUUID(); - editor.timeline.moveElement({ - sourceTrackId: dragState.trackId, - targetTrackId: newTrackId, - elementId: dragState.elementId, - newStartTime: snappedTime, - createTrack: { type: sourceTrack.type, index: dropTarget.trackIndex }, - rippleEnabled: rippleEditingEnabled, - }); - selectElement({ trackId: newTrackId, elementId: dragState.elementId }); - } else { - const targetTrack = tracks[dropTarget.trackIndex]; - if (targetTrack) { editor.timeline.moveElement({ sourceTrackId: dragState.trackId, - targetTrackId: targetTrack.id, + targetTrackId: newTrackId, elementId: dragState.elementId, newStartTime: snappedTime, + createTrack: { type: sourceTrack.type, index: dropTarget.trackIndex }, rippleEnabled: rippleEditingEnabled, }); - if (targetTrack.id !== dragState.trackId) { - selectElement({ trackId: targetTrack.id, elementId: dragState.elementId }); + selectElement({ trackId: newTrackId, elementId: dragState.elementId }); + } else { + const targetTrack = tracks[dropTarget.trackIndex]; + if (targetTrack) { + editor.timeline.moveElement({ + sourceTrackId: dragState.trackId, + targetTrackId: targetTrack.id, + elementId: dragState.elementId, + newStartTime: snappedTime, + rippleEnabled: rippleEditingEnabled, + }); + if (targetTrack.id !== dragState.trackId) { + selectElement({ + trackId: targetTrack.id, + elementId: dragState.elementId, + }); + } } } - } endDrag(); onSnapPointChange?.(null); @@ -520,10 +535,10 @@ export function useElementInteraction({ element: TimelineElement; track: TimelineTrack; }) => { - const isRightClick = event.button === MOUSE_BUTTON_RIGHT; + const isRightClick = event.button === MOUSE_BUTTON_RIGHT; - // right-click: don't stop propagation so ContextMenu can open - if (isRightClick) { + // right-click: don't stop propagation so ContextMenu can open + if (isRightClick) { const alreadySelected = isElementSelected({ trackId: track.id, elementId: element.id, @@ -538,12 +553,12 @@ export function useElementInteraction({ return; } - event.stopPropagation(); - mouseDownLocationRef.current = { x: event.clientX, y: event.clientY }; + event.stopPropagation(); + mouseDownLocationRef.current = { x: event.clientX, y: event.clientY }; - const isMultiSelect = event.metaKey || event.ctrlKey || event.shiftKey; + const isMultiSelect = event.metaKey || event.ctrlKey || event.shiftKey; - if (isMultiSelect) { + if (isMultiSelect) { handleSelectionClick({ trackId: track.id, elementId: element.id, @@ -551,7 +566,7 @@ export function useElementInteraction({ }); } - const clickOffsetTime = getClickOffsetTime({ + const clickOffsetTime = getClickOffsetTime({ clientX: event.clientX, elementRect: event.currentTarget.getBoundingClientRect(), zoomLevel, @@ -579,9 +594,9 @@ export function useElementInteraction({ element: TimelineElement; track: TimelineTrack; }) => { - event.stopPropagation(); + event.stopPropagation(); - if (mouseDownLocationRef.current) { + if (mouseDownLocationRef.current) { const deltaX = Math.abs(event.clientX - mouseDownLocationRef.current.x); const deltaY = Math.abs(event.clientY - mouseDownLocationRef.current.y); if (deltaX > DRAG_THRESHOLD_PX || deltaY > DRAG_THRESHOLD_PX) { @@ -593,7 +608,7 @@ export function useElementInteraction({ // modifier keys already handled in mousedown if (event.metaKey || event.ctrlKey || event.shiftKey) return; - const alreadySelected = isElementSelected({ + const alreadySelected = isElementSelected({ trackId: track.id, elementId: element.id, }); |
