README

mizchi/tui/vnode does not have a README file

#
TuiAttr

Type alias for luna Attr with TuiEvent and TuiAttrValue

#
TuiHandler

Type alias for luna EventHandler with TuiEvent

#
TuiNode

Type alias for luna Node with TuiEvent and TuiAttrValue

#
A11yNode

pub struct A11yNode {
id : String
role :
Role

name : String
rect : A11yRect
children : Array[A11yNode]
} derive(
Debug
)

impl Show for A11yNode

#
A11yRect

pub struct A11yRect {
x : Int
y : Int
width : Int
height : Int
} derive(
Debug
)

impl Show for A11yRect

#
AlignmentValue

pub(all) enum AlignmentValue {
Start
Center
End
Stretch
SpaceBetween
SpaceAround
SpaceEvenly
FlexStart
FlexEnd
}

Alignment value

#
AlignmentValue::to_alignment

Convert to crater Alignment

#
AlignmentValue::to_layout_alignment

Convert to layout Alignment

#
BorderValue

pub(all) enum BorderValue {
None
Single
Double
Rounded
Ascii
}

Border style

#
BorderValue::to_border_chars

Convert to BorderChars

#
BoxProps

pub struct BoxProps {
id : String
direction : DirectionValue
width : DimensionValue
height : DimensionValue
min_width : DimensionValue
min_height : DimensionValue
flex_grow : Double
flex_shrink : Double
gap : Double
padding : Double
padding_x : Double
padding_y : Double
margin : Double
margin_x : Double
margin_y : Double
justify : AlignmentValue?
align : AlignmentValue?
border : BorderValue
border_color : ColorValue?
bg : ColorValue?
tab_index : Int
role :
Role
?
}

Box properties for type-safe construction

#
BoxProps::default

fn BoxProps::default() -> BoxProps

#
BoxProps::to_attrs

fn BoxProps::to_attrs(self : BoxProps) -> Array[TuiAttrValue]

Convert BoxProps to typed attributes

#
ColorValue

pub(all) enum ColorValue {
Transparent
Named(String)
Rgb(Int, Int, Int)
}

Color value

#
ColorValue::to_color

Convert to Color

#
DimensionValue

pub(all) enum DimensionValue {
Auto
Length(Double)
Percent(Double)
}

Dimension value for layout properties

#
DimensionValue::to_dimension

Convert to crater Dimension

#
DimensionValue::to_layout_dimension

Convert to layout Dimension

#
DirectionValue

pub(all) enum DirectionValue {
Row
Column
}

Flex direction

#
DirectionValue::to_flex_direction

Convert to crater FlexDirection

#
DirectionValue::to_layout_flex_direction

Convert to layout FlexDirection

#
DisplayValue

pub(all) enum DisplayValue {
Flex
Grid
}

Display value

#
DisplayValue::to_display

Convert to crater Display

#
EditConfig

pub(all) struct EditConfig {
field_name : String
on_change : (String) -> Unit
on_edit_start : () -> Unit?
on_edit_end : () -> Unit?
on_force_quit : () -> Unit?
}

Configuration for editable input behavior

#
FocusContext

pub struct FocusContext {
elements : Array[FocusableElement]
current_index : Int
}

Focus context for managing Tab navigation

#
FocusContext::clear

fn FocusContext::clear(self : FocusContext) -> Unit

Clear all registered elements (call before re-rendering)

#
FocusContext::count

fn FocusContext::count(self : FocusContext) -> Int

Get the number of focusable elements

#
FocusContext::current_focus

fn FocusContext::current_focus(self : FocusContext) -> String?

Get the currently focused element id

#
FocusContext::focus_by_id

fn FocusContext::focus_by_id(self : FocusContext, id : String) -> Bool

Set focus to a specific element by id Returns true if the element was found and focused

#
FocusContext::focus_next

fn FocusContext::focus_next(self : FocusContext) -> String?

Move focus to the next element (Tab key) Returns the id of the newly focused element, or None if no focusable elements

#
FocusContext::focus_prev

fn FocusContext::focus_prev(self : FocusContext) -> String?

Move focus to the previous element (Shift+Tab key) Returns the id of the newly focused element, or None if no focusable elements

