ScrollBox drops its `wheel`, `keyboard`, and `linesPerWheel` props and instead exposes an imperative handle (`ScrollBoxExpose`): scrollToLine / scrollByLines / scrollToTop / scrollToBottom. It listens to no mouse or keyboard input itself — the consumer wires its own bindings to the handle. Built-in input is deferred because best practice isn't settled: the mouse wheel needs terminal mouse tracking (which suppresses native text selection window-wide), and keyboard input is global (collides with a focused field). Shipping only the scroll mechanism keeps the component honest and lets the app own input policy. The core bounded, sticky-following viewport still works with no props.
@vue-tui/components
High-level Vue components for vue-tui, composed from
@vue-tui/runtime primitives.
Early days — the component set is small and growing. Currently:
ScrollBox,Spinner.
Install
npm install @vue-tui/components
# peer deps: @vue-tui/runtime, vue ^3.4
Spinner
An animated loading spinner.
<script setup lang="ts">
import { Spinner } from "@vue-tui/components";
</script>
<template>
<Spinner type="dots" label="Loading" color="green" />
</template>
Props
| prop | type | default | description |
|---|---|---|---|
type |
preset name (e.g. "dots", "line") |
"dots" |
a built-in spinner animation |
frames |
string[] |
— | custom animation frames (overrides type) |
interval |
number |
preset's | ms between frames |
color |
string |
— | chalk color for the spinner glyph |
label |
string |
— | text shown next to the spinner |
ScrollBox
A bounded viewport that follows the bottom of its content. The core behavior — clip overflow and stick to the latest line as content grows — needs no props. It listens to no input itself: scroll it through the exposed imperative handle, and bind your own keys / mouse to that.
<script setup lang="ts">
import { shallowRef } from "vue";
import { ScrollBox, type ScrollBoxExpose } from "@vue-tui/components";
import { Text, useInput } from "@vue-tui/runtime";
const box = shallowRef<ScrollBoxExpose>();
// ScrollBox ships no built-in wheel/keyboard — wire your own keys to the handle.
useInput((_input, key) => {
if (key.upArrow) box.value?.scrollByLines(-1);
if (key.downArrow) box.value?.scrollByLines(1);
});
</script>
<template>
<ScrollBox ref="box">
<Text v-for="line in lines" :key="line">{{ line }}</Text>
</ScrollBox>
</template>
Imperative handle (ScrollBoxExpose)
ScrollBox has no props; grab its handle with a template ref and drive scrolling:
| action | description |
|---|---|
scrollToLine(line) |
scroll so content line line is at the top (clamped) |
scrollByLines(lines) |
scroll by lines relative to the current position (+ = down) |
scrollToTop() |
jump to the top |
scrollToBottom() |
jump to the bottom and resume following new content |
Why no built-in wheel / keyboard: the mouse wheel needs terminal mouse tracking, which breaks
native text selection window-wide; keyboard input is global and collides with a focused field. So
input policy is the app's to decide. For inline streaming output, prefer Static (let it flow into
the terminal's own scrollback).
License
MIT