tuix
Version:
A performant TUI framework for Bun with JSX and reactive state management
573 lines (451 loc) β’ 15.8 kB
Markdown
A comprehensive TypeScript framework for building modern command-line applications and terminal user interfaces. Built with [Effect.ts](https://effect.website/) for functional programming and featuring JSX support with Svelte-inspired reactivity through runes.
- π― **Type-Safe CLI Framework**: Full TypeScript support with Zod validation
- π§© **JSX Terminal Components**: Svelte-inspired syntax with runes for reactive terminal UIs
- π¨ **Rich Styling System**: Colors, gradients, borders, and advanced styling
- β¨οΈ **Input & Mouse Handling**: Comprehensive event processing
- π **Plugin System**: Extensible architecture with hooks and middleware
- β‘ **Performance Optimized**: Lazy loading, caching, and efficient rendering
- π± **Responsive Layouts**: Adaptive designs for any terminal size
- π **Effect.ts Integration**: Functional programming with proper error handling
```bash
bun add tuix
```
```typescript
import { createCLI, z } from 'tuix'
const cli = createCLI({
name: 'my-app',
version: '1.0.0',
commands: {
hello: {
description: 'Say hello to someone',
args: {
name: z.string().describe('Name to greet')
},
handler: (args) => `Hello, ${args.name}!`
}
}
})
await cli.run(process.argv.slice(2))
```
```tsx
import { Text, Button, Box } from 'tuix/components'
const MyComponent = ({ name }: { name: string }) => {
let clickCount = $state(0)
return (
<Box border="rounded" padding={2}>
<Text color="cyan" bold>
Welcome to CLI-Kit, {name}! π
</Text>
<Text>Clicked {clickCount} times</Text>
<Button
variant="primary"
onClick={() => clickCount++}
>
Get Started
</Button>
</Box>
)
}
```
```typescript
import { Effect } from "effect"
import { runApp } from "tuix"
import { text, vstack } from "tuix"
import { style, Colors } from "tuix/styling"
import type { Component } from "tuix"
interface Model {
readonly count: number
}
type Msg = { readonly tag: "increment" }
const counterApp: Component<Model, Msg> = {
init: Effect.succeed([{ count: 0 }, []]),
update: (msg: Msg, model: Model) => {
switch (msg.tag) {
case "increment":
return Effect.succeed([{ ...model, count: model.count + 1 }, []])
}
},
view: (model: Model) => (
<div>
<Text color="cyan" bold>CLI-Kit Counter π―</Text>
<Text>Count: {model.count}</Text>
<Text color="gray">Press Space to increment, Ctrl+C to exit</Text>
</div>
)
}
runApp(counterApp)
```
TUIX provides two complementary approaches:
Type-safe command-line applications with argument parsing, validation, and plugins:
```
βββββββββββββββ Parse βββββββββββββββ Route βββββββββββββββ
β Raw Args β βββββββββββΊ β Parsed Args β βββββββββββΊ β Handler β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββ
β Validation β β Result β
β (Zod) β β (Any Type) β
βββββββββββββββ βββββββββββββββ
```
Interactive terminal applications following the **Model-View-Update (MVU)** pattern:
```
βββββββββββββββ Messages βββββββββββββββ
β View β βββββββββββββββΊ β Update β
β (JSX) β β (Pure Fn) β
β β βββββββββββββββ β β
βββββββββββββββ New Model βββββββββββββββ
β β
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββ
β Render β β Model β
β Terminal β β State β
βββββββββββββββ βββββββββββββββ
β
β
βββββββββββββββ β
β Subscriptionsβ ββββββββββββββββββββββ
β (Input/Time) β
βββββββββββββββ
```
Both frameworks are powered by **Effect.ts** for functional programming, error handling, and resource management, with **Svelte runes** providing reactive state management.
```tsx
// Text rendering with styling
<Text color="blue" bold italic>Styled text</Text>
// Layout containers
<Box border="rounded" padding={2} width={40}>
<div>Content goes here</div>
</Box>
// Flexible layouts
<div style={{ display: 'flex', flexDirection: 'column' }}>
<Text>Item 1</Text>
<Text>Item 2</Text>
</div>
```
```tsx
// Reactive state with runes (planned)
let count = $state(0)
let inputValue = $state('')
let selectedIndex = $state(0)
// Buttons with reactive callbacks
<Button variant="primary" onClick={() => count++}>
Clicked {count} times
</Button>
// Text input with callback handlers
<TextInput
value={inputValue}
onChange={(value) => inputValue = value}
placeholder="Enter text..."
validate={(value) => value.length > 0}
/>
// Selectable lists with callback handlers
<List
items={['Option 1', 'Option 2', 'Option 3']}
selected={selectedIndex}
onSelect={(index) => selectedIndex = index}
/>
```
```tsx
// Reactive data with runes (planned)
let tableData = $state([...])
let currentTab = $state(0)
let progress = $state(75)
// Tables with callback handlers
<Table
data={tableData}
columns={[
{ key: 'name', title: 'Name', sortable: true },
{ key: 'value', title: 'Value', sortable: true }
]}
onSort={(column) => /* handle sorting */}
onFilter={(column) => /* handle filtering */}
/>
// Tab navigation with callback handlers
<Tabs
activeTab={currentTab}
onTabChange={(index) => currentTab = index}
>
<Tab title="Tab 1">Content 1</Tab>
<Tab title="Tab 2">Content 2</Tab>
</Tabs>
// Progress indicators
<ProgressBar value={progress} max={100} />
<Spinner variant="dots" />
```
- **Modal**: Dialog boxes with backdrop (coming soon)
- **FilePicker**: File and directory selection (coming soon)
- **Help**: Keybinding help system (coming soon)
- **Viewport**: Scrollable content areas (coming soon)
## π¨ Styling System
CLI-Kit provides a comprehensive styling system with multiple approaches:
### JSX Style Props
```tsx
// Direct style props
<Text
color="blue"
backgroundColor="white"
bold
italic
underline
>
Styled text
</Text>
// CSS-like styling
<div style={{
color: 'rgb(255, 100, 100)',
backgroundColor: '#1a1a1a',
border: '1px solid cyan',
padding: '2px 4px',
margin: '1px',
textAlign: 'center'
}}>
CSS-styled content
</div>
```
```tsx
// Standard colors
<Text color="red">Red text</Text>
<Text color="brightCyan">Bright cyan text</Text>
// RGB colors
<Text color="rgb(255, 100, 50)">Custom RGB</Text>
// Hex colors
<Text color="#ff6432">Hex color</Text>
// Gradients
<Text gradient="linear-gradient(90deg, red, blue)">
Gradient text
</Text>
```
```tsx
// Border styles
<Box border="single">Single border</Box>
<Box border="double">Double border</Box>
<Box border="rounded">Rounded border</Box>
<Box border="thick">Thick border</Box>
// Padding and margins
<Box padding={2} margin={1}>
Spaced content
</Box>
// Flexible layouts
<div style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center'
}}>
<Text>Left</Text>
<Text>Right</Text>
</div>
```
```typescript
import { style, Colors, createGradient } from 'tuix/styling'
// Function-based styling
const myStyle = style()
.color(Colors.blue)
.backgroundColor(Colors.white)
.bold()
.padding(2)
// Gradient creation
const gradient = createGradient({
type: 'linear',
angle: 90,
stops: [
{ color: Colors.red, position: 0 },
{ color: Colors.blue, position: 100 }
]
})
```
```typescript
// Standard ANSI colors
'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'
// Bright variants
'brightBlack', 'brightRed', 'brightGreen', 'brightYellow'
'brightBlue', 'brightMagenta', 'brightCyan', 'brightWhite'
// Extended colors
'gray', 'darkGray', 'lightGray'
// True color support
'rgb(255, 100, 50)'
'#ff6432'
'hsl(120, 50%, 75%)'
```
Handle keyboard and mouse events through subscriptions:
```typescript
subscriptions: (model: Model) =>
Effect.gen(function* (_) {
const input = yield* _(InputService)
return input.mapKeys(key => {
switch (key.key) {
case 'enter': return { tag: "submit" }
case 'escape': return { tag: "cancel" }
case 'tab': return { tag: "nextField" }
case 'up': return { tag: "moveUp" }
case 'down': return { tag: "moveDown" }
case 'ctrl+c': process.exit(0)
default: return null
}
})
})
```
```typescript
interface KeyEvent {
readonly key: string // 'a', 'enter', 'ctrl+c', 'shift+tab'
readonly ctrl: boolean // Ctrl modifier
readonly shift: boolean // Shift modifier
readonly alt: boolean // Alt modifier
readonly meta: boolean // Meta/Cmd modifier
}
```
Enable mouse support in your runtime config:
```typescript
const config: RuntimeConfig = {
enableMouse: true,
// ... other options
}
```
Mouse events are captured but coordinate-to-component routing is still in development.
Check out the `examples/` directory for real-world TUIX applications:
- **Git Dashboard** - Multi-panel git repository management (inspired by lazygit)
- **Process Monitor** - Real-time system monitoring (inspired by htop)
- **Log Viewer** - Streaming log analysis with filtering (inspired by lnav)
- **Package Manager** - Package management interface (inspired by npm/yarn)
### UI Pattern Libraries
- **Contact Form** - Form handling and validation patterns
- **Layout Patterns** - Layout composition and responsive design
### Component Showcases
- **Table Showcase** - Data table with sorting and filtering
- **Tabs Showcase** - Tab navigation and multi-view interfaces
### Quick Start
```bash
# List all available examples
bun run examples
# Run specific examples with convenient scripts
bun run example:git-dashboard
bun run example:process-monitor
bun run example:log-viewer
bun run example:package-manager
# Or run directly
bun examples/git-dashboard.ts
```
### Testing Examples
```bash
# Quick test all examples (3s timeout each)
bun run examples:test
# Run e2e tests for examples
bun run test:e2e:all
```
## π§ Configuration
### RuntimeConfig Options
```typescript
interface RuntimeConfig {
readonly fps?: number // Target FPS (default: 60)
readonly debug?: boolean // Enable debug logging
readonly quitOnEscape?: boolean // Quit on ESC key
readonly quitOnCtrlC?: boolean // Quit on Ctrl+C
readonly enableMouse?: boolean // Enable mouse support
readonly fullscreen?: boolean // Use alternate screen buffer
}
```
For most applications:
```typescript
const config: RuntimeConfig = {
fps: 30, // Good balance of responsiveness and performance
quitOnCtrlC: true, // Standard quit behavior
fullscreen: true, // Clean fullscreen experience
enableMouse: false // Enable if you need mouse support
}
```
- **Efficient Rendering**: Only re-renders when the model changes
- **Stream-Based**: Uses Effect streams for efficient event processing
- **Memory Safe**: Automatic cleanup of resources and subscriptions
- **Fiber-Based**: Non-blocking concurrent processing
```bash
git clone https://github.com/cinderlink/tuix
cd tuix
bun install
```
```bash
bun test
```
```
src/
βββ core/
βββ components/
βββ styling/
βββ services/
βββ testing/
examples/
docs/
```
- `runApp(component, config)` - Start your application
- `text(content, style?)` - Create styled text
- `vstack(...views)` - Vertical layout
- `hstack(...views)` - Horizontal layout
- `box(content, options)` - Container with borders
Every component must implement:
```typescript
interface Component<Model, Msg> {
init: Effect<[Model, Cmd<Msg>[]], never, AppServices>
update: (msg: Msg, model: Model) => Effect<[Model, Cmd<Msg>[]], never, AppServices>
view: (model: Model) => View
subscriptions?: (model: Model) => Effect<Sub<Msg>, never, AppServices>
}
```
This is an active development project. Some features are still being implemented:
- β
**CLI Framework**: Complete command parsing, routing, and validation
- β
**JSX Runtime**: Full JSX support with Svelte-inspired runes for reactive terminal UIs
- β
**Plugin System**: Extensible architecture with hooks and middleware
- β
**Performance Optimizations**: Lazy loading, caching, and efficient rendering
- β
**Core Components**: Text, Button, Box, List, Table, Tabs, ProgressBar, Spinner
- β
**Advanced Styling**: Colors, gradients, borders, layouts, and CSS-like styling
- β
**Type Safety**: Full TypeScript support with proper generics and Effect.ts integration
- β
**Input & Mouse Handling**: Comprehensive event processing system
- β
**Testing Framework**: Comprehensive test utilities and coverage
- π§ **Documentation**: Comprehensive guides and API reference
- π§ **Mouse Routing**: Coordinate-to-component mouse event routing
- π§ **Examples**: Real-world application examples and tutorials
- π **Modal/Dialog**: Overlay components with backdrop
- π **Viewport**: Scrollable content areas for large datasets
- π **FilePicker**: File and directory selection components
- π **Help System**: Interactive keybinding help and documentation
- π **Themes**: Comprehensive theming system and presets
- π **Animation**: Smooth transitions and loading animations
---
**Built with Bun and Effect for modern TypeScript development**
*TUIX is a play on "Twix" candy, referencing our .tuix file extension for reactive terminal UI components*