#
FocusContext::focusable_ids

fn FocusContext::focusable_ids(self : FocusContext) -> Array[String]

Get all focusable element ids in tab order

#
FocusContext::is_focusable

fn FocusContext::is_focusable(self : FocusContext, id : String) -> Bool

Check if an element is focusable

#
FocusContext::new

Create a new focus context

#
FocusContext::register

fn FocusContext::register(self : FocusContext, id : String, tab_index : Int) -> Unit

Register a focusable element Elements are sorted by tab_index when calculating focus order

#
FocusableElement

pub struct FocusableElement {
id : String
tab_index : Int
}

Focusable element with its tab index and element id

#
GridAreaInfo

pub(all) struct GridAreaInfo {
column : Int
row : Int
column_span : Int
row_span : Int
}

Grid area placement info (package-visible for render_typed.mbt)

#
GridAutoFlowValue

pub(all) enum GridAutoFlowValue {
Row
Column
RowDense
ColumnDense
}

Grid auto-flow value

#
GridAutoFlowValue::to_grid_auto_flow

Convert to crater GridAutoFlow

#
InputState

pub(all) enum InputState {
Idle
Focused
Editing
Disabled
}

Input state for visual feedback

#
MouseButton

pub(all) enum MouseButton {
Left
Right
Middle
}

Mouse button

#
OverlayEntry

pub(all) struct OverlayEntry {
node :
Node
[TuiEvent, TuiAttrValue]
position : PopupPosition
backdrop : Bool
shrink : Bool
}

#
PopupPosition

pub(all) enum PopupPosition {
Center
Top
Bottom
At(Int, Int)
}

#
RenderContext

pub struct RenderContext {
styles : Map[String,
RenderStyle
]
texts : Map[String, String]
handlers : Map[String, (TuiEvent) -> Unit]
roles : Map[String,
Role
]
id_counter : Int
area_stack : Array[Map[String, GridAreaInfo]]
}

Render context holding styles and handlers

#
RenderContext::new

Create a new render context

#
TextProps

pub struct TextProps {
content : String
fg : ColorValue?
bold : Bool
underline : Bool
role :
Role
?
}

Text properties

#
TextProps::default

fn TextProps::default(content : String) -> TextProps

#
TextProps::to_attrs

fn TextProps::to_attrs(self : TextProps) -> Array[TuiAttrValue]

#
TuiAttrValue

pub(all) enum TuiAttrValue {
Direction(DirectionValue)
Width(DimensionValue)
Height(DimensionValue)
MinWidth(DimensionValue)
MinHeight(DimensionValue)
FlexGrow(Double)
FlexShrink(Double)
Gap(Double)
Display(DisplayValue)
GridTemplateColumns(Array[
TrackSizingFunction
])
GridTemplateRows(Array[
TrackSizingFunction
])
GridAutoFlow(GridAutoFlowValue)
GridColumn(Int)
GridRow(Int)
GridColumnSpan(Int)
GridRowSpan(Int)
GridTemplateAreas(Array[String])
GridArea(String)
Padding(Double)
PaddingX(Double)
PaddingY(Double)
Margin(Double)
MarginX(Double)
MarginY(Double)
Justify(AlignmentValue)
Align(AlignmentValue)
Border(BorderValue)
BorderColor(ColorValue)
Fg(ColorValue)
Bg(ColorValue)
Bold(Bool)
Underline(Bool)
Id(String)
TabIndex(Int)
Role(
Role
)
}

Typed TUI attribute value Will replace String when luna supports Attr[E, A]

#
TuiEvent

pub(all) enum TuiEvent {
Click(Int, Int, MouseButton)
Hover(Int, Int, String)
Key(String, Int)
}

TUI Event - passed to event handlers

#
TypedRenderContext

pub struct TypedRenderContext {
styles : Map[String,
RenderStyle
]
texts : Map[String, String]
handlers : Map[String, (TuiEvent) -> Unit]
roles : Map[String,
Role
]
id_counter : Int
area_stack : Array[Map[String, GridAreaInfo]]
}

Context for typed rendering

#
TypedRenderContext::new

#
VNodeApp

