summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/use-timeline-element-resize.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/hooks/use-timeline-element-resize.ts')
-rw-r--r--apps/web/src/hooks/use-timeline-element-resize.ts86
1 files changed, 73 insertions, 13 deletions
diff --git a/apps/web/src/hooks/use-timeline-element-resize.ts b/apps/web/src/hooks/use-timeline-element-resize.ts
index 0e409977..3afa637b 100644
--- a/apps/web/src/hooks/use-timeline-element-resize.ts
+++ b/apps/web/src/hooks/use-timeline-element-resize.ts
@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import { ResizeState, TimelineElement, TimelineTrack } from "@/types/timeline";
import { useMediaStore } from "@/stores/media-store";
+import { useTimelineStore } from "@/stores/timeline-store";
interface UseTimelineElementResizeProps {
element: TimelineElement;
@@ -28,6 +29,12 @@ export function useTimelineElementResize({
}: UseTimelineElementResizeProps) {
const [resizing, setResizing] = useState<ResizeState | null>(null);
const { mediaItems } = useMediaStore();
+ const {
+ updateElementStartTime,
+ updateElementTrim,
+ updateElementDuration,
+ pushHistory,
+ } = useTimelineStore();
// Set up document-level mouse listeners during resize (like proper drag behavior)
useEffect(() => {
@@ -59,6 +66,9 @@ export function useTimelineElementResize({
e.stopPropagation();
e.preventDefault();
+ // Push history once at the start of the resize operation
+ pushHistory();
+
setResizing({
elementId,
side,
@@ -100,12 +110,58 @@ export function useTimelineElementResize({
const deltaTime = deltaX / (50 * zoomLevel);
if (resizing.side === "left") {
- // Left resize - only trim within original duration
+ // Left resize - different behavior for media vs text/image elements
const maxAllowed = element.duration - resizing.initialTrimEnd - 0.1;
const calculated = resizing.initialTrimStart + deltaTime;
- const newTrimStart = Math.max(0, Math.min(maxAllowed, calculated));
- onUpdateTrim(track.id, element.id, newTrimStart, resizing.initialTrimEnd);
+ if (calculated >= 0) {
+ // Normal trimming within available content
+ const newTrimStart = Math.min(maxAllowed, calculated);
+ const trimDelta = newTrimStart - resizing.initialTrimStart;
+ const newStartTime = element.startTime + trimDelta;
+
+ updateElementTrim(
+ track.id,
+ element.id,
+ newTrimStart,
+ resizing.initialTrimEnd,
+ false
+ );
+ updateElementStartTime(track.id, element.id, newStartTime, false);
+ } else {
+ // Trying to extend beyond trimStart = 0
+ if (canExtendElementDuration()) {
+ // Text/Image: extend element to the left by moving startTime and increasing duration
+ const extensionAmount = Math.abs(calculated);
+ const newStartTime = element.startTime - extensionAmount;
+ const newDuration = element.duration + extensionAmount;
+
+ // Keep trimStart at 0 and extend the element
+ updateElementTrim(
+ track.id,
+ element.id,
+ 0,
+ resizing.initialTrimEnd,
+ false
+ );
+ updateElementDuration(track.id, element.id, newDuration, false);
+ updateElementStartTime(track.id, element.id, newStartTime, false);
+ } else {
+ // Video/Audio: can't extend beyond original content - limit to trimStart = 0
+ const newTrimStart = 0;
+ const trimDelta = newTrimStart - resizing.initialTrimStart;
+ const newStartTime = element.startTime + trimDelta;
+
+ updateElementTrim(
+ track.id,
+ element.id,
+ newTrimStart,
+ resizing.initialTrimEnd,
+ false
+ );
+ updateElementStartTime(track.id, element.id, newStartTime, false);
+ }
+ }
} else {
// Right resize - can extend duration for supported element types
const calculated = resizing.initialTrimEnd - deltaTime;
@@ -119,36 +175,40 @@ export function useTimelineElementResize({
const newTrimEnd = 0; // Reset trimEnd to 0 since we're extending
// Update duration first, then trim
- onUpdateDuration(track.id, element.id, newDuration);
- onUpdateTrim(
+ updateElementDuration(track.id, element.id, newDuration, false);
+ updateElementTrim(
track.id,
element.id,
resizing.initialTrimStart,
- newTrimEnd
+ newTrimEnd,
+ false
);
} else {
// Can't extend - just set trimEnd to 0 (maximum possible extension)
- onUpdateTrim(track.id, element.id, resizing.initialTrimStart, 0);
+ updateElementTrim(
+ track.id,
+ element.id,
+ resizing.initialTrimStart,
+ 0,
+ false
+ );
}
} else {
// Normal trimming within original duration
const maxTrimEnd = element.duration - resizing.initialTrimStart - 0.1; // Leave at least 0.1s visible
const newTrimEnd = Math.max(0, Math.min(maxTrimEnd, calculated));
- onUpdateTrim(
+ updateElementTrim(
track.id,
element.id,
resizing.initialTrimStart,
- newTrimEnd
+ newTrimEnd,
+ false
);
}
}
};
- const handleResizeMove = (e: React.MouseEvent) => {
- updateTrimFromMouseMove(e);
- };
-
const handleResizeEnd = () => {
setResizing(null);
};