controlroom
API reference

controlroom/ink

Every export of controlroom/ink, with its signature and doc comment: Box, Newline, Spacer, Static, Text, Transform and 18 more, plus 25 types.

controlroom/ink — a drop-in for ink (R11, R12), graded by ink's own suite in compat-oracle. A program moves by changing its import and installing the reconciler ink used to bring along: npm install react react-reconciler.

React is the program's own, rendered by React's own reconciler through a host config of ours; layout is a TypeScript port of yoga's algorithm (no yoga); colour is roundel's and borders are flagstaff's. Nothing else in the package imports React, so the native API never loads it.

import { Box, Newline, Spacer, … } from 'controlroom/ink';

Functions

measureElement

A Box's laid-out size and its position in the live region, in cells; zeros before layout.

function measureElement(node: DOMElement): ElementMetrics;
ParameterType
nodeDOMElement

Returns ElementMetrics

Newline

function Newline({ count }: NewlineProps): ReactElement;
ParameterType
{ count }NewlineProps

Returns ReactElement

render

Mount node and draw it: ink's render. A stream as the second argument is the stdout.

function render(node: React.ReactNode, options?: RenderOptions | NodeJS.WritableStream): Instance;
ParameterType
nodeReact.ReactNode
options (optional)RenderOptions | NodeJS.WritableStream

Returns Instance

renderToString

The tree as a string, once, with no stream at all: ink's renderToString.

function renderToString(node: React.ReactNode, options?: RenderToStringOptions): string;
ParameterType
nodeReact.ReactNode
options (optional)RenderToStringOptions

Returns string

Spacer

A flexible space that fills the main axis between its siblings.

function Spacer(): ReactElement;

Returns ReactElement

Static

Items rendered once, above everything else, and never again: what has finished.

function Static<T>({ items, children: render, style: customStyle }: StaticProps<T>): ReactElement;
ParameterType
{ items, children: render, style: customStyle }StaticProps<T>

Returns ReactElement

Text

function Text({ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, 'aria-label': ariaLabel, 'aria-hidden': ariaHidden }: TextProps): ReactElement | null;
ParameterType
{ color, backgroundColor, dimColor, bold, italic, underline, strikethrough, inverse, wrap, children, 'aria-label': ariaLabel, 'aria-hidden': ariaHidden }TextProps

Returns ReactElement \| null

Transform

function Transform({ children, transform, accessibilityLabel }: TransformProps): ReactElement | null;
ParameterType
{ children, transform, accessibilityLabel }TransformProps

Returns ReactElement \| null

useAnimation

A frame counter, elapsed time and delta on the shared animation timer, with a reset.

function useAnimation(options?: {
    interval?: number;
    isActive?: boolean;
}): AnimationResult;
ParameterType
options (optional){ interval?: number; isActive?: boolean; }

Returns AnimationResult

useBoxMetrics

The tracked box's layout metrics, kept current across every layout; zeros until measured.

function useBoxMetrics(ref: React.RefObject<DOMElement | null>): UseBoxMetricsResult;
ParameterType
refReact.RefObject<DOMElement | null>

Returns UseBoxMetricsResult

useCursor

Place the terminal's cursor inside the output (for an IME); undefined hides it.

function useCursor(): {
    setCursorPosition: (position: CursorPosition | undefined) => void;
};

Returns { setCursorPosition: (position: CursorPosition \| undefined) => void; }

useFocus

Make this component focusable: Tab and Shift+Tab move focus between such components in registration order.

function useFocus({ isActive, autoFocus, id: customId }?: {
    isActive?: boolean;
    autoFocus?: boolean;
    id?: string;
}): {
    isFocused: boolean;
    focus: (id: string) => void;
};
ParameterType
{ isActive, autoFocus, id: customId } (optional){ isActive?: boolean; autoFocus?: boolean; id?: string; }

Returns { isFocused: boolean; focus: (id: string) => void; }

useFocusManager

function useFocusManager(): Pick<React.ContextType<typeof FocusContext>, 'enableFocus' | 'disableFocus' | 'focusNext' | 'focusPrevious' | 'focus' | 'activeId'>;

Returns Pick<React.ContextType<typeof FocusContext>, 'enableFocus' \| 'disableFocus' \| 'focusNext' \| 'focusPrevious' \| 'focus' \| 'activeId'>

useInput