pub struct VNodeApp {
width : Int
height : Int
prev_buffer :
CharBuffer
?
last_layout :
Layout
?
overlay_layouts : Array[
Layout
]
render_ctx : RenderContext
}

VNodeApp manages the vnode render loop with diff-based updates

#
VNodeApp::a11y_tree

fn VNodeApp::a11y_tree(self : VNodeApp) -> Array[A11yNode]

Get accessibility tree from the last render.

#
VNodeApp::clear_prev_buffer

fn VNodeApp::clear_prev_buffer(self : VNodeApp) -> Unit

Clear the previous buffer to force a full re-render on next render call

#
VNodeApp::create_render_effect

fn VNodeApp::create_render_effect(self : VNodeApp, render_fn : () ->
Node
[TuiEvent, TuiAttrValue], output_fn : (String) -> Unit) -> (() -> Unit)

Create a reactive effect that re-renders when signals change Returns a dispose function

#
VNodeApp::dispatch_hover

fn VNodeApp::dispatch_hover(self : VNodeApp, event :
MouseEvent
) -> String?

Dispatch hover event - returns hovered component ID on Move/Drag events Also dispatches TuiEvent::Hover to handlers for overlay-aware hit testing

#
VNodeApp::dump_a11y_tree

fn VNodeApp::dump_a11y_tree(self : VNodeApp) -> String

Debug: dump accessibility tree structure.

#
VNodeApp::find_by_id

fn VNodeApp::find_by_id(self : VNodeApp, id : String) ->
HitTestResult
?

Find component by ID

#
VNodeApp::handle_click

fn VNodeApp::handle_click(self : VNodeApp, event :
MouseEvent
) -> String?

Handle a mouse event using the render context's handlers Returns the clicked component ID if found and handler was invoked

#
VNodeApp::hit_test

fn VNodeApp::hit_test(self : VNodeApp, x : Int, y : Int) ->
HitTestResult
?

Perform hit test at coordinates Checks overlays first (top-most layer) before main layout

#
VNodeApp::init_terminal

fn VNodeApp::init_terminal() -> String

Initialize terminal (enter alt screen, hide cursor)

#
VNodeApp::layout_rects

Get all layout rects from the last render (absolute coordinates).

#
VNodeApp::new

fn VNodeApp::new(width : Int, height : Int) -> VNodeApp

#
VNodeApp::render

fn VNodeApp::render(self : VNodeApp, root :
Node
[TuiEvent, TuiAttrValue]) -> String

Render a vnode tree to ANSI string

#
VNodeApp::render_frame

fn VNodeApp::render_frame(self : VNodeApp, root :
Node
[TuiEvent, TuiAttrValue]) -> String

Render with cursor hidden and positioned at origin

#
VNodeApp::render_frame_with_overlays

fn VNodeApp::render_frame_with_overlays(self : VNodeApp, main :
Node
[TuiEvent, TuiAttrValue], overlays : Array[OverlayEntry]) -> String

Render with overlays and cursor hidden

#
VNodeApp::render_with_overlays

fn VNodeApp::render_with_overlays(self : VNodeApp, main :
Node
[TuiEvent, TuiAttrValue], overlays : Array[OverlayEntry]) -> String

Render main content with overlay layers on top

#
VNodeApp::resize

fn VNodeApp::resize(self : VNodeApp, width : Int, height : Int) -> Unit

Resize the render target and force a full redraw on next render.

#
VNodeApp::restore_terminal

fn VNodeApp::restore_terminal() -> String

Restore terminal (show cursor, leave alt screen)

#
attr

Create a static typed attribute

#
attr_dyn

Create a dynamic typed attribute

#
attr_to_string

fn attr_to_string(attr : TuiAttrValue) -> (String, String)

Convert TuiAttrValue to (key, value) string pair

#
box_node

Create a box node from typed props

#
box_to_crater

Convert BoxProps directly to crater node (type-safe path)

#
build_a11y_tree

fn build_a11y_tree(layout :
Layout
, ctx : RenderContext) -> Array[A11yNode]

#
column

