UNPKG

tuix

Version:

A performant TUI framework for Bun with JSX and reactive state management

573 lines (451 loc) β€’ 15.8 kB
# TUIX 🎨 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. ## ✨ Features - 🎯 **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 ## πŸš€ Quick Start ### Installation ```bash bun add tuix ``` ### Create Your First CLI ```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)) ``` ### JSX Terminal UI with Runes ```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> ) } ``` ### Advanced TUI Application ```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) ``` ## πŸ—οΈ Architecture TUIX provides two complementary approaches: ### 1. CLI Framework Type-safe command-line applications with argument parsing, validation, and plugins: ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Parse β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Route β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Raw Args β”‚ ──────────► β”‚ Parsed Args β”‚ ──────────► β”‚ Handler β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β–Ό β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Validation β”‚ β”‚ Result β”‚ β”‚ (Zod) β”‚ β”‚ (Any Type) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### 2. TUI Framework 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. ## 🧩 JSX Components ### Core Elements ```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> ``` ### Interactive Components ```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} /> ``` ### Data Display ```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" /> ``` ### Advanced Components - **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> ``` ### Advanced Color System ```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> ``` ### Layout and Borders ```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> ``` ### Programmatic Styling ```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 } ] }) ``` ### Available Colors ```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%)' ``` ## ⌨️ Input Handling 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 } }) }) ``` ### Key Event Properties ```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 } ``` ## πŸ–±οΈ Mouse Support 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. ## πŸ“ Examples Check out the `examples/` directory for real-world TUIX applications: ### Real-World 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 } ``` ### Recommended Settings 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 } ``` ## πŸƒβ€β™‚οΈ Performance - **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 ## 🀝 Development ### Development Setup ```bash git clone https://github.com/cinderlink/tuix cd tuix bun install ``` ### Running Tests ```bash bun test ``` ### Project Structure ``` src/ β”œβ”€β”€ core/ # Core framework (runtime, types, view) β”œβ”€β”€ components/ # Built-in UI components β”œβ”€β”€ styling/ # Styling system and themes β”œβ”€β”€ services/ # Input, rendering, and system services └── testing/ # Test utilities examples/ # Example applications docs/ # Documentation ``` ## πŸ“š API Reference ### Core Functions - `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 ### Component Interface 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> } ``` ## 🚧 Current Status This is an active development project. Some features are still being implemented: ### βœ… Completed - βœ… **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 ### 🚧 In Progress - πŸ”§ **Documentation**: Comprehensive guides and API reference - πŸ”§ **Mouse Routing**: Coordinate-to-component mouse event routing - πŸ”§ **Examples**: Real-world application examples and tutorials ### πŸ“‹ Planned - πŸ“‹ **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*