diff options
| author | Maze Winther <mazewinther@gmail.com> | 2026-03-27 00:55:15 +0100 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2026-03-29 15:56:48 +0200 |
| commit | 4d127a038bf768eded68aae3cfa5c1b12241bdac (patch) | |
| tree | 16bbb801caf6770546cff4fdb37b6408ec9ead98 /apps/web/src/hooks/timeline/use-edge-auto-scroll.ts | |
| parent | 82817cb50cb0487350573d6129130aec705f924b (diff) | |
| download | opencut-4d127a038bf768eded68aae3cfa5c1b12241bdac.tar.gz | |
chore: normalize line endings
Diffstat (limited to 'apps/web/src/hooks/timeline/use-edge-auto-scroll.ts')
| -rw-r--r-- | apps/web/src/hooks/timeline/use-edge-auto-scroll.ts | 194 |
1 files changed, 97 insertions, 97 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 fc5df4d9..509031bb 100644 --- a/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts +++ b/apps/web/src/hooks/timeline/use-edge-auto-scroll.ts @@ -1,97 +1,97 @@ -import { useEffect, useRef } from "react"; - -interface UseEdgeAutoScrollParams { - isActive: boolean; - getMouseClientX: () => number; - rulerScrollRef: React.RefObject<HTMLDivElement | null>; - tracksScrollRef: React.RefObject<HTMLDivElement | null>; - contentWidth: number; - edgeThreshold?: number; - maxScrollSpeed?: number; -} - -export function useEdgeAutoScroll({ - isActive, - getMouseClientX, - rulerScrollRef, - tracksScrollRef, - contentWidth, - edgeThreshold = 100, - maxScrollSpeed = 15, -}: UseEdgeAutoScrollParams): void { - const rafRef = useRef<number | null>(null); - - useEffect(() => { - if (!isActive) { - if (rafRef.current) { - cancelAnimationFrame(rafRef.current); - rafRef.current = null; - } - return; - } - - const step = () => { - const rulerViewport = rulerScrollRef.current; - const tracksViewport = tracksScrollRef.current; - if (!rulerViewport || !tracksViewport) { - rafRef.current = requestAnimationFrame(step); - return; - } - - const viewportRect = rulerViewport.getBoundingClientRect(); - const mouseX = getMouseClientX(); - const mouseXRelative = mouseX - viewportRect.left; - - const viewportWidth = rulerViewport.clientWidth; - const intrinsicContentWidth = rulerViewport.scrollWidth; - const effectiveContentWidth = Math.max( - contentWidth, - intrinsicContentWidth, - ); - const scrollMax = Math.max(0, effectiveContentWidth - viewportWidth); - - let scrollSpeed = 0; - - if (mouseXRelative < edgeThreshold && rulerViewport.scrollLeft > 0) { - const edgeDistance = Math.max(0, mouseXRelative); - const intensity = 1 - edgeDistance / edgeThreshold; - scrollSpeed = -maxScrollSpeed * intensity; - } else if ( - mouseXRelative > viewportWidth - edgeThreshold && - rulerViewport.scrollLeft < scrollMax - ) { - const edgeDistance = Math.max(0, viewportWidth - mouseXRelative); - const intensity = 1 - edgeDistance / edgeThreshold; - scrollSpeed = maxScrollSpeed * intensity; - } - - if (scrollSpeed !== 0) { - const newScrollLeft = Math.max( - 0, - Math.min(scrollMax, rulerViewport.scrollLeft + scrollSpeed), - ); - rulerViewport.scrollLeft = newScrollLeft; - tracksViewport.scrollLeft = newScrollLeft; - } - - rafRef.current = requestAnimationFrame(step); - }; - - rafRef.current = requestAnimationFrame(step); - - return () => { - if (rafRef.current) { - cancelAnimationFrame(rafRef.current); - rafRef.current = null; - } - }; - }, [ - isActive, - getMouseClientX, - rulerScrollRef, - tracksScrollRef, - contentWidth, - edgeThreshold, - maxScrollSpeed, - ]); -} +import { useEffect, useRef } from "react";
+
+interface UseEdgeAutoScrollParams {
+ isActive: boolean;
+ getMouseClientX: () => number;
+ rulerScrollRef: React.RefObject<HTMLDivElement | null>;
+ tracksScrollRef: React.RefObject<HTMLDivElement | null>;
+ contentWidth: number;
+ edgeThreshold?: number;
+ maxScrollSpeed?: number;
+}
+
+export function useEdgeAutoScroll({
+ isActive,
+ getMouseClientX,
+ rulerScrollRef,
+ tracksScrollRef,
+ contentWidth,
+ edgeThreshold = 100,
+ maxScrollSpeed = 15,
+}: UseEdgeAutoScrollParams): void {
+ const rafRef = useRef<number | null>(null);
+
+ useEffect(() => {
+ if (!isActive) {
+ if (rafRef.current) {
+ cancelAnimationFrame(rafRef.current);
+ rafRef.current = null;
+ }
+ return;
+ }
+
+ const step = () => {
+ const rulerViewport = rulerScrollRef.current;
+ const tracksViewport = tracksScrollRef.current;
+ if (!rulerViewport || !tracksViewport) {
+ rafRef.current = requestAnimationFrame(step);
+ return;
+ }
+
+ const viewportRect = rulerViewport.getBoundingClientRect();
+ const mouseX = getMouseClientX();
+ const mouseXRelative = mouseX - viewportRect.left;
+
+ const viewportWidth = rulerViewport.clientWidth;
+ const intrinsicContentWidth = rulerViewport.scrollWidth;
+ const effectiveContentWidth = Math.max(
+ contentWidth,
+ intrinsicContentWidth,
+ );
+ const scrollMax = Math.max(0, effectiveContentWidth - viewportWidth);
+
+ let scrollSpeed = 0;
+
+ if (mouseXRelative < edgeThreshold && rulerViewport.scrollLeft > 0) {
+ const edgeDistance = Math.max(0, mouseXRelative);
+ const intensity = 1 - edgeDistance / edgeThreshold;
+ scrollSpeed = -maxScrollSpeed * intensity;
+ } else if (
+ mouseXRelative > viewportWidth - edgeThreshold &&
+ rulerViewport.scrollLeft < scrollMax
+ ) {
+ const edgeDistance = Math.max(0, viewportWidth - mouseXRelative);
+ const intensity = 1 - edgeDistance / edgeThreshold;
+ scrollSpeed = maxScrollSpeed * intensity;
+ }
+
+ if (scrollSpeed !== 0) {
+ const newScrollLeft = Math.max(
+ 0,
+ Math.min(scrollMax, rulerViewport.scrollLeft + scrollSpeed),
+ );
+ rulerViewport.scrollLeft = newScrollLeft;
+ tracksViewport.scrollLeft = newScrollLeft;
+ }
+
+ rafRef.current = requestAnimationFrame(step);
+ };
+
+ rafRef.current = requestAnimationFrame(step);
+
+ return () => {
+ if (rafRef.current) {
+ cancelAnimationFrame(rafRef.current);
+ rafRef.current = null;
+ }
+ };
+ }, [
+ isActive,
+ getMouseClientX,
+ rulerScrollRef,
+ tracksScrollRef,
+ contentWidth,
+ edgeThreshold,
+ maxScrollSpeed,
+ ]);
+}
|
