summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks/timeline/use-scroll-position.ts
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2026-02-08 22:21:17 +0100
committerMaze Winther <mazewinther@gmail.com>2026-02-08 22:21:17 +0100
commite50a817b97b87baa0cd8fdde0fdb5d607143c1c3 (patch)
tree8f33d19153be9a6d9fe81b1a7e7a54179ab88feb /apps/web/src/hooks/timeline/use-scroll-position.ts
parent484ce47867b1c92c83e4cfab9fa8371bb6e68e12 (diff)
downloadopencut-e50a817b97b87baa0cd8fdde0fdb5d607143c1c3.tar.gz
add transform + few fixes
feat: transform feat: batch command fix: slider undo fix: timeline zoom perf refactor: make updateElement support multiple
Diffstat (limited to 'apps/web/src/hooks/timeline/use-scroll-position.ts')
-rw-r--r--apps/web/src/hooks/timeline/use-scroll-position.ts52
1 files changed, 52 insertions, 0 deletions
diff --git a/apps/web/src/hooks/timeline/use-scroll-position.ts b/apps/web/src/hooks/timeline/use-scroll-position.ts
new file mode 100644
index 00000000..ad2c6374
--- /dev/null
+++ b/apps/web/src/hooks/timeline/use-scroll-position.ts
@@ -0,0 +1,52 @@
+import { useEffect, useState, useRef } from "react";
+
+interface UseScrollPositionReturn {
+ scrollLeft: number;
+ viewportWidth: number;
+}
+
+export function useScrollPosition({
+ scrollRef,
+}: {
+ scrollRef: React.RefObject<HTMLElement | null>;
+}): UseScrollPositionReturn {
+ const [scrollLeft, setScrollLeft] = useState(0);
+ const [viewportWidth, setViewportWidth] = useState(0);
+ const rafIdRef = useRef<number | null>(null);
+
+ useEffect(() => {
+ const scrollElement = scrollRef.current;
+ if (!scrollElement) return;
+
+ const updatePosition = () => {
+ if (rafIdRef.current !== null) {
+ cancelAnimationFrame(rafIdRef.current);
+ }
+
+ rafIdRef.current = requestAnimationFrame(() => {
+ setScrollLeft(scrollElement.scrollLeft);
+ setViewportWidth(scrollElement.clientWidth);
+ rafIdRef.current = null;
+ });
+ };
+
+ const resizeObserver = new ResizeObserver(() => {
+ updatePosition();
+ });
+
+ updatePosition();
+
+ scrollElement.addEventListener("scroll", updatePosition, { passive: true });
+ resizeObserver.observe(scrollElement);
+
+ return () => {
+ scrollElement.removeEventListener("scroll", updatePosition);
+ resizeObserver.disconnect();
+ if (rafIdRef.current !== null) {
+ cancelAnimationFrame(rafIdRef.current);
+ }
+ };
+ }, [scrollRef]);
+
+ return { scrollLeft, viewportWidth };
+}