import { useCallback, useRef, useState, type ReactNode } from "react"; const STORAGE_KEY = "typst-leaf.split"; const MIN_PCT = 25; const DEFAULT_PCT = 55; function loadRatio(): number { try { const v = Number(localStorage.getItem(STORAGE_KEY)); return v >= MIN_PCT && v <= 100 - MIN_PCT ? v : DEFAULT_PCT; } catch { return DEFAULT_PCT; } } function persistRatio(v: number) { try { localStorage.setItem(STORAGE_KEY, String(v)); } catch { /* ignore */ } } function clampPct(v: number): number { return Math.max(MIN_PCT, Math.min(100 - MIN_PCT, v)); } export function ResizableSplit({ left, right, onResize, }: { left: ReactNode; right: ReactNode; onResize?: () => void; }) { const [leftPct, setLeftPct] = useState(loadRatio); const leftPctRef = useRef(leftPct); const containerRef = useRef(null); const startDrag = useCallback((e: React.PointerEvent) => { e.preventDefault(); const el = e.currentTarget as HTMLElement; el.setPointerCapture(e.pointerId); const onMove = (ev: PointerEvent) => { if (!containerRef.current) return; const rect = containerRef.current.getBoundingClientRect(); const pct = clampPct(((ev.clientX - rect.left) / rect.width) * 100); leftPctRef.current = pct; setLeftPct(pct); onResize?.(); }; const onUp = () => { persistRatio(leftPctRef.current); onResize?.(); window.removeEventListener("pointermove", onMove); window.removeEventListener("pointerup", onUp); }; window.addEventListener("pointermove", onMove); window.addEventListener("pointerup", onUp); }, [onResize]); return (
{left}
{ const pct = DEFAULT_PCT; leftPctRef.current = pct; setLeftPct(pct); persistRatio(pct); }} />
{right}
); }