# `Harlock.Elements`
[🔗](https://github.com/thatsme/harlock/blob/v0.2.0/lib/harlock/elements.ex#L1)

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 content
  * `text_input/1` — single-line editable input (paired with
    `Harlock.TextBuffer`)
  * `vbox/1` / `hbox/1` — vertical / horizontal stacks with layout
    constraints (`:length`, `:percentage`, `:fill`)
  * `box/1` — single-child container with border + title + padding
  * `spacer/0` — empty element that occupies a layout slot
  * `overlay/1` — render a foreground element on top of a background
    with optional `focus_trap`
  * `table/1` / `list/2` — row-based primitives with selection and
    focus highlighting
  * `column/1` — column spec for `table/1`

All elements that accept focus take a `:focusable` opt — the runtime
walks the tree to collect focusable ids for Tab traversal.

# `box`

```elixir
@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.

# `column`

```elixir
@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`

# `hbox`

```elixir
@spec hbox(keyword()) :: Harlock.Element.t()
```

Horizontal stack. Children share the box's height; width is split.

Options as `vbox/1`.

# `list`

```elixir
@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 to `to_string/1`
  * any option accepted by `table/1`

# `overlay`

```elixir
@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 the `over`
    subtree until the overlay disappears. Prior focus is stashed and
    restored automatically when the overlay closes.

Overlays nest cleanly: just put another overlay as `:over`.

# `spacer`

```elixir
@spec spacer() :: Harlock.Element.t()
```

Empty cell that occupies a layout slot. Useful with constraints.

# `table`

```elixir
@spec table(keyword()) :: Harlock.Element.t()
```

Table primitive.

Required options:
  * `:columns`  — list of `column/1` specs
  * `: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` — default `true`
  * `:focusable`, `:focus_trap` — same as other elements

# `text`

```elixir
@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.

# `text_input`

```elixir
@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, but
    `Harlock.TextBuffer.apply_key/3` respects 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`.

# `vbox`

```elixir
@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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