fn column(id? : String, gap? : Double, margin? : Double, margin_x? : Double, margin_y? : Double, padding? : Double, padding_x? : Double, padding_y? : Double, width? : Double, height? : Double, min_width? : Double, min_height? : Double, flex_grow? : Double, justify? : String, align? : String, border? : String, border_color? : String, bg? : String, role? : String, tab_index? : Int, on_click? : (TuiEvent) -> Unit?, children : Array[
Node
[TuiEvent, TuiAttrValue]]) ->
Node
[TuiEvent, TuiAttrValue]

Column container (vertical flex)

#
component

Component boundary

#
dump_a11y_tree

fn dump_a11y_tree(nodes : Array[A11yNode]) -> String

#
extract_tab_index

fn extract_tab_index(attrs : Array[(String,
Attr
[TuiEvent, TuiAttrValue])]) -> Int?

Extract tab_index from TuiAttrValue if present

#
form_edit_config

fn form_edit_config(field_name : String, signal :
Signal
[String], on_edit_start? : () -> Unit?, on_edit_end? : () -> Unit?, on_force_quit? : () -> Unit?) -> EditConfig

Helper to create a standard edit config for form fields

#
grid

fn grid(columns? : Array[Double], rows? : Array[Double], areas? : Array[String], auto_flow? : String, id? : String, gap? : Double, padding? : Double, padding_x? : Double, padding_y? : Double, width? : Double, height? : Double, border? : String, border_color? : String, bg? : String, role? : String, tab_index? : Int, children : Array[
Node
[TuiEvent, TuiAttrValue]]) ->
Node
[TuiEvent, TuiAttrValue]

Grid container with CSS Grid layout Supports both explicit columns/rows and named areas

#
grid_area

Grid area - place child in a named grid area Used with grid(areas=[...]) for semantic layout

#
grid_item

fn grid_item(column? : Int, row? : Int, column_span? : Int, row_span? : Int, tab_index? : Int, child~ :
Node
[TuiEvent, TuiAttrValue]) ->
Node
[TuiEvent, TuiAttrValue]

Grid item with placement control (explicit column/row positioning)

#
hspace

fn hspace(width : Double) ->
Node
[TuiEvent, TuiAttrValue]

Horizontal space with fixed width

#
init_vnode_terminal

fn init_vnode_terminal(width : Int, height : Int, output_fn : (String) -> Unit, mouse? : Bool, raw_mode? : Bool) -> (VNodeApp, () -> Unit)

Initialize a VNodeApp with terminal setup and return a cleanup function.

#
input

fn input(value : String, id? : String, placeholder? : String, state? : InputState, fg? : String, bg? : String, placeholder_fg? : String, focus_border_color? : String, edit_border_color? : String, disabled_fg? : String, disabled_bg? : String, width? : Double, min_width? : Double, padding_x? : Double, padding_y? : Double) ->
Node
[TuiEvent, TuiAttrValue]

Create an input component

#
input_plain

fn input_plain(value : String, placeholder? : String, state? : InputState, fg? : String, placeholder_fg? : String) ->
Node
[TuiEvent, TuiAttrValue]

Create an input field without border (inline style)

#
is_printable_char

fn is_printable_char(c : Char) -> Bool

Check if a character is printable (for IME input detection)

#
is_printable_string

fn is_printable_string(s : String) -> Bool

Check if a string is all printable characters (for IME input detection)

Create an event handler attribute

#
render_overlay_at

fn render_overlay_at(x : Int, y : Int, node :
Node
[TuiEvent, TuiAttrValue]) -> String

Render a TuiNode as an overlay at specified position Returns ANSI string with cursor positioning commands Each line of the node is rendered at (x + i, y) for i-th line

#
render_to_lines

fn render_to_lines(node :
Node
[TuiEvent, TuiAttrValue]) -> Array[String]

Render a TuiNode to an array of lines Each line is a complete string with ANSI escape codes

#
render_vnode_once

fn render_vnode_once(width : Int, height : Int, root :
Node
[TuiEvent, TuiAttrValue]) -> String

Simple render function for one-shot rendering (no reactivity)

#
row

