/** * Tiny framework-free store for the page transition („Umblättern“). * TransitionLink calls `startTransition`; Curtain subscribes, animates, * pushes the route and finally calls `endTransition`. */ export type TransitionPhase = "idle" | "cover" | "pushed" | "reveal"; export interface TransitionState { phase: TransitionPhase; href: string | null; label?: string; } type Listener = (state: TransitionState) => void; let state: TransitionState = { phase: "idle", href: null }; const listeners = new Set(); function emit() { listeners.forEach((cb) => cb(state)); } /** Begins a transition. Returns false when one is already running (double clicks). */ export function startTransition(href: string, label?: string): boolean { if (state.phase !== "idle") return false; state = { phase: "cover", href, label }; emit(); return true; } /** Internal: Curtain advances the phase. */ export function setTransitionPhase(phase: TransitionPhase) { state = { ...state, phase }; emit(); } export function endTransition() { state = { phase: "idle", href: null }; emit(); } export function isTransitioning(): boolean { return state.phase !== "idle"; } export function getTransitionState(): TransitionState { return state; } export function subscribe(cb: Listener): () => void { listeners.add(cb); return () => { listeners.delete(cb); }; }