# `ExRatatui.App`
[🔗](https://github.com/mcass19/ex_ratatui/blob/v0.5.1/lib/ex_ratatui/app.ex#L1)

A behaviour for building supervised TUI applications.

Provides a LiveView-inspired callback interface for terminal apps
that can be placed in OTP supervision trees.

## Usage

    defmodule MyTUI do
      use ExRatatui.App

      @impl true
      def mount(_opts) do
        {:ok, %{count: 0}}
      end

      @impl true
      def render(state, frame) do
        alias ExRatatui.Widgets.Paragraph
        alias ExRatatui.Layout.Rect

        widget = %Paragraph{text: "Count: #{state.count}"}
        rect = %Rect{x: 0, y: 0, width: frame.width, height: frame.height}
        [{widget, rect}]
      end

      @impl true
      def handle_event(%ExRatatui.Event.Key{code: "q"}, state) do
        {:stop, state}
      end

      def handle_event(_event, state) do
        {:noreply, state}
      end
    end

Then add to your supervision tree:

    children = [{MyTUI, []}]
    Supervisor.start_link(children, strategy: :one_for_one)

## Options

Options are passed through `start_link/1` and forwarded to `mount/1`:

  * `:name` - process registration name (defaults to the module name,
    pass `nil` to skip registration)
  * `:poll_interval` - event polling interval in milliseconds (default: `16`,
    which gives ~60fps). The poll runs on the BEAM's DirtyIo scheduler so it
    never blocks normal processes. Lower values increase responsiveness but
    use more CPU; higher values reduce CPU but add input latency.
  * `:test_mode` - `{width, height}` tuple to use a headless test terminal
    instead of the real terminal. Enables `async: true` tests without a TTY.

## Callbacks

  * `mount/1` — Called once on startup with options. Return `{:ok, initial_state}`
    or `{:error, reason}` to abort startup.
  * `render/2` — Called after every state change. Receives state and a
    `%ExRatatui.Frame{}` with terminal dimensions. Return a list of
    `{widget, rect}` tuples.
  * `handle_event/2` — Called when a terminal event arrives. Return
    `{:noreply, new_state}` or `{:stop, state}`.
  * `handle_info/2` — Called for non-terminal messages (e.g., PubSub).
    Optional; default implementation returns `{:noreply, state}`.
  * `terminate/2` — Called when the TUI is shutting down. Receives the
    exit reason and final state. Optional; default is a no-op.
    Use this to stop the VM with `System.stop(0)` in standalone apps.

# `state`

```elixir
@type state() :: term()
```

# `handle_event`

```elixir
@callback handle_event(
  ExRatatui.Event.Key.t()
  | ExRatatui.Event.Mouse.t()
  | ExRatatui.Event.Resize.t(),
  state()
) :: {:noreply, state()} | {:stop, state()}
```

# `handle_info`
*optional* 

```elixir
@callback handle_info(msg :: term(), state()) :: {:noreply, state()} | {:stop, state()}
```

# `mount`

```elixir
@callback mount(opts :: keyword()) :: {:ok, state()} | {:error, reason :: term()}
```

# `render`

```elixir
@callback render(state(), ExRatatui.Frame.t()) :: [
  {ExRatatui.widget(), ExRatatui.Layout.Rect.t()}
]
```

# `terminate`
*optional* 

```elixir
@callback terminate(reason :: term(), state()) :: term()
```

---

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