View-tree constructors. Auto-imported into apps via use Harlock.App,
so most apps use text(...), vbox(...), box(...) etc. directly
without qualification.
An element is a plain struct (Harlock.Element); building a view is
just calling these functions to assemble a tree. The renderer walks
the tree once per dirty frame and produces a Frame ready for the
diff renderer.
Primitives
text/2— single-line text contenttext_input/1— single-line editable input (paired withHarlock.TextBuffer)vbox/1/hbox/1— vertical / horizontal stacks with layout constraints (:length,:percentage,:fill)box/1— single-child container with border + title + paddingspacer/0— empty element that occupies a layout slotoverlay/1— render a foreground element on top of a background with optionalfocus_traptable/1/list/2— row-based primitives with selection and focus highlightingcolumn/1— column spec fortable/1
All elements that accept focus take a :focusable opt — the runtime
walks the tree to collect focusable ids for Tab traversal.
Summary
Functions
A single-child container with a border and optional inner padding.
Build a column spec for use inside table/1.
Horizontal stack. Children share the box's height; width is split.
Single-column table with chrome hidden. :row_id defaults to & &1
because lists are usually homogeneous; pass an explicit :row_id if
yours aren't.
Render over on top of child in a sub-rectangle anchored within the
parent region.
Empty cell that occupies a layout slot. Useful with constraints.
Table primitive.
A text element. content is rendered as a single line; callers split
multi-line content themselves.
Single-line text input.
Vertical stack. Children share the box's width; height is split according
to :constraints.
Functions
@spec box(keyword()) :: Harlock.Element.t()
A single-child container with a border and optional inner padding.
Required options:
:child— the element drawn inside the box
Optional:
:title— string overlaid on the top border (truncated to fit):title_align—:left(default) |:center|:right:border—:single(default) |:double|:rounded|:thick|:none:border_style—%Style{}or keyword applied to the border + title:padding— non-negative integer (uniform),{v, h}, or{top, right, bottom, left}:focusable,:focus_style— when focused, the focus style replaces the border style (the child is left alone)
For multiple children, wrap them in vbox/1 or hbox/1 and pass the
result as :child. The box reserves one cell on each side for the border
(unless :border is :none); when the region is smaller than that the
border is skipped and the child takes the full region.
@spec column(keyword()) :: Harlock.Element.Column.t()
Build a column spec for use inside table/1.
Options:
:title— header label:width— layout constraint (default{:fill, 1}):align—:left|:right|:center:render—fn row -> string | iodata
@spec hbox(keyword()) :: Harlock.Element.t()
Horizontal stack. Children share the box's height; width is split.
Options as vbox/1.
@spec list( Enumerable.t(), keyword() ) :: Harlock.Element.t()
Single-column table with chrome hidden. :row_id defaults to & &1
because lists are usually homogeneous; pass an explicit :row_id if
yours aren't.
Options:
:render—fn item -> string; defaults toto_string/1- any option accepted by
table/1
@spec overlay(keyword()) :: Harlock.Element.t()
Render over on top of child in a sub-rectangle anchored within the
parent region.
Required options:
:child— the background element (rendered first):over— the foreground element (rendered on top)
Anchor + sizing:
:anchor—:center(default),:top_left,:top_right,:bottom_left,:bottom_right, or{row, col}for absolute placement:width— width of the over region in cells (default: full parent):height— height of the over region in cells (default: full parent)
Focus:
:focus_trap— when true, focus traversal wraps within theoversubtree until the overlay disappears. Prior focus is stashed and restored automatically when the overlay closes.
Overlays nest cleanly: just put another overlay as :over.
@spec spacer() :: Harlock.Element.t()
Empty cell that occupies a layout slot. Useful with constraints.
@spec table(keyword()) :: Harlock.Element.t()
Table primitive.
Required options:
:columns— list ofcolumn/1specs:rows— enumerable of row data:row_id— fn(row) -> id. Row identity is by id, not index, so focus and selection survive sort/filter.
Optional:
:focused_row— currently-focused row id:selection—:none|{:single, id}|{:multi, MapSet}:show_header— defaulttrue:focusable,:focus_trap— same as other elements
@spec text( String.t(), keyword() ) :: Harlock.Element.t()
A text element. content is rendered as a single line; callers split
multi-line content themselves.
Options:
:style—%Harlock.Render.Style{}or keyword list of style attrs.
@spec text_input(keyword()) :: Harlock.Element.t()
Single-line text input.
Required options:
:value— the current string contents (caller-owned):cursor— grapheme index of the cursor (0..length):focusable— id for focus traversal
Optional:
:placeholder— shown when value is empty and the input isn't focused:max_length— soft hint; the element doesn't enforce it, butHarlock.TextBuffer.apply_key/3respects it if you wire it in your app:style—%Style{}for the value text:placeholder_style—%Style{}for the placeholder:password— when true, render each grapheme as•
The element is a dumb renderer. The app's update/2 owns the value and
cursor; call Harlock.TextBuffer.apply_key/3 to react to key events
when this input is focused. When focused, the renderer positions the
terminal cursor at the visual column matching :cursor.
@spec vbox(keyword()) :: Harlock.Element.t()
Vertical stack. Children share the box's width; height is split according
to :constraints.
Options:
:constraints— list of layout constraints, one per child. Defaults to[fill: 1]for each child if not provided.:children— list of child elements.