| 1 | import { useCallback, useEffect, useState } from "react"; |
| 2 | |
| 3 | import { prefersReducedMotion } from "./motion"; |
| 4 | |
| 5 | const TERMINAL_TRANSITION_MS = 220; |
| 6 | |
| 7 | // Load xterm lazily, then keep it mounted so closing the drawer does not lose |
| 8 | // its live canvas. Fit is paused while the grid row animates because fitting |
| 9 | // every intermediate height also emits redundant PTY resize traffic. |
| 10 | export function useWarmTerminalPanel(open: boolean, resizing: boolean, visible = true): { |
| 11 | mounted: boolean; |
| 12 | fitEnabled: boolean; |
| 13 | prefetch: () => void; |
| 14 | } { |
| 15 | const [mounted, setMounted] = useState(open); |
| 16 | const [fitEnabled, setFitEnabled] = useState(false); |
| 17 | useEffect(() => { |
| 18 | if (open) setMounted(true); |
| 19 | }, [open]); |
| 20 | useEffect(() => { |
| 21 | if (!open || !visible) { |
| 22 | setFitEnabled(false); |
| 23 | return; |
| 24 | } |
| 25 | if (resizing) { |
| 26 | setFitEnabled(true); |
| 27 | return; |
| 28 | } |
| 29 | const delay = prefersReducedMotion() ? 0 : TERMINAL_TRANSITION_MS; |
| 30 | const timer = window.setTimeout(() => setFitEnabled(true), delay); |
| 31 | return () => window.clearTimeout(timer); |
| 32 | }, [open, resizing, visible]); |
| 33 | const prefetch = useCallback(() => { |
| 34 | void import("../components/TerminalPanel"); |
| 35 | }, []); |
| 36 | return { mounted, fitEnabled, prefetch }; |
| 37 | } |
| 38 |