diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-02-10 16:28:21 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-02-10 16:28:21 +0100 |
| commit | fca99d6126c31fbb18ed9f1034cee6f940b040e8 (patch) | |
| tree | 11500ff0fcc4a933650e3e91f1ea00fd315c4d0c /apps/web/src/hooks | |
| parent | 33a8705f0d967891402c61dd3192e6bad24921ef (diff) | |
| download | opencut-fca99d6126c31fbb18ed9f1034cee6f940b040e8.tar.gz | |
refactor
Diffstat (limited to 'apps/web/src/hooks')
| -rw-r--r-- | apps/web/src/hooks/timeline/use-edge-auto-scroll.ts | 5 | ||||
| -rw-r--r-- | apps/web/src/hooks/timeline/use-timeline-zoom.ts | 22 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-container-size.ts | 29 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-fullscreen.ts | 30 | ||||
| -rw-r--r-- | apps/web/src/hooks/use-preview-interaction.ts | 10 |
5 files changed, 87 insertions, 9 deletions
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<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; +} 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<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 }; +} 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); |
