From fca99d6126c31fbb18ed9f1034cee6f940b040e8 Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Tue, 10 Feb 2026 16:28:21 +0100 Subject: refactor --- .../web/src/hooks/timeline/use-edge-auto-scroll.ts | 5 +--- apps/web/src/hooks/timeline/use-timeline-zoom.ts | 22 ++++++++++++---- apps/web/src/hooks/use-container-size.ts | 29 +++++++++++++++++++++ apps/web/src/hooks/use-fullscreen.ts | 30 ++++++++++++++++++++++ apps/web/src/hooks/use-preview-interaction.ts | 10 ++++++++ 5 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/hooks/use-container-size.ts create mode 100644 apps/web/src/hooks/use-fullscreen.ts (limited to 'apps/web/src/hooks') diff --git a/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts b/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts index 095c0599..fc5df4d9 100644 --- a/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts +++ b/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts @@ -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; } diff --git a/apps/web/src/hooks/timeline/use-timeline-zoom.ts b/apps/web/src/hooks/timeline/use-timeline-zoom.ts index 13024103..10563a05 100644 --- a/apps/web/src/hooks/timeline/use-timeline-zoom.ts +++ b/apps/web/src/hooks/timeline/use-timeline-zoom.ts @@ -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 }); diff --git a/apps/web/src/hooks/use-container-size.ts b/apps/web/src/hooks/use-container-size.ts new file mode 100644 index 00000000..8b46f20e --- /dev/null +++ b/apps/web/src/hooks/use-container-size.ts @@ -0,0 +1,29 @@ +import { useEffect, useState } from "react"; + +export function useContainerSize({ + containerRef, +}: { + containerRef: React.RefObject; +}) { + 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; +} diff --git a/apps/web/src/hooks/use-fullscreen.ts b/apps/web/src/hooks/use-fullscreen.ts new file mode 100644 index 00000000..193441c9 --- /dev/null +++ b/apps/web/src/hooks/use-fullscreen.ts @@ -0,0 +1,30 @@ +import { useCallback, useEffect, useState } from "react"; + +export function useFullscreen({ + containerRef, +}: { + containerRef: React.RefObject; +}) { + 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 }; +} diff --git a/apps/web/src/hooks/use-preview-interaction.ts b/apps/web/src/hooks/use-preview-interaction.ts index 6aeb0c9b..31b33504 100644 --- a/apps/web/src/hooks/use-preview-interaction.ts +++ b/apps/web/src/hooks/use-preview-interaction.ts @@ -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); -- cgit v1.3.1