Files
vue-tui/packages/runtime/README.md
T
Yunfei He e4f756def2 chore(runtime): prepare 0.1.0 public beta release (#205)
Re-applies the 0.1.0 release prep on top of current main. PR #167's branch
(release/runtime-0.1.0) was 35 commits behind main and predated the #173..#204
fix batch (incl. the severe renderer fixes #198/#199), so publishing from it
would have shipped a 0.1.0 missing those fixes.

- version 0.0.3 -> 0.1.0 (runtime only; testing/cli stay 0.0.x)
- add root LICENSE + packages/runtime/LICENSE (MIT)
- add packages/runtime/CHANGELOG.md (0.1.0 public API; ./internal is non-semver)
- npm metadata: author, repository(+directory), homepage, bugs, keywords
- engines.node >=22 -> >=22.18.0 (match the real toolchain floor)
- files: ship LICENSE explicitly alongside dist + CHANGELOG
- README: reframe to public-beta status; fix useCursor (position-based, not
  visibility); add useIsScreenReaderEnabled + renderToString to the API docs

Verified on this branch: build, type-check, lint (0 warnings), and the full test
suite (runtime 1289, cli 364, testing 12, PTY 129) all green. pnpm pack ships
LICENSE + CHANGELOG + dist with 0 literal `catalog:` deps; attw resolves types
green under node16(ESM) + bundler for `.` and `./internal`.

Note: `exports` is auto-generated by `vp pack` (pack.exports: true) as bare
strings; attw confirms types resolve via the sibling .d.mts, so no manual
types condition is added (it would be wiped by the next build anyway).

Supersedes #167.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-20 00:32:56 +08:00

5.7 KiB

@vue-tui/runtime

Public beta (0.1) — the @vue-tui/runtime API is entering stabilization: usable and broadly stable, but may still change before 1.0. The CLI and dev tooling remain experimental and may change between releases. Feedback and bug reports are very welcome — they directly shape what we lock down next. Not yet recommended for production use.

Vue 3 terminal renderer with Yoga flexbox layout — build rich TUI apps with the same component model you use on the web.

npm version npm downloads

Why

  • Vue SFC & JSX<template>, TSX, or render functions — your choice
  • Yoga flexbox — the same layout engine behind React Native, not a CSS-subset hack
  • Built-in input system — keyboard handling, focus management, Tab navigation
  • Terminal-native — renders directly to stdout, purpose-built for CLI tools and AI agent interfaces

@vue-tui/runtime is a terminal platform renderer parallel to @vue/runtime-dom, comparable to React Ink but adapted for Vue's reactivity model.

Install

npm install @vue-tui/runtime vue

Quick Start

// src/main.ts
import { createApp } from "@vue-tui/runtime";
import App from "./app.vue";

createApp(App).mount();
<!-- src/app.vue -->
<script setup lang="ts">
import { shallowRef } from "vue";
import { Box, Text, useInput } from "@vue-tui/runtime";

const count = shallowRef(0);

useInput((input) => {
  if (input === "+") count.value++;
  if (input === "-") count.value--;
});
</script>

<template>
  <Box>
    <Text>Count: </Text>
    <Text bold color="green">{{ count }}</Text>
    <Text dimColor> (+/- to change)</Text>
  </Box>
</template>

Components

Component Description
<Box> Flexbox container — direction, wrap, align, justify, gap, padding, margin, borders, background
<Text> Styled text — color, bold, italic, underline, strikethrough, dimColor, wrap/truncate modes
<Spacer> Expands to fill available space (flex-grow: 1)
<Newline> Inserts line breaks (configurable count)
<Static> Renders a list of items once, above the redrawn region
<Transform> Applies a string transform function to each rendered line

Composables

Composable Description
useInput(handler, opts?) Keyboard input — (input, key) with modifier and arrow key detection
useFocus(opts?) Component-level focus — returns { isFocused, focus }
useFocusManager() App-level focus — focusNext(), focusPrevious(), focus(id)
useApp() App lifecycle — { exit(error?), waitUntilRenderFlush() }
useWindowSize() Reactive terminal dimensions — { columns, rows }
useAnimation(opts?) Frame-based animation loop — returns { frame, time, delta, reset }
useBoxMetrics(ref) Reactive layout metrics — { width, height, left, top, hasMeasured }
measureElement(node) Imperative read of computed { width, height } from a yoga node
useCursor() Position the terminal cursor — returns setCursorPosition(pos); pass undefined to hide it
usePaste(handler, opts?) Handle clipboard paste events
useStdin() Access stdin stream and raw mode control
useStdout() Write directly to stdout
useStderr() Write directly to stderr
useIsScreenReaderEnabled() Reactive boolean — whether screen-reader / accessibility mode is active

App Lifecycle

import { createApp } from "@vue-tui/runtime";

// Fire and forget (most common):
createApp(App).mount();

// Wait for the app to exit:
const app = createApp(App);
app.mount();
await app.waitUntilExit();

// Custom streams (for testing):
createApp(App).mount({ stdout, stdin, stderr });

Render to String

Render a component to a single output frame without driving a live terminal — useful for snapshots, logging, or non-interactive output:

import { renderToString } from "@vue-tui/runtime";

const frame = renderToString(App); // synchronous, returns a string

License

MIT