fix: undo for resizing timeline elements

This commit is contained in:
Maze Winther 2025-07-21 14:46:28 +02:00
parent aeb9cfc6b8
commit a2a9bef1d8
2 changed files with 68 additions and 25 deletions

View File

@ -29,7 +29,12 @@ export function useTimelineElementResize({
}: UseTimelineElementResizeProps) {
const [resizing, setResizing] = useState<ResizeState | null>(null);
const { mediaItems } = useMediaStore();
const { updateElementStartTime } = useTimelineStore();
const {
updateElementStartTime,
updateElementTrim,
updateElementDuration,
pushHistory,
} = useTimelineStore();
// Set up document-level mouse listeners during resize (like proper drag behavior)
useEffect(() => {
@ -61,6 +66,9 @@ export function useTimelineElementResize({
e.stopPropagation();
e.preventDefault();
// Push history once at the start of the resize operation
pushHistory();
setResizing({
elementId,
side,
@ -112,13 +120,14 @@ export function useTimelineElementResize({
const trimDelta = newTrimStart - resizing.initialTrimStart;
const newStartTime = element.startTime + trimDelta;
onUpdateTrim(
updateElementTrim(
track.id,
element.id,
newTrimStart,
resizing.initialTrimEnd
resizing.initialTrimEnd,
false
);
updateElementStartTime(track.id, element.id, newStartTime);
updateElementStartTime(track.id, element.id, newStartTime, false);
} else {
// Trying to extend beyond trimStart = 0
if (canExtendElementDuration()) {
@ -128,22 +137,29 @@ export function useTimelineElementResize({
const newDuration = element.duration + extensionAmount;
// Keep trimStart at 0 and extend the element
onUpdateTrim(track.id, element.id, 0, resizing.initialTrimEnd);
onUpdateDuration(track.id, element.id, newDuration);
updateElementStartTime(track.id, element.id, newStartTime);
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;
onUpdateTrim(
updateElementTrim(
track.id,
element.id,
newTrimStart,
resizing.initialTrimEnd
resizing.initialTrimEnd,
false
);
updateElementStartTime(track.id, element.id, newStartTime);
updateElementStartTime(track.id, element.id, newStartTime, false);
}
}
} else {
@ -159,27 +175,35 @@ 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
);
}
}

View File

@ -106,17 +106,20 @@ interface TimelineStore {
trackId: string,
elementId: string,
trimStart: number,
trimEnd: number
trimEnd: number,
pushHistory?: boolean
) => void;
updateElementDuration: (
trackId: string,
elementId: string,
duration: number
duration: number,
pushHistory?: boolean
) => void;
updateElementStartTime: (
trackId: string,
elementId: string,
startTime: number
startTime: number,
pushHistory?: boolean
) => void;
toggleTrackMute: (trackId: string) => void;
@ -687,8 +690,14 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
updateTracksAndSave(newTracks);
},
updateElementTrim: (trackId, elementId, trimStart, trimEnd) => {
get().pushHistory();
updateElementTrim: (
trackId,
elementId,
trimStart,
trimEnd,
pushHistory = true
) => {
if (pushHistory) get().pushHistory();
updateTracksAndSave(
get()._tracks.map((track) =>
track.id === trackId
@ -705,8 +714,13 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
);
},
updateElementDuration: (trackId, elementId, duration) => {
get().pushHistory();
updateElementDuration: (
trackId,
elementId,
duration,
pushHistory = true
) => {
if (pushHistory) get().pushHistory();
updateTracksAndSave(
get()._tracks.map((track) =>
track.id === trackId
@ -721,8 +735,13 @@ export const useTimelineStore = create<TimelineStore>((set, get) => {
);
},
updateElementStartTime: (trackId, elementId, startTime) => {
get().pushHistory();
updateElementStartTime: (
trackId,
elementId,
startTime,
pushHistory = true
) => {
if (pushHistory) get().pushHistory();
updateTracksAndSave(
get()._tracks.map((track) =>
track.id === trackId