Handle each key press, while isActive (default true): raw mode is on for as long as it is.

function useInput(handler: (input: string, key: Key) => void, options?: {
    isActive?: boolean;
}): void;
ParameterType
handler(input: string, key: Key) => void
options (optional){ isActive?: boolean; }

Returns void

usePaste

Handle each paste as one string, with bracketed paste on for as long as the hook is active.

function usePaste(handler: (text: string) => void, options?: {
    isActive?: boolean;
}): void;
ParameterType
handler(text: string) => void
options (optional){ isActive?: boolean; }

Returns void

useWindowSize

The terminal's size, re-read on every resize.

function useWindowSize(): WindowSize;

Returns WindowSize

Constants

Box

const Box: import("react").ForwardRefExoticComponent<Omit<Styles, "textWrap"> & {
    readonly children?: Node | undefined;
    readonly 'aria-label'?: string | undefined;
    readonly 'aria-hidden'?: boolean | undefined;
    readonly 'aria-role'?: string | undefined;
    readonly 'aria-state'?: Accessibility["state"] | undefined;
} & import("react").RefAttributes<DOMElement>>;

kittyFlags

kitty's progressive-enhancement flags.

const kittyFlags: {
    readonly disambiguateEscapeCodes: 1;
    readonly reportEventTypes: 2;
    readonly reportAlternateKeys: 4;
    readonly reportAllKeysAsEscapeCodes: 8;
    readonly reportAssociatedText: 16;
};

kittyModifiers

kitty's modifier bits: shift, alt, ctrl, super, hyper, meta, caps lock, num lock.

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;
};

useApp

const useApp: () => AppProps;

useIsScreenReaderEnabled

const useIsScreenReaderEnabled: () => boolean;

useStderr

const useStderr: () => StderrProps;

useStdin

const useStdin: () => Pick<StdinProps, "stdin" | "setRawMode" | "isRawModeSupported">;

useStdout

const useStdout: () => StdoutProps;

Interfaces

AnimationResult

interface AnimationResult {
    readonly frame: number;
    readonly time: number;
    readonly delta: number;
    readonly reset: () => void;
}

AppProps

interface AppProps {
    /** Exit (unmount) the whole app; an `Error` rejects `waitUntilExit()`, anything else resolves it. */
    readonly exit: (errorOrResult?: unknown) => void;
    /** Settles once pending render output has reached stdout. */
    readonly waitUntilRenderFlush: () => Promise<void>;
    /** Hand the terminal to a child process, then take it back and redraw. */
    readonly suspendTerminal: SuspendTerminal;
}

BoxMetrics

interface BoxMetrics {
    readonly width: number;
    readonly height: number;
    readonly left: number;
    readonly top: number;
    readonly clientWidth: number;
    readonly clientHeight: number;
}

CursorPosition

interface CursorPosition {
    x: number;
    y: number;
}

DOMElement

interface DOMElement {
    nodeName: ElementName;
    attributes: Record<string, unknown>;
    childNodes: DOMNode[];
    parentNode: DOMElement | undefined;
    style: Styles;
    /** The node's flex item; `undefined` for virtual text, which lays out inside its `Text`, and once freed. */
    yogaNode: FlexNode | undefined;
    /** Set by Suspense: the node keeps its place in the tree and takes no space. */
    isHidden?: boolean;
    internal_static?: boolean;
    internal_transform?: Transformer | undefined;
    internal_accessibility?: Accessibility;
    isStaticDirty?: boolean;
    staticNode?: DOMElement | undefined;
    previousStaticNode?: DOMElement | undefined;
    onComputeLayout?: (() => void) | undefined;
    onRender?: (() => void) | undefined;
    onImmediateRender?: (() => void) | undefined;
    onStaticChange?: (() => void) | undefined;
    internal_layoutListeners?: Set<LayoutListener>;
}

ElementMetrics

interface ElementMetrics {
    x: number;
    y: number;
    width: number;
    height: number;
    clientWidth: number;
    clientHeight: number;
}

Instance

interface Instance {
    rerender: (node: React.ReactNode) => void;
    unmount: () => void;
    waitUntilExit: () => Promise<unknown>;
    waitUntilRenderFlush: () => Promise<void>;
    cleanup: () => void;
    clear: () => void;
}

Key

