# hefesto-widgets
[](https://crates.io/crates/hefesto-widgets)
[](https://opensource.org/licenses/MIT)
Widgets reutilizables para interfaces TUI construidas con [ratatui](https://crates.io/crates/ratatui), orientados al ecosistema **Hefesto**. Proporcionan componentes modulares, stateful y configurables para construir asistentes interactivos en terminal.
---
## Dependencias
Solo requiere `ratatui ≥ 0.30`.
```toml
[dependencies]
hefesto-widgets = "0.5.0"
```
## Componentes
### `Popup` — Popup base reutilizable
Caja de diálogo centrada con borde redondeado, título opcional, contenido multilínea y soporte para color de fondo (`bg_color`). Soporta modos de tamaño `Fixed`, `Percent`, `Auto` y `Max`.
```rust
use hefesto_widgets::{Popup, PopupSize};
let popup = Popup::new(Color::White)
.title("Aviso")
.content(vec![Line::from("Operación completada")])
.width(PopupSize::Fixed(44));
```
| `.title()`, `.border_color()`, `.border_type()` | Configuración de apariencia |
| `.bg_color()` | Color de fondo de todo el popup (incluye borde) |
| `.position()`, `.origin()` | Posicionamiento explícito |
| `.content()`, `.empty_message()` | Contenido interno |
### `BorderType` — Estilos de borde
`Plain`, `Rounded`, `Double`, `Thick`, `QuadrantInside`, `QuadrantOutside`, `None`.
### `ChoosePopup` — Lista seleccionable con filtro inline
Popup que muestra una lista de ítems `(String, Style)`. El usuario puede navegar, seleccionar múltiples entradas (con límite opcional `max_selected`) y filtrar con un campo de texto integrado. Cada ítem seleccionado se marca con ✓.
| `new(items)` | Crea el popup con la lista de ítems |
| `.title()`, `.border_color()`, `.bg_color()` | Configuración de apariencia |
| `.filter_placeholder()`, `.filter_rows()` | Configuración del campo de búsqueda |
| `.max_selected(n)` | Limita selección múltiple |
**State:** `ChoosePopupState` expone `cursor`, `chosen_indices`, `show_filter`, y delegados a `TextInputState` para el filtro.
### `ConfirmationPopup` — Diálogo de confirmación
Popup compacto (44×9) con título, cuerpo, y dos botones (confirmar/cancelar) con fondos de color personalizables. Implementa `Widget` (sin estado).
```rust
use hefesto_widgets::ConfirmationPopup;
ConfirmationPopup::new()
.title("Eliminar archivo")
.body(vec![Line::from("¿Está seguro?")])
.confirm_style(Style::new().bg(Color::Red).fg(Color::Black));
```
| `.title()`, `.border_color()`, `.bg_color()` | Configuración de apariencia |
| `.body()`, `.options()` | Contenido y etiquetas |
| `.confirm_style()`, `.cancel_style()` | Estilo de botones |
### `ThemedConfirmationPopup` — Confirmación con variante semántica
Wrapping de `ConfirmationPopup` que asigna colores según la variante: `Success`, `Warning`, `Danger` o `None`. Recibe título y cuerpo en el constructor.
```rust
use hefesto_widgets::{ThemedConfirmationPopup, ConfirmationVariant};
ThemedConfirmationPopup::new(
"Peligro",
vec![Line::from("Esta operación no se puede deshacer")],
ConfirmationVariant::Danger,
);
```
| `.options()` | Etiquetas de botones |
| `.border_type()` | Estilo de borde |
| `.bg_color()` | Color de fondo del popup |
| `.position()` | Posicionamiento explícito |
### `TextInputPopup` — Popup de entrada de texto
Popup que envuelve un `TextInput` para capturar texto del usuario. Hereda toda la configuración del `TextInput` (cursor, borde, placeholder, scroll) y del `Popup` (título, borde, posición, fondo).
| `.title()`, `.border_color()`, `.bg_color()` | Configuración del popup |
| `.input_bg_color()` | Fondo del área de texto (`TextInput`) |
| `.cursor_style()`, `.text_style()`, `.placeholder()` | Configuración del `TextInput` |
> ⚠️ **Breaking change:** en versiones anteriores `bg_color()` aplicaba fondo al `TextInput`. Ahora `bg_color()` aplica al popup y `input_bg_color()` al input.
### `SpinPopup` — Indicador de progreso con spinner
Popup que muestra un spinner animado (variantes: `Dots`, `Line`, `Dots2`, `Bounce`, `Pulse`, `Arrows`, `Square`, `Clock`), un título, el comando en ejecución, líneas de salida en un `ScrollList` y un mensaje de finalización. Útil para operaciones asíncronas.
| `.title()` | Título descriptivo |
| `.command()` | Comando que se está ejecutando |
| `.variant(SpinVariant)` | Estilo de animación |
| `.output_lines()` | Líneas de log a mostrar |
| `.max_output_rows()` | Límite de líneas visibles |
| `.finished_msg()` | Mensaje al completar (Enter) |
| `.bg_color()` | Color de fondo del popup |
### `FileBrowserPopup` — Navegador de archivos
Popup que presenta un explorador de directorios. Construido sobre `ChoosePopup`: navega entre directorios, muestra archivos con iconos (`📁`/`📄`), filtra por nombre y soporta selección múltiple. Oculta archivos ocultos (`.` por defecto) salvo que se active `show_hidden`.
| `.border_color()`, `.border_type()`, `.bg_color()` | Configuración de apariencia |
| `.dir_style()`, `.file_style()`, `.highlight_style()` | Estilo visual |
| `.dir_icon()`, `.file_icon()` | Iconos personalizados |
| `.max_selected(n)` | Límite de selección |
**State:** `FileBrowserState` gestiona la navegación: `navigate_to()`, `go_up()`, `enter_directory()`, `selected_entry()`, `chosen_paths()`, más toda la API de filtro delegada.
### `ScrollList` — Lista desplazable
Lista virtual con scrollbar vertical automático. Soporta tres constructores:
| `new(Vec<String>)` | Ítems simples |
| `new_styled(Vec<(String, Style)>)` | Ítems con estilo individual |
| `new_list(Vec<ListItem>)` | Ítems preconstruidos (árboles, indentación) |
Incluye `follow` mode (autoscroll al final) útil para logs.
**State:** `ScrollListState` con `select()`, `next()`, `previous()`, `last()`.
### `Tree` — Árbol expandible/colapsable
Proyecta una jerarquía de `TreeNode` en una `ScrollList` plana con indentación e iconos de expandir/colapsar/hoja. Los nodos se identifican por `id` (entero único).
```rust
use hefesto_widgets::{Tree, TreeNode, TreeState};
let tree = Tree::new(vec![
TreeNode {
text: Line::from("src"),
children: vec![TreeNode { text: Line::from("main.rs"), children: vec![], id: 2 }],
id: 1,
},
]);
// toggle expand/colapse
state.toggle(node_id);
```
**State:** `TreeState` con `expanded: HashSet<usize>`, `toggle()`, `visible_index_of()`.
### `TextInput` — Campo de texto stateful
Editor de una o varias líneas con cursor visible, placeholder, scroll horizontal automático y borde configurable. Ideal para formularios inline o filtros.
```rust
use hefesto_widgets::{TextInput, TextInputState};
let input = TextInput::new()
.placeholder("Buscar...")
.rows(1);
input.render(area, buf, &mut state);
```
**State:** `TextInputState` expone `content: String`, `cursor: usize`, y métodos de edición (`insert_char`, `delete_before`, `delete_at`, `cursor_left/right/home/end`).
### `Spin` / `ThemedSpin` — Spinner atómico
Widget mínimo que renderiza un carácter animado. Al finalizar muestra ✓ (verde) o ✗ (rojo) según `exit_code`. `ThemedSpin` es un wrapper que añade los `SpinVariant` predefinidos.
**State:** `SpinState` con `frame`, `finished`, `exit_code` y un `ScrollListState` para salida asociada.
---
## Constantes de estilo
Definidas en `styles.rs` y reexportadas desde la crate:
| `BORDER_GRAY` | `rgb(100,100,100)` |
| `OUTPUT_GRAY` | `rgb(120,120,120)` |
| `FOOTER_GRAY` | `rgb(140,140,140)` |
| `CHECK` / `CROSS` | `✓` / `✗` |
| `HIGHLIGHT_SYMBOL` | `> ` |
| `POPUP_WIDTH` | `PopupSize::Fixed(44)` |
| `DEFAULT_HIGHLIGHT` | letra blanca sobre fondo azul marino |
| `DEFAULT_FRAMES` | frames braille para spinner braille |
| `TEXT_PADDING` | padding horizontal 1 |
---
## Licencia
MIT.