# tui-kit

Presentation-only [ratatui](https://docs.rs/ratatui) widgets shared by `runplan-tui`
and external consumers (e.g. Overdeck). Every widget takes plain data — no
knowledge of any app's control API, HTTP client, or state — and either
renders directly to a `Frame` or returns styled `Line`/`String` values for
the caller to compose. Colors always flow through `&Theme`; there are no
inline `ratatui::style::Color` literals outside `src/theme.rs`.

## Widgets

| Widget | Constructor / entry point | Inputs |
| --- | --- | --- |
| Tab bar | `tabs::render_tabs(frame, theme, area, items, active)` | `&[TabItem { label, dimmed }]`, active index |
| Selectable list rows | `table::render_one_line_rows(rows)` | `&[OneLineRow { text, selected }]` → `Vec<Line>` |
| Selectable list rows (detail) | `table::render_two_line_rows(theme, rows)` | `&[TwoLineRow { line1, line2, selected }]` → `Vec<Line>` |
| Footer key hints | `statusbar::key_hint_line(theme, pairs)` | `&[(key, label)]` → `Line` |
| Shortcut-letter highlight | `statusbar::label_with_shortcut(theme, label, key)` | label text, shortcut char → `Vec<Span>` |
| Progress meter | `meter::render_meter(done, total, width)` | counts, bar width → `String` |
| Label/value panel | `kv::render_kv_sections(sections, column)` | `&[KvSection { heading, rows: Vec<KvRow> }]` → `String` |
| Modal overlay | `overlay::render_modal(frame, title, text)` | title, body text |
| Scrollable help modal | `overlay::render_help_modal(frame, text, scroll)` | body text, scroll offset |
| Toast | `overlay::render_toast(frame, theme, area, text)` | message text |
| Scrollable pager | `pager::PagerState` (state) + associated key-handling methods | keyboard input, source lines |
| State glyph | `glyphs::StateGlyph` (enum) + `theme.state_color(glyph)` | task state |
| Command palette | `palette::render_palette(frame, theme, palette)` | `CommandPalette { input, items: Vec<PaletteItem { label, hint }>, selected }` |

The kit never filters or matches `CommandPalette::items` against `input` —
that logic (fuzzy or exact) belongs to the consuming app; the kit only
renders the items it is given.

See `examples/deck_sample.rs` for a full composition of tabs, table,
statusbar, meter, and palette under `Theme::deck()`.

## Theme tokens

Every widget takes `&Theme` (from `theme::Theme`). Built-in themes:
`Theme::runplan()` (pins the pre-extraction hardcoded palette) and
`Theme::deck()` (dark, blue-accented). Look one up by name with
`Theme::by_name(name)`; list all names with `Theme::names()`.

Token | Meaning
--- | ---
`bg` | Application background
`panel` | Panel/card background
`line` | Border and divider lines
`ink` | Primary text
`muted` | Secondary text
`dim` | Deemphasized text
`accent` | Interactive/highlight accent (key hints, active tab divider)
`ok` | Success state
`warn` | Warning state
`err` | Error state
`info` | Informational state
`teal` | Teal accent
`purple` | Purple accent
`selection_bg` | Selected-row background, where a widget paints one explicitly

## Using from an external crate

```toml
[dependencies]
tui-kit = { git = "https://github.com/alexcodeplace/mega-plan-harness.git" }
```

Cargo locates the crate by name inside the checked-out repository (it lives
at `tui/crates/tui-kit`), so no `path` key is needed — `git` and `path`
together on one dependency is rejected by Cargo as ambiguous.

`tui-kit` depends only on `ratatui` and `unicode-width` in its normal
dependency graph — no runtime, terminal-backend, or app-framework dependency
is pulled in.
