This commit is contained in:
Maze Winther
2026-02-10 16:28:21 +01:00
parent 33a8705f0d
commit fca99d6126
51 changed files with 1358 additions and 1048 deletions
@@ -60,10 +60,7 @@ export function useEdgeAutoScroll({
mouseXRelative > viewportWidth - edgeThreshold &&
rulerViewport.scrollLeft < scrollMax
) {
const edgeDistance = Math.max(
0,
viewportWidth - edgeThreshold - mouseXRelative,
);
const edgeDistance = Math.max(0, viewportWidth - mouseXRelative);
const intensity = 1 - edgeDistance / edgeThreshold;
scrollSpeed = maxScrollSpeed * intensity;
}
@@ -44,7 +44,7 @@ export function useTimelineZoom({
null,
);
const [zoomLevel, setZoomLevel] = useState(() => {
const [zoomLevel, setZoomLevelRaw] = useState(() => {
if (initialZoom !== undefined) {
hasInitializedRef.current = true;
return Math.max(
@@ -56,6 +56,18 @@ export function useTimelineZoom({
});
const previousZoomRef = useRef(zoomLevel);
const hasRestoredScrollRef = useRef(false);
const preZoomScrollLeftRef = useRef(0);
const setZoomLevel = useCallback(
(updater: number | ((prev: number) => number)) => {
const scrollElement = tracksScrollRef.current;
if (scrollElement) {
preZoomScrollLeftRef.current = scrollElement.scrollLeft;
}
setZoomLevelRaw(updater);
},
[tracksScrollRef],
);
const handleWheel = useCallback(
(event: ReactWheelEvent) => {
@@ -82,7 +94,7 @@ export function useTimelineZoom({
return;
}
},
[minZoom],
[minZoom, setZoomLevel],
);
useEffect(() => {
@@ -99,7 +111,7 @@ export function useTimelineZoom({
}
return prev;
});
}, [minZoom, initialZoom]);
}, [minZoom, initialZoom, setZoomLevel]);
const wrappedSetZoomLevel = useCallback(
(zoomLevelOrUpdater: number | ((prev: number) => number)) => {
@@ -115,7 +127,7 @@ export function useTimelineZoom({
return clampedZoom;
});
},
[minZoom],
[minZoom, setZoomLevel],
);
useLayoutEffect(() => {
@@ -128,7 +140,7 @@ export function useTimelineZoom({
return;
}
const currentScrollLeft = scrollElement.scrollLeft;
const currentScrollLeft = preZoomScrollLeftRef.current;
const playheadTime = editor.playback.getCurrentTime();
const sliderPercent = zoomToSlider({ zoomLevel, minZoom });
+29
View File
@@ -0,0 +1,29 @@
import { useEffect, useState } from "react";
export function useContainerSize({
containerRef,
}: {
containerRef: React.RefObject<HTMLElement | null>;
}) {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const container = containerRef.current;
if (!container) return;
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const { width, height } = entry.contentRect;
setSize({ width, height });
}
});
observer.observe(container);
return () => {
observer.disconnect();
};
}, [containerRef]);
return size;
}
+30
View File
@@ -0,0 +1,30 @@
import { useCallback, useEffect, useState } from "react";
export function useFullscreen({
containerRef,
}: {
containerRef: React.RefObject<HTMLElement | null>;
}) {
const [isFullscreen, setIsFullscreen] = useState(false);
useEffect(() => {
const handleChange = () => {
setIsFullscreen(document.fullscreenElement !== null);
};
document.addEventListener("fullscreenchange", handleChange);
return () => {
document.removeEventListener("fullscreenchange", handleChange);
};
}, []);
const toggleFullscreen = useCallback(() => {
if (!containerRef.current) return;
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
containerRef.current.requestFullscreen();
}
}, [containerRef]);
return { isFullscreen, toggleFullscreen };
}
@@ -137,6 +137,16 @@ export function usePreviewInteraction({
const deltaX = currentPos.x - dragStateRef.current.startX;
const deltaY = currentPos.y - dragStateRef.current.startY;
const hasMovement = Math.abs(deltaX) > 0.5 || Math.abs(deltaY) > 0.5;
if (!hasMovement) {
dragStateRef.current = null;
setIsDragging(false);
event.currentTarget.releasePointerCapture(event.pointerId);
return;
}
// revert to pre-drag state so the command captures the correct undo snapshot
editor.timeline.updateTracks(dragStateRef.current.tracksSnapshot);