Widgets implementados (13): - Block, Paragraph, List, Table - Gauge, LineGauge, Tabs, Sparkline - Scrollbar, BarChart, Canvas, Chart - Calendar (Monthly), Clear Modulos: - src/text.zig: Span, Line, Text, Alignment - src/symbols/: line, border, block, bar, braille, half_block, scrollbar, marker - src/widgets/: todos los widgets con tests Documentacion: - docs/ARCHITECTURE.md: arquitectura tecnica - docs/WIDGETS.md: guia completa de widgets - docs/API.md: referencia rapida - CLAUDE.md: actualizado con estado v1.0 Tests: 103+ tests en widgets, todos pasan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
23 KiB
zcatui - Documentacion de Widgets
Referencia completa de todos los widgets disponibles en zcatui
Indice
- Block - Contenedor con bordes
- Paragraph - Texto con wrapping
- List - Lista seleccionable
- Table - Tabla multi-columna
- Gauge - Barra de progreso
- LineGauge - Progreso en linea
- Tabs - Navegacion por pestanas
- Sparkline - Mini graficos
- Scrollbar - Indicador de scroll
- BarChart - Graficos de barras
- Canvas - Dibujo libre
- Chart - Graficos con ejes
- Calendar - Calendario mensual
- Clear - Limpiar area
Block
Widget base que proporciona bordes, titulos y padding. Usado como contenedor para otros widgets.
Archivo
src/widgets/block.zig
Ejemplo Basico
const block = Block.init()
.title("Mi Titulo")
.borders(Borders.all)
.borderStyle(Style.default.fg(Color.blue));
block.render(area, buf);
API
pub const Block = struct {
// Constructores
pub fn init() Block;
pub fn bordered() Block; // Con bordes en todos los lados
// Configuracion
pub fn title(self: Block, t: []const u8) Block;
pub fn titleStyle(self: Block, style: Style) Block;
pub fn titleAlignment(self: Block, alignment: Alignment) Block;
pub fn borders(self: Block, b: Borders) Block;
pub fn borderStyle(self: Block, style: Style) Block;
pub fn borderSet(self: Block, set: BorderSet) Block;
pub fn style(self: Block, s: Style) Block;
pub fn padding(self: Block, p: Padding) Block;
// Utilidades
pub fn inner(self: Block, area: Rect) Rect;
pub fn horizontalSpace(self: Block) u16;
pub fn verticalSpace(self: Block) u16;
// Renderizado
pub fn render(self: Block, area: Rect, buf: *Buffer) void;
};
pub const Borders = packed struct {
top: bool = false,
right: bool = false,
bottom: bool = false,
left: bool = false,
pub const none: Borders = .{};
pub const all: Borders = .{ .top = true, .right = true, .bottom = true, .left = true };
pub const top: Borders = .{ .top = true };
// etc.
};
Border Sets Disponibles
| Set | Descripcion | Caracteres |
|---|---|---|
plain |
Lineas simples | ─ │ ┌ ┐ └ ┘ |
rounded |
Esquinas redondeadas | ─ │ ╭ ╮ ╰ ╯ |
double |
Lineas dobles | ═ ║ ╔ ╗ ╚ ╝ |
thick |
Lineas gruesas | ━ ┃ ┏ ┓ ┗ ┛ |
Paragraph
Widget para mostrar texto con word-wrapping, alineacion y scroll.
Archivo
src/widgets/paragraph.zig
Ejemplo Basico
const text = Text.raw("Este es un texto largo que sera\nenvuelto automaticamente si es necesario.");
const para = Paragraph.init(text)
.setBlock(Block.bordered().title("Info"))
.setWrap(.{ .trim = true })
.setAlignment(.center);
para.render(area, buf);
API
pub const Paragraph = struct {
pub fn init(text: Text) Paragraph;
pub fn initWithSpans(spans: []const Span) Paragraph;
pub fn setBlock(self: Paragraph, block: Block) Paragraph;
pub fn setStyle(self: Paragraph, style: Style) Paragraph;
pub fn setWrap(self: Paragraph, wrap: Wrap) Paragraph;
pub fn setAlignment(self: Paragraph, alignment: Alignment) Paragraph;
pub fn setScroll(self: Paragraph, offset: struct { x: u16, y: u16 }) Paragraph;
pub fn render(self: Paragraph, area: Rect, buf: *Buffer) void;
};
pub const Wrap = struct {
trim: bool = false, // Eliminar espacios extra
};
List
Lista seleccionable con soporte para scroll automatico y highlighting.
Archivo
src/widgets/list.zig
Ejemplo Basico
const items = [_]ListItem{
ListItem.init(Line.raw("Item 1")),
ListItem.init(Line.raw("Item 2")).setStyle(Style.default.fg(Color.red)),
ListItem.init(Line.raw("Item 3")),
};
var state = ListState.init();
state.select(1); // Seleccionar segundo item
const list = List.init(&items)
.setBlock(Block.bordered().title("Lista"))
.setHighlightStyle(Style.default.bg(Color.blue))
.setHighlightSymbol("> ");
list.renderStateful(area, buf, &state);
API
pub const List = struct {
pub fn init(items: []const ListItem) List;
pub fn setBlock(self: List, block: Block) List;
pub fn setStyle(self: List, style: Style) List;
pub fn setHighlightStyle(self: List, style: Style) List;
pub fn setHighlightSymbol(self: List, symbol: []const u8) List;
pub fn setHighlightSpacing(self: List, spacing: HighlightSpacing) List;
pub fn setDirection(self: List, direction: ListDirection) List;
pub fn setRepeatHighlightSymbol(self: List, repeat: bool) List;
pub fn render(self: List, area: Rect, buf: *Buffer) void;
pub fn renderStateful(self: List, area: Rect, buf: *Buffer, state: *ListState) void;
};
pub const ListState = struct {
selected: ?usize = null,
offset: usize = 0,
pub fn init() ListState;
pub fn select(self: *ListState, index: usize) void;
pub fn selectNext(self: *ListState, len: usize) void;
pub fn selectPrevious(self: *ListState) void;
};
pub const ListDirection = enum { top_to_bottom, bottom_to_top };
Table
Tabla multi-columna con headers, footers y seleccion de filas.
Archivo
src/widgets/table.zig
Ejemplo Basico
const header = Row.init(&[_]Cell{
Cell.init(Line.raw("Nombre")),
Cell.init(Line.raw("Edad")),
Cell.init(Line.raw("Ciudad")),
}).setStyle(Style.default.bold());
const rows = [_]Row{
Row.init(&[_]Cell{
Cell.init(Line.raw("Ana")),
Cell.init(Line.raw("25")),
Cell.init(Line.raw("Madrid")),
}),
Row.init(&[_]Cell{
Cell.init(Line.raw("Juan")),
Cell.init(Line.raw("30")),
Cell.init(Line.raw("Barcelona")),
}),
};
const widths = [_]Constraint{
Constraint.percentage(40),
Constraint.length(10),
Constraint.fill(1),
};
var state = TableState.init();
state.select(0);
const table = Table.init(&rows, &widths)
.setHeader(header)
.setBlock(Block.bordered().title("Usuarios"))
.setHighlightStyle(Style.default.bg(Color.yellow));
table.renderStateful(area, buf, &state);
API
pub const Table = struct {
pub fn init(rows: []const Row, widths: []const Constraint) Table;
pub fn setHeader(self: Table, header: Row) Table;
pub fn setFooter(self: Table, footer: Row) Table;
pub fn setBlock(self: Table, block: Block) Table;
pub fn setStyle(self: Table, style: Style) Table;
pub fn setHighlightStyle(self: Table, style: Style) Table;
pub fn setHighlightSymbol(self: Table, symbol: []const u8) Table;
pub fn setColumnSpacing(self: Table, spacing: u16) Table;
pub fn render(self: Table, area: Rect, buf: *Buffer) void;
pub fn renderStateful(self: Table, area: Rect, buf: *Buffer, state: *TableState) void;
};
pub const TableState = struct {
selected: ?usize = null,
offset: usize = 0;
pub fn init() TableState;
pub fn select(self: *TableState, index: usize) void;
};
Gauge
Barra de progreso usando caracteres de bloque.
Archivo
src/widgets/gauge.zig
Ejemplo Basico
const gauge = Gauge.init()
.setRatio(0.75)
.setLabel("75%")
.setBlock(Block.bordered().title("Progreso"))
.setGaugeStyle(Style.default.fg(Color.green).bg(Color.black));
gauge.render(area, buf);
API
pub const Gauge = struct {
pub fn init() Gauge;
pub fn setRatio(self: Gauge, ratio: f64) Gauge; // 0.0 - 1.0
pub fn setPercent(self: Gauge, percent: u16) Gauge; // 0 - 100
pub fn setLabel(self: Gauge, label: []const u8) Gauge;
pub fn setBlock(self: Gauge, block: Block) Gauge;
pub fn setStyle(self: Gauge, style: Style) Gauge;
pub fn setGaugeStyle(self: Gauge, style: Style) Gauge;
pub fn setUseUnicode(self: Gauge, use: bool) Gauge;
pub fn render(self: Gauge, area: Rect, buf: *Buffer) void;
};
LineGauge
Barra de progreso en una sola linea.
Archivo
src/widgets/gauge.zig
Ejemplo Basico
const gauge = LineGauge.init()
.setRatio(0.5)
.setLabel("Loading...")
.setLineSet(symbols.line.NORMAL)
.setFilledStyle(Style.default.fg(Color.cyan))
.setUnfilledStyle(Style.default.fg(Color.white));
gauge.render(area, buf);
API
pub const LineGauge = struct {
pub fn init() LineGauge;
pub fn setRatio(self: LineGauge, ratio: f64) LineGauge;
pub fn setLabel(self: LineGauge, label: []const u8) LineGauge;
pub fn setBlock(self: LineGauge, block: Block) LineGauge;
pub fn setStyle(self: LineGauge, style: Style) LineGauge;
pub fn setFilledStyle(self: LineGauge, style: Style) LineGauge;
pub fn setUnfilledStyle(self: LineGauge, style: Style) LineGauge;
pub fn setLineSet(self: LineGauge, set: symbols.line.Set) LineGauge;
pub fn render(self: LineGauge, area: Rect, buf: *Buffer) void;
};
Tabs
Widget de navegacion por pestanas.
Archivo
src/widgets/tabs.zig
Ejemplo Basico
const titles = [_]Line{
Line.raw("Tab 1"),
Line.raw("Tab 2"),
Line.raw("Tab 3"),
};
const tabs = Tabs.init(&titles)
.select(1)
.setBlock(Block.bordered())
.setHighlightStyle(Style.default.fg(Color.yellow).bold())
.setDivider(" | ");
tabs.render(area, buf);
API
pub const Tabs = struct {
pub fn init(titles: []const Line) Tabs;
pub fn select(self: Tabs, index: usize) Tabs;
pub fn setBlock(self: Tabs, block: Block) Tabs;
pub fn setStyle(self: Tabs, style: Style) Tabs;
pub fn setHighlightStyle(self: Tabs, style: Style) Tabs;
pub fn setDivider(self: Tabs, divider: []const u8) Tabs;
pub fn setPadding(self: Tabs, left: []const u8, right: []const u8) Tabs;
pub fn render(self: Tabs, area: Rect, buf: *Buffer) void;
};
Sparkline
Mini grafico de linea usando caracteres de bloque.
Archivo
src/widgets/sparkline.zig
Ejemplo Basico
const data = [_]u64{ 0, 1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4 };
const spark = Sparkline.init()
.setData(&data)
.setMax(5)
.setBlock(Block.bordered().title("CPU"))
.setStyle(Style.default.fg(Color.cyan))
.setDirection(.left_to_right);
spark.render(area, buf);
API
pub const Sparkline = struct {
pub fn init() Sparkline;
pub fn setData(self: Sparkline, data: []const u64) Sparkline;
pub fn setMax(self: Sparkline, max: u64) Sparkline;
pub fn setBlock(self: Sparkline, block: Block) Sparkline;
pub fn setStyle(self: Sparkline, style: Style) Sparkline;
pub fn setBarSet(self: Sparkline, set: symbols.bar.Set) Sparkline;
pub fn setDirection(self: Sparkline, direction: RenderDirection) Sparkline;
pub fn render(self: Sparkline, area: Rect, buf: *Buffer) void;
};
pub const RenderDirection = enum { left_to_right, right_to_left };
Scrollbar
Indicador visual de posicion de scroll.
Archivo
src/widgets/scrollbar.zig
Ejemplo Basico
var state = ScrollbarState.init(100) // 100 items totales
.setPosition(25) // Posicion actual
.setViewportContentLength(20); // Items visibles
const scrollbar = Scrollbar.init(.vertical_right)
.setSymbols(.{ .track = "│", .thumb = "█" })
.setStyle(Style.default.fg(Color.white));
scrollbar.render(area, buf, &state);
API
pub const Scrollbar = struct {
pub fn init(orientation: ScrollbarOrientation) Scrollbar;
pub fn setOrientation(self: Scrollbar, o: ScrollbarOrientation) Scrollbar;
pub fn setThumbSymbol(self: Scrollbar, symbol: []const u8) Scrollbar;
pub fn setTrackSymbol(self: Scrollbar, symbol: ?[]const u8) Scrollbar;
pub fn setBeginSymbol(self: Scrollbar, symbol: ?[]const u8) Scrollbar;
pub fn setEndSymbol(self: Scrollbar, symbol: ?[]const u8) Scrollbar;
pub fn setSymbols(self: Scrollbar, symbols: ScrollbarSymbols) Scrollbar;
pub fn setStyle(self: Scrollbar, style: Style) Scrollbar;
pub fn setThumbStyle(self: Scrollbar, style: Style) Scrollbar;
pub fn setTrackStyle(self: Scrollbar, style: Style) Scrollbar;
pub fn render(self: Scrollbar, area: Rect, buf: *Buffer, state: *ScrollbarState) void;
};
pub const ScrollbarState = struct {
pub fn init(content_length: usize) ScrollbarState;
pub fn setPosition(self: ScrollbarState, position: usize) ScrollbarState;
pub fn setViewportContentLength(self: ScrollbarState, length: usize) ScrollbarState;
};
pub const ScrollbarOrientation = enum {
vertical_right,
vertical_left,
horizontal_bottom,
horizontal_top,
};
BarChart
Graficos de barras con soporte para grupos.
Archivo
src/widgets/barchart.zig
Ejemplo Basico
const bars = [_]Bar{
Bar.init(50).setLabel("Ene").setStyle(Style.default.fg(Color.red)),
Bar.init(80).setLabel("Feb").setStyle(Style.default.fg(Color.green)),
Bar.init(65).setLabel("Mar").setStyle(Style.default.fg(Color.blue)),
};
const group = BarGroup.init(&bars).setLabel("Q1 2024");
const groups = [_]BarGroup{group};
const chart = BarChart.init()
.setData(&groups)
.setBarWidth(5)
.setBarGap(1)
.setGroupGap(2)
.setBlock(Block.bordered().title("Ventas"))
.setMax(100);
chart.render(area, buf);
API
pub const BarChart = struct {
pub fn init() BarChart;
pub fn setData(self: BarChart, data: []const BarGroup) BarChart;
pub fn setBlock(self: BarChart, block: Block) BarChart;
pub fn setBarWidth(self: BarChart, width: u16) BarChart;
pub fn setBarGap(self: BarChart, gap: u16) BarChart;
pub fn setGroupGap(self: BarChart, gap: u16) BarChart;
pub fn setBarStyle(self: BarChart, style: Style) BarChart;
pub fn setLabelStyle(self: BarChart, style: Style) BarChart;
pub fn setValueStyle(self: BarChart, style: Style) BarChart;
pub fn setStyle(self: BarChart, style: Style) BarChart;
pub fn setMax(self: BarChart, max: u64) BarChart;
pub fn setDirection(self: BarChart, dir: Direction) BarChart;
pub fn render(self: BarChart, area: Rect, buf: *Buffer) void;
};
pub const Bar = struct {
pub fn init(value: u64) Bar;
pub fn setLabel(self: Bar, label: []const u8) Bar;
pub fn setStyle(self: Bar, style: Style) Bar;
pub fn setValueStyle(self: Bar, style: Style) Bar;
pub fn setTextValue(self: Bar, text: []const u8) Bar;
};
pub const BarGroup = struct {
pub fn init(bars: []const Bar) BarGroup;
pub fn setLabel(self: BarGroup, label: []const u8) BarGroup;
};
Canvas
Widget para dibujo libre con diferentes tipos de marcadores.
Archivo
src/widgets/canvas.zig
Ejemplo Basico
const canvas = Canvas.init()
.setXBounds(-10.0, 10.0)
.setYBounds(-10.0, 10.0)
.setMarker(.braille)
.setBlock(Block.bordered().title("Canvas"))
.paint(struct {
pub fn draw(painter: *Painter) void {
// Dibujar una linea
painter.line(0, 0, 10, 10, Color.red);
// Dibujar un rectangulo
painter.rectangle(2, 2, 8, 8, Color.blue);
// Dibujar un circulo
painter.circle(5, 5, 3, Color.green);
// Dibujar puntos individuales
painter.point(0, 0, Color.yellow);
}
}.draw);
canvas.render(area, buf);
API
pub const Canvas = struct {
pub fn init() Canvas;
pub fn setXBounds(self: Canvas, min: f64, max: f64) Canvas;
pub fn setYBounds(self: Canvas, min: f64, max: f64) Canvas;
pub fn setMarker(self: Canvas, marker: Marker) Canvas;
pub fn setBlock(self: Canvas, block: Block) Canvas;
pub fn setBackgroundColor(self: Canvas, color: Color) Canvas;
pub fn paint(self: Canvas, painter_fn: *const fn(*Painter) void) Canvas;
pub fn render(self: Canvas, area: Rect, buf: *Buffer) void;
};
pub const Marker = enum {
dot, // Punto simple
block, // Caracter bloque completo
bar, // Barras verticales
braille, // Patrones braille (2x4 por celda)
half_block, // Half-blocks (1x2 por celda)
};
pub const Painter = struct {
pub fn point(self: *Painter, x: f64, y: f64, color: Color) void;
pub fn line(self: *Painter, x1: f64, y1: f64, x2: f64, y2: f64, color: Color) void;
pub fn rectangle(self: *Painter, x: f64, y: f64, width: f64, height: f64, color: Color) void;
pub fn circle(self: *Painter, x: f64, y: f64, radius: f64, color: Color) void;
};
Resoluciones por Marker
| Marker | Resolucion por celda | Uso recomendado |
|---|---|---|
dot |
1x1 | Simple, compatible |
block |
1x1 | Relleno solido |
bar |
8x1 | Barras horizontales |
braille |
2x4 | Alta resolucion |
half_block |
1x2 | Resolucion media |
Chart
Graficos de linea, scatter y barras con ejes X/Y.
Archivo
src/widgets/chart.zig
Ejemplo Basico
const data1 = [_][2]f64{
.{ 0, 0 }, .{ 1, 1 }, .{ 2, 4 }, .{ 3, 9 }, .{ 4, 16 },
};
const data2 = [_][2]f64{
.{ 0, 16 }, .{ 1, 9 }, .{ 2, 4 }, .{ 3, 1 }, .{ 4, 0 },
};
const datasets = [_]Dataset{
Dataset.init(&data1)
.setName("x^2")
.setMarker(.braille)
.setGraphType(.line)
.setStyle(Style.default.fg(Color.cyan)),
Dataset.init(&data2)
.setName("(4-x)^2")
.setMarker(.braille)
.setGraphType(.scatter)
.setStyle(Style.default.fg(Color.yellow)),
};
const x_axis = Axis.init()
.setTitle("X")
.setBounds(0, 4)
.setLabels(&[_][]const u8{ "0", "1", "2", "3", "4" });
const y_axis = Axis.init()
.setTitle("Y")
.setBounds(0, 16);
const chart = Chart.init(&datasets)
.setXAxis(x_axis)
.setYAxis(y_axis)
.setBlock(Block.bordered().title("Grafico"))
.setLegendPosition(.top_right);
chart.render(area, buf);
API
pub const Chart = struct {
pub fn init(datasets: []const Dataset) Chart;
pub fn setXAxis(self: Chart, axis: Axis) Chart;
pub fn setYAxis(self: Chart, axis: Axis) Chart;
pub fn setBlock(self: Chart, block: Block) Chart;
pub fn setStyle(self: Chart, style: Style) Chart;
pub fn setLegendPosition(self: Chart, pos: ?LegendPosition) Chart;
pub fn setHideLegendConstraint(self: Chart, constraint: Constraint) Chart;
pub fn render(self: Chart, area: Rect, buf: *Buffer) void;
};
pub const Dataset = struct {
pub fn init(data: []const [2]f64) Dataset;
pub fn setName(self: Dataset, name: []const u8) Dataset;
pub fn setData(self: Dataset, data: []const [2]f64) Dataset;
pub fn setMarker(self: Dataset, marker: Marker) Dataset;
pub fn setGraphType(self: Dataset, graph_type: GraphType) Dataset;
pub fn setStyle(self: Dataset, style: Style) Dataset;
};
pub const Axis = struct {
pub fn init() Axis;
pub fn setTitle(self: Axis, title: []const u8) Axis;
pub fn setTitleStyle(self: Axis, style: Style) Axis;
pub fn setBounds(self: Axis, min: f64, max: f64) Axis;
pub fn setLabels(self: Axis, labels: []const []const u8) Axis;
pub fn setLabelsAlignment(self: Axis, alignment: Alignment) Axis;
pub fn setStyle(self: Axis, style: Style) Axis;
};
pub const GraphType = enum { scatter, line, bar };
pub const LegendPosition = enum { top_left, top_right, bottom_left, bottom_right };
Calendar
Calendario mensual con soporte para eventos y estilos personalizados.
Archivo
src/widgets/calendar.zig
Ejemplo Basico
// Crear eventos con estilos
var events = CalendarEventStore.init();
events.add(Date.init(2024, 12, 25), Style.default.fg(Color.red).bold());
events.add(Date.init(2024, 12, 31), Style.default.fg(Color.yellow));
const calendar = Monthly.init(Date.init(2024, 12, 1))
.withEvents(events)
.showMonthHeader(Style.default.fg(Color.blue).bold())
.showWeekdaysHeader(Style.default.fg(Color.cyan))
.showSurrounding(Style.default.fg(Color.white))
.setDefaultStyle(Style.default)
.setBlock(Block.bordered());
calendar.render(area, buf);
Salida Visual
┌──────────────────────┐
│ December 2024 │
│ Su Mo Tu We Th Fr Sa │
│ 1 2 3 4 5 6 7 │
│ 8 9 10 11 12 13 14 │
│ 15 16 17 18 19 20 21 │
│ 22 23 24 25 26 27 28 │
│ 29 30 31 │
└──────────────────────┘
API
pub const Monthly = struct {
pub fn init(display_date: Date) Monthly;
pub fn withEvents(display_date: Date, events: CalendarEventStore) Monthly;
pub fn showSurrounding(self: Monthly, style: Style) Monthly;
pub fn showWeekdaysHeader(self: Monthly, style: Style) Monthly;
pub fn showMonthHeader(self: Monthly, style: Style) Monthly;
pub fn setDefaultStyle(self: Monthly, style: Style) Monthly;
pub fn setBlock(self: Monthly, block: Block) Monthly;
pub fn width(self: Monthly) u16; // Siempre 21 + bordes
pub fn height(self: Monthly) u16; // Variable segun mes
pub fn render(self: Monthly, area: Rect, buf: *Buffer) void;
};
pub const Date = struct {
year: i16,
month: u4, // 1-12
day: u5, // 1-31
pub fn init(year: i16, month: u4, day: u5) Date;
pub fn isLeapYear(self: Date) bool;
pub fn daysInMonth(self: Date) u5;
pub fn dayOfWeek(self: Date) u3; // 0=Sunday
pub fn monthName(self: Date) []const u8;
};
pub const CalendarEventStore = struct {
pub fn init() CalendarEventStore;
pub fn add(self: *CalendarEventStore, date: Date, style: Style) void;
pub fn getStyle(self: CalendarEventStore, date: Date) Style;
};
Clear
Widget simple que limpia/resetea un area de la pantalla.
Archivo
src/widgets/clear.zig
Ejemplo Basico
// Limpiar todo el area antes de renderizar otros widgets
Clear.init().render(area, buf);
// Ahora renderizar contenido fresco
my_widget.render(area, buf);
API
pub const Clear = struct {
pub fn init() Clear;
pub fn render(self: Clear, area: Rect, buf: *Buffer) void;
};
Uso Tipico
Clear es util cuando:
- Necesitas borrar contenido previo antes de re-renderizar
- Quieres resetear estilos de un area especifica
- Implementas transiciones entre pantallas
Patrones Comunes
Composicion de Widgets
// Crear un layout dividido
const chunks = Layout.vertical(&[_]Constraint{
Constraint.length(3), // Header
Constraint.min(0), // Contenido
Constraint.length(1), // Footer
}).split(area);
// Renderizar widgets en cada area
Block.bordered().title("Header").render(chunks[0], buf);
list.renderStateful(chunks[1], buf, &list_state);
Paragraph.init("Status: OK").render(chunks[2], buf);
Widgets Anidados
// List con block personalizado
const list = List.init(items)
.setBlock(
Block.bordered()
.title("Items")
.titleStyle(Style.default.bold())
.borderStyle(Style.default.fg(Color.cyan))
);
Estilos Condicionales
const item_style = if (is_selected)
Style.default.bg(Color.blue).fg(Color.white)
else if (is_important)
Style.default.fg(Color.red).bold()
else
Style.default;