tui
js/tty/tui.ts
fino:tty/tui — terminal host renderer for fino:ui components.
This module is the first host for the portable fino:ui core. It provides
terminal component primitives, deterministic frame rendering for tests, and a
small fullscreen live renderer. The layout engine is intentionally a Fino
subset: row/column direction, fixed sizes, flex spacers, gap, padding,
borders, simple alignment, wrapping, and clipping.
V1 is terminal-only and POSIX-oriented. It includes raw keyboard input and SGR mouse events for fullscreen apps, but it does not implement DOM/HTML output, React hooks, or inline terminal regions.
/** @jsxImportSource fino:ui *\/
import { Box, Text, renderFrame } from 'fino:tty/tui';
const frame = renderFrame(
<Box border padding={1}><Text>Hello</Text></Box>,
{ width: 20, height: 3 },
);
Interfaces
interface BoxProps extends Props {
Props accepted by Box.
Properties
width?: number
height?: number
flex?: number
direction?: Direction
gap?: number
padding?: number
paddingX?: number
paddingY?: number
border?: boolean
align?: Align
background?: BackgroundColor
children?: Child
interface TextProps extends Props {
Props accepted by Text.
Properties
wrap?: boolean
align?: Align
background?: BackgroundColor
children?: Child
interface SpacerProps extends Props {
Props accepted by Spacer.
Properties
width?: number
height?: number
flex?: number
interface InputProps extends Props {
Props accepted by Input.
Properties
value?: string
placeholder?: string
focused?: boolean
background?: BackgroundColor
interface ButtonProps extends Props {
Props accepted by Button.
Properties
label?: string
focused?: boolean
interface ListProps extends Props {
Props accepted by List.
Properties
items: string[]
selectedIndex?: number
interface ScrollViewProps extends Props {
Props accepted by ScrollView.
Properties
width?: number
height?: number
offset?: number
children?: Child
interface RenderFrameOptions {
Options for deterministic terminal snapshot rendering.
Properties
width: number
height: number
interface TerminalSize {
Current terminal viewport size in character cells.
Properties
width: number
height: number
interface RenderOptions {
Options for live fullscreen terminal rendering.
Properties
width?: number
height?: number
input?: boolean
mouse?: boolean
onEvent?: (event: TuiEvent, app: TuiApp) => void | Promise<void>
interface TuiApp {
Handle returned by render() for updating or stopping a fullscreen app.
Methods
update(element: VNode): void
stop(): void
Properties
input?: TuiInput
interface TuiKeyEvent {
Keyboard event decoded from terminal input.
Properties
type: 'key'
key: string
text?: string
ctrl?: boolean
alt?: boolean
shift?: boolean
interface TuiMouseEvent {
Mouse event decoded from SGR terminal mouse reporting.
Properties
type: 'mouse'
action: 'press' | 'release' | 'drag' | 'move' | 'wheel'
button: 'left' | 'middle' | 'right' | 'none' | 'wheel-up' | 'wheel-down'
x: number
y: number
ctrl: boolean
alt: boolean
shift: boolean
interface TuiInputOptions {
Options for creating a raw terminal input reader.
Properties
mouse?: boolean
Types
type TuiEvent = TuiKeyEvent | TuiMouseEvent
Terminal input event consumed by TUI applications.
Functions
function Box(props: BoxProps): VNode
Terminal box container with row/column layout, padding, gap, and borders.
function Text(props: TextProps): VNode
Terminal text node with optional wrapping.
function Spacer(props: SpacerProps): VNode
Flexible or fixed empty space inside a Box.
function Input(props: InputProps): VNode
Single-line text input primitive for terminal forms.
function Button(props: ButtonProps): VNode
Push button primitive rendered as bracketed terminal text.
function List(props: ListProps): VNode
Vertical list primitive with a selected row marker.
function ScrollView(props: ScrollViewProps): VNode
Clipped viewport over child content.
function decodeTuiInput(bytes: Uint8Array): TuiEvent[]
Decode one terminal input byte chunk into TUI input events.
The decoder understands printable UTF-8, common control keys, arrow/function
CSI sequences, and SGR mouse reporting (CSI < code ; x ; y M/m). SGR mouse
coordinates are converted to zero-based x/y values.
function createTuiInput(options: TuiInputOptions = {}): TuiInput
Create a raw terminal input reader for TUI applications.
The reader enables raw mode immediately. Call close() when the application
exits so terminal state is restored.
function getTerminalSize(): TerminalSize
Return the current terminal viewport size.
The TUI host asks the terminal with ioctl(TIOCGWINSZ) when possible and
falls back to environment dimensions in non-interactive contexts.
async function measureTerminalSize(): Promise<TerminalSize>
Measure the visible terminal viewport with an ANSI cursor-position query.
This is slower than getTerminalSize() but handles terminal panes where
ioctl(TIOCGWINSZ) or environment dimensions are stale. The function enters
raw mode briefly, moves the cursor to a very large coordinate, asks the
terminal to report the clamped cursor position, restores the cursor, and
returns the reported row/column. If the terminal does not answer quickly, it
falls back to getTerminalSize().
function renderFrame(element: VNode, options: RenderFrameOptions): string
Render an element tree to a deterministic terminal frame.
The returned string contains exactly height lines joined with \n, and
each line is padded or clipped to width cells.
function render(element: VNode, options: RenderOptions = {}): TuiApp
Render a fullscreen terminal app and return a lifecycle handle.
This enters the alternate screen, hides the cursor, writes the current frame,
and restores terminal state from stop(). Width and height default to the
current terminal size when available.
Classes
class TuiInput {
Raw terminal input reader for keyboard and mouse events.
Constructors
constructor(options: TuiInputOptions = {})
Methods
async read(): Promise<TuiEvent | null>
Read the next decoded keyboard or mouse event from stdin.
close(): void
Restore raw mode and mouse reporting.