@open-composer/multiplexer
v0.1.1
Published
A tmux-like terminal multiplexer component for Ink applications.
Downloads
6
Readme
@open-composer/multiplexer
A tmux-like terminal multiplexer component for Ink applications.
Features
- 🔀 Split terminals horizontally and vertically
- 🎯 Focus management with keyboard navigation
- 🎨 Customizable borders and titles
- ⌨️ tmux-like key bindings (Ctrl+B prefix)
- 📺 Full-screen mode with alternate screen buffer
- 🔄 Nested splits for complex layouts
- 📏 Flexible sizing (percentage, fractions, or auto)
Installation
bun add @open-composer/multiplexer @open-composer/terminalUsage
Simple Horizontal Split
import { Multiplexer } from '@open-composer/multiplexer';
import { render } from 'ink';
const layout = {
type: 'split',
id: 'root',
direction: 'horizontal',
children: [
{
type: 'pane',
id: 'left',
command: 'bash',
args: ['-i'],
title: 'Left Pane',
focus: true,
},
{
type: 'pane',
id: 'right',
command: 'htop',
title: 'Right Pane',
},
],
};
render(
<Multiplexer layout={layout} enterFullScreen={true} />,
{
patchConsole: false,
exitOnCtrlC: false,
}
);Vertical Split
const layout = {
type: 'split',
id: 'root',
direction: 'vertical',
children: [
{
type: 'pane',
id: 'top',
command: 'bash',
args: ['-i'],
title: 'Top',
},
{
type: 'pane',
id: 'bottom',
command: 'npm',
args: ['run', 'dev'],
title: 'Bottom',
},
],
};Complex Nested Layout
const layout = {
type: 'split',
id: 'root',
direction: 'horizontal',
children: [
{
type: 'pane',
id: 'main',
command: 'bash',
args: ['-i'],
size: '70%',
title: 'Main',
focus: true,
},
{
type: 'split',
id: 'sidebar',
direction: 'vertical',
size: '30%',
children: [
{
type: 'pane',
id: 'top-right',
command: 'git',
args: ['log', '--oneline', '--graph'],
title: 'Git Log',
},
{
type: 'pane',
id: 'bottom-right',
command: 'npm',
args: ['run', 'test', '--', '--watch'],
title: 'Tests',
},
],
},
],
};Custom Sizing
const layout = {
type: 'split',
id: 'root',
direction: 'horizontal',
children: [
{ type: 'pane', id: 'left', command: 'bash', size: '1/3' }, // 33%
{ type: 'pane', id: 'middle', command: 'bash', size: '1/3' }, // 33%
{ type: 'pane', id: 'right', command: 'bash', size: '1/3' }, // 33%
],
};Key Bindings
The multiplexer uses tmux-like key bindings with a prefix key (default: Ctrl+B):
| Keys | Description |
|------|-------------|
| Ctrl+B, ? | Show help modal |
| Ctrl+B, n or o | Navigate to next pane |
| Ctrl+B, p | Navigate to previous pane |
| Ctrl+B, → or ↓ | Navigate to next pane (arrow keys) |
| Ctrl+B, ← or ↑ | Navigate to previous pane (arrow keys) |
| Ctrl+B, d or x | Exit multiplexer |
| Ctrl+C (twice) | Safe exit (press twice within 1 second) |
| Ctrl+Q | Quick exit (no prefix needed) |
API
Multiplexer Component
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| layout | Layout | - | Layout configuration (required) |
| width | number | terminal width | Terminal width |
| height | number | terminal height | Terminal height |
| showHelp | boolean | true | Show help text at bottom |
| showBorders | boolean | false | Show pane borders |
| prefixKey | string | 'b' | Prefix key for commands (e.g., 'b' for Ctrl+B) |
| enterFullScreen | boolean | false | Use alternate screen buffer (like tmux) |
Layout Types
Pane
interface Pane {
type: 'pane';
id: string;
command: string;
args?: string[];
cwd?: string;
env?: Record<string, string>;
size?: string | number; // "50%", "1/2", or absolute number
focus?: boolean; // Initially focused
title?: string;
interactive?: boolean; // Default: true
}Split
interface Split {
type: 'split';
id: string;
direction: 'horizontal' | 'vertical';
children: (Pane | Split)[];
size?: string | number; // "50%", "1/2", or absolute number
}Full Screen Mode
When enterFullScreen={true}, the multiplexer uses the terminal's alternate screen buffer, providing a true tmux-like experience:
- No scrolling with previous terminal history
- Clean exit returns to previous screen state
- No persistent output after exit
render(
<Multiplexer layout={layout} enterFullScreen={true} />,
{
patchConsole: false,
exitOnCtrlC: false, // Let multiplexer handle its own exit
}
);Testing
# Run tests
bun test
# Run tests with coverage
bun test --coverage
# Update snapshots
bun test --update-snapshotsLicense
MIT