fn row(id? : String, gap? : Double, margin? : Double, margin_x? : Double, margin_y? : Double, padding? : Double, padding_x? : Double, padding_y? : Double, width? : Double, height? : Double, min_width? : Double, min_height? : Double, flex_grow? : Double, justify? : String, align? : String, border? : String, border_color? : String, bg? : String, role? : String, tab_index? : Int, on_click? : (TuiEvent) -> Unit?, children : Array[
Node
[TuiEvent, TuiAttrValue]]) ->
Node
[TuiEvent, TuiAttrValue]

Row container (horizontal flex)

#
run_vnode_app

fn run_vnode_app(width : Int, height : Int, render_fn : () ->
Node
[TuiEvent, TuiAttrValue], output_fn : (String) -> Unit) -> (() -> Unit)

Full-screen vnode app helper: sets up alt screen and handles cleanup

#
show

Conditional rendering

#
spacer

Flexible spacer

#
start_edit

fn start_edit(config : EditConfig, current_value : String, on_complete : () -> Unit, confirm_on_shift_enter? : Bool, esc_cancels? : Bool) -> Unit

Start editing a field with cooked mode (IME support) This exits alternate screen temporarily for proper IME input confirm_on_shift_enter: if true, Shift+Enter confirms and Enter inserts newline esc_cancels: if false, Esc is ignored

#
start_edit_inplace

fn start_edit_inplace(config : EditConfig, current_value : String, row : Int, col : Int, width : Int, height : Int, multiline : Bool, on_complete : () -> Unit, confirm_on_shift_enter? : Bool, esc_cancels? : Bool, on_lines_change? : (Int) -> Int?, on_completion? : (String, Int) -> String??) -> Unit

Start editing a field inplace (stays in TUI screen) row/col are 1-indexed ANSI coordinates width/height define the input area (supports multi-line wrapping) multiline: if true, Enter can insert newline when confirm_on_shift_enter is true confirm_on_shift_enter: if true, Shift+Enter confirms esc_cancels: if false, Esc is ignored on_lines_change: optional callback (line_count) -> new_height for dynamic resizing on_completion: optional callback (text, cursor_pos) -> completion_suffix for Tab completion

#
start_edit_inplace_in_bounds

fn start_edit_inplace_in_bounds(config : EditConfig, current_value : String, bounds :
HitTestResult
, multiline : Bool, on_complete : () -> Unit, confirm_on_shift_enter? : Bool, esc_cancels? : Bool, border? : Int, on_lines_change? : (Int) -> Int?, on_completion? : (String, Int) -> String??) -> Unit

Start editing within bounds (HitTestResult) with border adjustment. bounds.x/y are 0-indexed; row/col for ANSI are 1-indexed. on_completion: optional callback (text, cursor_pos) -> completion_suffix for Tab completion

#
text

fn text(content : String, fg? : String, bold? : Bool, underline? : Bool, role? : String) ->
Node
[TuiEvent, TuiAttrValue]

Static text node

#
text_dyn

fn text_dyn(getter : () -> String, fg? : String, bold? : Bool, underline? : Bool, role? : String) ->
Node
[TuiEvent, TuiAttrValue]

Dynamic text node

#
text_node

Create a text node from typed props

#
textarea

fn textarea(value : String, id? : String, placeholder? : String, state? : InputState, rows? : Int, fg? : String, bg? : String, placeholder_fg? : String, focus_border_color? : String, edit_border_color? : String, min_width? : Double, padding_x? : Double, padding_y? : Double) ->
Node
[TuiEvent, TuiAttrValue]

Create a textarea component (multi-line input)

#
to_crater_node

Convert TuiNode to crater Node

#
view

fn view(direction? : String, id? : String, gap? : Double, margin? : Double, margin_x? : Double, margin_y? : Double, padding? : Double, padding_x? : Double, padding_y? : Double, width? : Double, height? : Double, min_width? : Double, min_height? : Double, flex_grow? : Double, justify? : String, align? : String, border? : String, border_color? : String, bg? : String, role? : String, tab_index? : Int, on_click? : (TuiEvent) -> Unit?, children : Array[
Node
[TuiEvent, TuiAttrValue]]) ->
Node
[TuiEvent, TuiAttrValue]

Generic view container (flex layout with configurable direction) Default direction is column (React Native style)

#
vspace

fn vspace(height : Double) ->
Node
[TuiEvent, TuiAttrValue]

Vertical space with fixed height