import type { Element } from "./elements.js"; import type { InputSource, KeyEvent } from "./input/types.js"; import type { OutputTarget } from "./output/types.js"; import { Frame } from "./frame.js"; export declare class Screen { private output; private input; private width; private height; constructor(opts: { output: OutputTarget; input: InputSource; width: number; height: number; }); render(root: Element, label?: string): Frame; nextKey(): Promise; nextLine(prompt: string): Promise; size(): { width: number; height: number; }; runLoop(opts: { initialState: S; render: (state: S) => Element | Promise; handleKey: (state: S, event: KeyEvent) => S | Promise; isDone: (state: S) => boolean | Promise; label?: string; /** * If set, the loop races each `nextKey()` against a `setTimeout` * of `tickMs` milliseconds. On a tick, it re-renders with the * current state (no transition). On a key, it runs `handleKey` * then re-renders. Used by `repl()` to keep a live status line * ticking while no keys arrive (e.g. during a long LLM call). * * When omitted, the loop is pure event-driven: it blocks on * `nextKey()` and re-renders only after each keypress. * * The tick-side branch reuses a single in-flight `nextKey()` * promise across iterations so a key the user types during a * tick race is consumed by the next race rather than queued * behind abandoned waiters. */ tickMs?: number; }): Promise; destroy(): void; }