import { App, Component, ComponentPublicInstance, ShallowRef } from "vue"; import { Node } from "yoga-layout"; import { EventEmitter } from "node:events"; //#region src/io/kitty-keyboard.d.ts declare const kittyFlags: { readonly disambiguateEscapeCodes: 1; readonly reportEventTypes: 2; readonly reportAlternateKeys: 4; readonly reportAllKeysAsEscapeCodes: 8; readonly reportAssociatedText: 16; }; type KittyFlagName = keyof typeof kittyFlags; declare const kittyModifiers: { readonly shift: 1; readonly alt: 2; readonly ctrl: 4; readonly super: 8; readonly hyper: 16; readonly meta: 32; readonly capsLock: 64; readonly numLock: 128; }; type KittyKeyboardOptions = { mode?: "auto" | "enabled" | "disabled"; flags?: KittyFlagName[]; }; declare function resolveFlags(flags: KittyFlagName[]): number; type KittyQueryMatch = { state: "complete"; endIndex: number; } | { state: "partial"; }; declare function matchKittyQueryResponse(buffer: number[], startIndex: number): KittyQueryMatch | undefined; declare function hasCompleteKittyQueryResponse(buffer: number[]): boolean; declare function stripKittyQueryResponsesAndTrailingPartial(buffer: number[]): number[]; interface KittyKeyboardController { init(options: KittyKeyboardOptions | undefined, interactive: boolean): void; /** * @param sync When true, write the disable-kitty escape synchronously * (fs.writeSync) so it reaches the fd before an abrupt signal-driven exit * re-raises the signal (G18, Finding A). Defaults to async stream.write for * the normal unmount path. */ dispose(sync?: boolean): void; readonly isEnabled: boolean; } declare function createKittyKeyboardController(stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream): KittyKeyboardController; //#endregion //#region src/context.d.ts interface CursorPosition { x: number; y: number; } interface AppContext { exit: (errorOrResult?: unknown) => void; waitUntilRenderFlush: () => Promise; stdout: NodeJS.WriteStream; stderr: NodeJS.WriteStream; stdin: NodeJS.ReadStream; debug: boolean; interactive: boolean; isScreenReaderEnabled: boolean; isRawModeSupported: boolean; setRawMode: (mode: boolean) => void; writeToStdout: (data: string) => void; writeToStderr: (data: string) => void; cursorPosition: CursorPosition | undefined; setCursorPosition: (pos: CursorPosition | undefined) => void; } interface FocusContext { activeId: string | null; activeIdRef: ShallowRef; enabled: boolean; enableFocus: () => void; disableFocus: () => void; focusNext: () => void; focusPrevious: () => void; focus: (id: string) => void; blur: () => void; add: (id: string, options: { autoFocus?: boolean; }) => void; remove: (id: string) => void; activate: (id: string) => void; deactivate: (id: string) => void; subscribe: (id: string, fn: (focused: boolean) => void) => () => void; } //#endregion //#region src/host/nodes.d.ts type YogaNodeRef = Node; interface BoxProps { [k: string]: unknown; } interface TextProps { color?: unknown; backgroundColor?: unknown; dimColor?: boolean; bold?: boolean; italic?: boolean; underline?: boolean; strikethrough?: boolean; inverse?: boolean; wrap?: "wrap" | "hard" | "truncate" | "truncate-end" | "truncate-middle" | "truncate-start"; } interface NodeBase { parent: TuiContainer | null; } interface TuiRoot extends NodeBase { type: "root"; parent: null; children: TuiNode[]; yoga: YogaNodeRef; appContext: AppContext; /** Currently mounted node (if any). Updated on insert/remove. */ staticNode?: TuiStatic; /** Previous commit's staticNode — used to detect identity changes. */ previousStaticNode?: TuiStatic; /** Callback invoked when the identity changes (mount/unmount/remount). */ onStaticChange?: () => void; /** Listeners invoked after every layout calculation (yoga.calculateLayout). */ layoutListeners: Set<() => void>; } interface TuiBox extends NodeBase { type: "tui-box"; children: TuiNode[]; yoga: YogaNodeRef; props: BoxProps; paintDirty: boolean; internal_accessibility?: { role?: string; state?: Record; }; } interface TuiText extends NodeBase { type: "tui-text"; children: TuiInlineNode[]; yoga: YogaNodeRef; props: TextProps; measuredCache?: string; } interface TuiVirtualText extends NodeBase { type: "tui-virtual-text"; parent: TuiText | TuiVirtualText | TuiTransform | null; children: TuiInlineNode[]; props: TextProps; } interface TuiTextLeaf extends NodeBase { type: "text-leaf"; parent: TuiText | TuiVirtualText | TuiTransform | null; value: string; } /** Placeholder comment node used by Vue's renderer for v-if / null renders. */ interface TuiComment extends NodeBase { type: "comment"; value: string; } interface TuiStatic extends NodeBase { type: "tui-static"; children: TuiNode[]; yoga: YogaNodeRef; props: BoxProps; /** * Host child nodes already written to the static channel. Static items are * write-once: each commit only paints the children NOT in this set. We track * by node identity rather than a count because a single logical item expands * to several host nodes (the / plus empty text-leaf fragment * anchors Vue inserts), so a positional `writtenCount` would mis-slice. Once a * child is painted it is recorded here, then the component advances * its cursor and unmounts it (mirroring Ink's `setIndex(items.length)`). */ writtenNodes: Set; /** * Callback registered by the component, invoked by the renderer AFTER * a commit has painted freshly-written items. It advances the component's * reactive cursor (Ink's `index`) so the just-written items are sliced out and * unmount on the next render — the vue-tui analogue of Ink's post-commit * `useLayoutEffect(() => setIndex(items.length))`. Advancing AFTER paint (never * during render) guarantees items are written before they are dropped. */ onWritten?: () => void; } interface TuiTransform extends NodeBase { type: "tui-transform"; children: TuiNode[]; yoga: YogaNodeRef; transform: (line: string, lineIndex: number) => string; } type TuiInlineNode = TuiVirtualText | TuiTextLeaf | TuiComment | TuiTransform; type TuiContainer = TuiRoot | TuiBox | TuiStatic | TuiTransform | TuiText | TuiVirtualText; type TuiNode = TuiContainer | TuiTextLeaf | TuiComment; declare function createRoot(appContext: AppContext): TuiRoot; declare function createBox(): TuiBox; declare function createText(): TuiText; declare function createTextLeaf(value: string): TuiTextLeaf; //#endregion //#region src/render.d.ts interface MountOptions { stdout?: NodeJS.WriteStream; stdin?: NodeJS.ReadStream; stderr?: NodeJS.WriteStream; debug?: boolean; exitOnCtrlC?: boolean; /** * Controls when the app holds the terminal's raw mode, which suppresses the * terminal's own echo and line-editing. * * - `'always'` (default): raw mode is enabled at mount and held for the whole * run, even when no input composable is mounted, so typed keys never echo * into the rendered frame and Ctrl+C behaves the same on every screen. * - `'auto'`: raw mode is enabled only while a `useInput`, `useFocus`, or * `usePaste` is mounted, and released when the last one unmounts — so a * screen with no input handler returns to the terminal's normal cooked mode * (native echo, line-editing, Ctrl+C/Ctrl+Z). This is Ink's original behavior. * * Has no effect when non-interactive or when stdin is not a TTY (raw mode is * unsupported there). * * @default 'always' */ rawMode?: "always" | "auto"; /** * Override automatic interactive mode detection. * * By default, vue-tui detects whether the environment is interactive based * on CI detection (via `is-in-ci`) and `stdout.isTTY`. Most users should * not need to set this. * * When non-interactive, vue-tui disables ANSI erase sequences, cursor * manipulation, resize handling, writing only the final frame at unmount. * * @default true (false if in CI or `stdout.isTTY` is falsy) */ interactive?: boolean; /** * Patch `console.*` methods to route output through the TUI frame * coordinator (writeToStdout / writeToStderr) so that console.log * calls don't corrupt the rendered UI. * * Automatically disabled in debug mode. * * @default true */ patchConsole?: boolean; /** * Callback invoked after each render commit with timing information. */ onRender?: (info: { renderTime: number; }) => void; /** * Maximum frames per second. Controls the render-throttle window * (`ceil(1000 / maxFps)` ms) that throttles both the commit scheduler and * the useAnimation tick coalescing. Defaults to 30 (≈34ms), matching Ink. * * Ignored in debug / screen-reader mode (commits are immediate). * @default 30 */ maxFps?: number; /** * Enable screen reader mode. When enabled, the commit scheduler bypasses * throttling (immediate commits) so every frame is flushed without delay. * * @default true when `process.env["INK_SCREEN_READER"] === "true"`, otherwise false */ isScreenReaderEnabled?: boolean; /** * Enable incremental rendering. When enabled, the frame writer uses * line-diffing to minimize terminal writes — only changed lines are * rewritten instead of erasing and repainting the entire frame. * * @default false */ incrementalRendering?: boolean; /** * Render in the terminal's alternate screen buffer. When enabled, the * terminal switches to a clean buffer on mount and restores the original * content on unmount — no rendering artifacts are left behind. * * Requires interactive mode and a TTY stdout. Silently ignored otherwise. * * @default false */ alternateScreen?: boolean; /** * Configure kitty keyboard protocol support for enhanced keyboard input. * Enables additional modifiers (super, hyper, capsLock, numLock) and * disambiguated key events in terminals that support the protocol. * * @see https://sw.kovidgoyal.net/kitty/keyboard-protocol/ */ kittyKeyboard?: KittyKeyboardOptions; } interface TuiApp extends Omit, "mount"> { mount(options?: MountOptions): ComponentPublicInstance; waitUntilExit(): Promise; waitUntilRenderFlush(): Promise; clear(): void; } type RootProps = Record; declare function createApp(root: Component, rootProps?: RootProps | null): TuiApp; interface FocusControllerForTest extends FocusContext { __subscriberMapSize: () => number; } declare function createFocusController(): FocusControllerForTest; //#endregion //#region src/render-to-string.d.ts interface RenderToStringOptions { /** * Width of the virtual terminal in columns. * * @default 80 */ columns?: number; } /** * Options for the internal, screen-reader-capable render-to-string used by the * accessibility test suite. NOT part of the public API: Ink likewise keeps * screen-reader string rendering out of its public `renderToString` (layout * only) and reaches it through a private test helper. Exposed via * `@vue-tui/runtime/internal` as `renderToStringWithScreenReader`. */ interface RenderToStringInternalOptions extends RenderToStringOptions { /** * Enable screen reader mode. When enabled, the output is plain text * suitable for screen readers (no ANSI styling, with role/state annotations). * * @default false */ isScreenReaderEnabled?: boolean; } /** * Render a Vue component to a string synchronously. Unlike `createApp()`, * this function does not write to stdout, does not set up any terminal event * listeners, and returns the rendered output as a string. * * Useful for generating documentation, writing output to files, testing, or * any scenario where you need the rendered output as a string without * starting a persistent terminal application. * * Terminal-specific composables (`useInput`, `useStdin`, `useStdout`, * `useStderr`, `useApp`, `useFocus`, `useFocusManager`) return default * no-op values since there is no terminal session. They will not throw, but * they will not function as in a live terminal. * * The `` component is supported --- its output is prepended to the * dynamic output. * * If a component throws during rendering, the error is propagated to the * caller after cleanup. */ declare function renderToString(component: Component, options?: RenderToStringOptions): string; /** * Screen-reader-capable variant of {@link renderToString}, for the accessibility * test suite only (exported from `@vue-tui/runtime/internal`). The public * `renderToString` is layout-only, matching Ink, which keeps screen-reader * string rendering in a private test helper rather than its public API. */ declare function renderToStringWithScreenReader(component: Component, options?: RenderToStringInternalOptions): string; //#endregion export { createKittyKeyboardController as C, matchKittyQueryResponse as D, kittyModifiers as E, resolveFlags as O, KittyKeyboardOptions as S, kittyFlags as T, createText as _, MountOptions as a, KittyFlagName as b, createFocusController as c, TuiRoot as d, TuiStatic as f, createRoot as g, createBox as h, FocusControllerForTest as i, stripKittyQueryResponsesAndTrailingPartial as k, TuiBox as l, TuiTransform as m, renderToString as n, TuiApp as o, TuiText as p, renderToStringWithScreenReader as r, createApp as s, RenderToStringOptions as t, TuiNode as u, createTextLeaf as v, hasCompleteKittyQueryResponse as w, KittyKeyboardController as x, AppContext as y };