@jsvision/ui / createEventLoop
Function: createEventLoop()
createEventLoop(
viewport,opts):EventLoop
Defined in: ui/src/event/event-loop.ts:617
Create an event loop over a viewport of the given size.
The loop is host-agnostic: you drive it by feeding decoded input to EventLoop.dispatch and reading loop.renderRoot.buffer() for the composed frame — no terminal required, which is what makes it usable headlessly and in tests. To connect it to a real terminal, wire the onFrame/ onCaret/writeClipboard sinks to a host, or use createApplication, which does that for you.
Parameters
viewport
The initial viewport size in cells.
opts
Required caps, plus optional theme/logger/keymap/commands/onIdle and more.
Returns
An EventLoop ready to mount a view tree and be driven with dispatch.
Example
ts
import { resolveCapabilities } from '@jsvision/core';
import { View, Group, createEventLoop, type DrawContext, type DispatchEvent } from '@jsvision/ui';
// A minimal focusable widget that reacts to Enter.
class Button extends View {
focusable = true;
constructor(private label: string, private onEnter: () => void) { super(); }
draw(ctx: DrawContext) {
ctx.text(1, 0, `${this.state.focused ? '>' : ' '} ${this.label}`, ctx.color('button'));
}
override onEvent(ev: DispatchEvent) {
if (ev.event.type === 'key' && ev.event.key === 'enter') { this.onEnter(); ev.handled = true; }
}
}
const caps = resolveCapabilities({ env: {}, platform: 'linux' }).profile;
const loop = createEventLoop({ width: 40, height: 10 }, { caps });
const root = new Group();
root.add(new Button('OK', () => loop.emitCommand('ok')));
loop.mount(root);
// Feed input: focus the button, then press Enter to emit the 'ok' command.
loop.focusNext();
loop.dispatch({ type: 'key', key: 'enter', ctrl: false, alt: false, shift: false });
// Read the composed frame (headless — no terminal needed).
const rows = loop.renderRoot.buffer().rows();