| 1 | import { useCallback, useEffect, type RefObject, type UIEvent } from "react"; |
| 2 | import { flushWorkspaceTreeMemory, rememberWorkspaceTreeScroll } from "./workspaceViewMemory"; |
| 3 | |
| 4 | export function useWorkspaceTreeScrollPersistence<T extends HTMLElement>({ |
| 5 | memoryKey, |
| 6 | open, |
| 7 | scrollRef, |
| 8 | }: { |
| 9 | memoryKey: string; |
| 10 | open: boolean; |
| 11 | scrollRef: RefObject<T | null>; |
| 12 | }) { |
| 13 | useEffect(() => { |
| 14 | if (!open) return; |
| 15 | const element = scrollRef.current; |
| 16 | const flush = () => flushWorkspaceTreeMemory(); |
| 17 | const flushWhenHidden = () => { |
| 18 | if (document.visibilityState === "hidden") flush(); |
| 19 | }; |
| 20 | element?.addEventListener("scrollend", flush); |
| 21 | window.addEventListener("pagehide", flush); |
| 22 | document.addEventListener("visibilitychange", flushWhenHidden); |
| 23 | return () => { |
| 24 | element?.removeEventListener("scrollend", flush); |
| 25 | window.removeEventListener("pagehide", flush); |
| 26 | document.removeEventListener("visibilitychange", flushWhenHidden); |
| 27 | flush(); |
| 28 | }; |
| 29 | }, [memoryKey, open, scrollRef]); |
| 30 | |
| 31 | return useCallback((event: UIEvent<T>) => { |
| 32 | // Only user-initiated scrolling is persisted: tree rebuilds reset the |
| 33 | // container to scrollTop 0 via script (isTrusted=false), and persisting |
| 34 | // that 0 would clobber the saved offset so restoration jumps back to top. |
| 35 | if (!event.nativeEvent.isTrusted) return; |
| 36 | rememberWorkspaceTreeScroll(memoryKey, event.currentTarget.scrollTop); |
| 37 | }, [memoryKey]); |
| 38 | } |
| 39 |