interface Key {
    upArrow: boolean;
    downArrow: boolean;
    leftArrow: boolean;
    rightArrow: boolean;
    pageDown: boolean;
    pageUp: boolean;
    home: boolean;
    end: boolean;
    return: boolean;
    escape: boolean;
    ctrl: boolean;
    shift: boolean;
    tab: boolean;
    backspace: boolean;
    delete: boolean;
    meta: boolean;
    super: boolean;
    hyper: boolean;
    capsLock: boolean;
    numLock: boolean;
    eventType?: 'press' | 'repeat' | 'release' | undefined;
}

KittyKeyboardOptions

interface KittyKeyboardOptions {
    mode?: 'auto' | 'enabled' | 'disabled';
    flags?: KittyFlagName[];
}

NewlineProps

interface NewlineProps {
    /** Newlines to insert. Default 1. */
    readonly count?: number;
}

RenderMetrics

interface RenderMetrics {
    renderTime: number;
}

RenderOptions

interface RenderOptions {
    stdout?: NodeJS.WriteStream | NodeJS.WritableStream;
    stdin?: NodeJS.ReadStream | NodeJS.ReadableStream;
    stderr?: NodeJS.WriteStream | NodeJS.WritableStream;
    debug?: boolean;
    exitOnCtrlC?: boolean;
    patchConsole?: boolean;
    maxFps?: number;
    incrementalRendering?: boolean;
    concurrent?: boolean;
    isScreenReaderEnabled?: boolean;
    onRender?: (metrics: RenderMetrics) => void;
    kittyKeyboard?: KittyKeyboardOptions;
    interactive?: boolean;
    alternateScreen?: boolean;
}

RenderToStringOptions

interface RenderToStringOptions {
    /** Columns of the virtual terminal. Default 80. */
    columns?: number;
}

StaticProps

interface StaticProps<T> {
    readonly items: T[];
    readonly style?: Styles | undefined;
    readonly children: (item: T, index: number) => Node;
}

StderrProps

interface StderrProps {
    readonly stderr: NodeJS.WriteStream;
    readonly write: (data: string) => void;
}

StdinProps

interface StdinProps {
    readonly stdin: NodeJS.ReadStream;
    readonly setRawMode: (value: boolean) => void;
    readonly setBracketedPasteMode: (value: boolean) => void;
    readonly isRawModeSupported: boolean;
    readonly internal_exitOnCtrlC: boolean;
    readonly internal_eventEmitter: EventEmitter;
}

StdoutProps

interface StdoutProps {
    readonly stdout: NodeJS.WriteStream;
    readonly write: (data: string) => void;
}

SuspendTerminal

interface SuspendTerminal {
    (callback: () => void | Promise<void>): Promise<void>;
    (): Promise<TerminalSuspension>;
}

TerminalSuspension

The handle suspendTerminal() returns without a callback.

interface TerminalSuspension {
    readonly resume: () => Promise<void>;
    readonly [Symbol.asyncDispose]: () => Promise<void>;
}

TextProps

interface TextProps {
    readonly color?: string | undefined;
    readonly backgroundColor?: string | undefined;
    readonly dimColor?: boolean | undefined;
    readonly bold?: boolean | undefined;
    readonly italic?: boolean | undefined;
    readonly underline?: boolean | undefined;
    readonly strikethrough?: boolean | undefined;
    readonly inverse?: boolean | undefined;
    readonly wrap?: TextWrap | undefined;
    readonly children?: Node | undefined;
    readonly 'aria-label'?: string | undefined;
    readonly 'aria-hidden'?: boolean | undefined;
}

TransformProps

interface TransformProps {
    readonly transform: (children: string, index: number) => string;
    readonly accessibilityLabel?: string | undefined;
    readonly children?: Node | undefined;
}

WindowSize

interface WindowSize {
    readonly columns: number;
    readonly rows: number;
}

Types

BoxProps

type BoxProps = Omit<Styles, 'textWrap'> & {
    readonly children?: Node | undefined;
    readonly 'aria-label'?: string | undefined;
    readonly 'aria-hidden'?: boolean | undefined;
    readonly 'aria-role'?: string | undefined;
    readonly 'aria-state'?: Accessibility['state'] | undefined;
};

KittyFlagName

type KittyFlagName = keyof typeof kittyFlags;

UseBoxMetricsResult

type UseBoxMetricsResult = BoxMetrics & {
    readonly hasMeasured: boolean;
};

On this page