# lv-tui

A reactive TUI framework for Rust. Component tree, reactive state, CSS-like styling, event bubbling, focus management — everything you need to build complex terminal applications.

```rust
use lv_tui::prelude::*;
use lv_tui::Component;

#[derive(Component)]
struct Counter {
    #[reactive(paint, copy)]
    count: i32,
}

impl Counter {
    fn new() -> Self { Self { count: 0 } }

    fn render(&self, cx: &mut RenderCx) {
        cx.line(format!("count: {}", self.get_count()));
        cx.line("press + to increment, q to quit");
    }

    fn event(&mut self, event: &Event, cx: &mut EventCx) {
        if event.is_key(Key::Char('+')) { self.set_count(self.get_count() + 1, cx); }
        if event.is_key(Key::Char('q')) { cx.quit(); }
    }
}

fn main() -> lv_tui::Result<()> {
    App::new(Counter::new()).run()
}
```

## Features

- **Component tree** — compose UIs with Column, Row, Stack, Block, Scroll, Overlay
- **Reactive state** — `#[reactive(paint)]` auto-triggers repaint on change
- **Event bubbling** — Capture → Target → Bubble with `stop_propagation()`
- **Focus management** — Tab/Shift+Tab navigation with Focus/Blur events
- **CSS-like stylesheets** — type/class/id selectors with style inheritance
- **Unicode** — CJK/Emoji wide characters, text wrap, truncation, alignment
- **Async tasks** — `cx.spawn()` for background work with TaskComplete events
- **Debug view** — press `d` to visualize component borders and labels

## Widgets

| Widget | Description |
|--------|-------------|
| `Label` | Text display with styling |
| `Input` | Single-line text input with cursor |
| `Column` | Vertical layout container |
| `Row` | Horizontal layout container |
| `Stack` | Layered/z-order container |
| `Block` | Border + padding wrapper with optional title |
| `Scroll` | Scrollable content container |
| `Overlay` | Modal dialog with background dimming |
| `Table` | Data table with headers, selection, and sorting |
| `Tabs` | Tabbed container with keyboard navigation |
| `Select` | Dropdown with keyboard navigation |
| `Checkbox` | Toggleable boolean with label |
| `RadioGroup` | Mutually exclusive radio selection |
| `ProgressBar` | Unicode 8-segment progress bar |
| `Dialog` | Border + key bindings (Esc/Enter) wrapper |
| `SplitPane` | Resizable split panels (Ctrl+arrows) |
| `VirtualList` | Virtual-scrolling list for large datasets |

## Getting Started

### Quick example

Create a settings form with checkboxes, radio group, and keyboard navigation:

```rust
use lv_tui::prelude::*;
use lv_tui::widgets::*;

struct App { content: Column }

impl App {
    fn new() -> Self {
        Self {
            content: Column::new()
                .child(Label::new("Settings").style(Style::default().bold()))
                .child(Label::new(""))
                .child(Checkbox::new("Enable notifications"))
                .child(Checkbox::new("Auto-save").checked())
                .child(Label::new(""))
                .child(Label::new("Theme:"))
                .child(RadioGroup::new(vec![
                    "Light".into(), "Dark".into(), "System".into(),
                ]))
                .child(Label::new(""))
                .child(Label::new("Tab: switch  Space: toggle  q: quit")
                    .style(Style::default().fg(Color::Gray))),
        }
    }
}

impl Component for App {
    fn render(&self, cx: &mut RenderCx) { self.content.render(cx); }
    fn event(&mut self, e: &Event, cx: &mut EventCx) {
        if e.is_key(Key::Char('q')) { cx.quit(); return; }
        self.content.event(e, cx);
    }
    fn layout(&mut self, r: lv_tui::geom::Rect, cx: &mut lv_tui::component::LayoutCx) { self.content.layout(r, cx); }
    fn measure(&self, c: lv_tui::layout::Constraint, _cx: &mut lv_tui::component::MeasureCx) -> lv_tui::geom::Size {
        lv_tui::geom::Size { width: c.max.width, height: c.max.height }
    }
    fn focusable(&self) -> bool { false }
}

fn main() -> lv_tui::Result<()> {
    lv_tui::app::App::new(App::new()).run()
}
```

### Theme support

```rust
use lv_tui::prelude::*;

fn main() -> lv_tui::Result<()> {
    set_theme(Theme::Light); // or Theme::Dark (default)
    // ... rest of app
}
```

### Clipboard

```rust
fn event(&mut self, event: &Event, cx: &mut EventCx) {
    // Copy selected text to system clipboard (OSC 52)
    cx.copy_to_clipboard("copied text");
}
```

```toml
[dependencies]
lv-tui = "0.1"
```

```bash
cargo run --example counter
cargo run --example demo_app
```

## License

MIT
