# `Drafter`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter.ex#L1)

An Elixir Terminal User Interface framework.

Drafter provides a complete TUI framework with:
- Widget-based UI components
- Event-driven architecture  
- Flexible layout system
- Self-implemented drawing primitives
- Minimal dependencies

defmodule MyApp do
      use Drafter.App
      
      def mount(_props) do
        %{counter: 0}
      end
      
      def render(state) do
        Drafter.container([
          Drafter.label("Counter: \\#{state.counter}"),
          Drafter.button("Click me!", on_click: :increment)
        ])
      end
      
      def handle_event(:increment, state) do
        {:ok, %{state | counter: state.counter + 1}}
      end
    end
    
    Drafter.run(MyApp)
    

# `activate_widget`

```elixir
@spec activate_widget(atom()) :: term()
```

Programmatically activate (press) a widget by its ID.

# `animate`

```elixir
@spec animate(atom(), atom(), any(), keyword()) :: reference()
```

Animate a widget property.

## Properties

- `:opacity` - Opacity (0.0 to 1.0)
- `:background` - Background color (RGB tuple)
- `:color` - Foreground color (RGB tuple)
- `:offset_x` - X offset in cells
- `:offset_y` - Y offset in cells

## Options

- `:duration` - Animation duration in ms (default: 300)
- `:easing` - Easing function (default: :ease_out)
- `:on_complete` - Callback when animation finishes

## Easing Functions

`:linear`, `:ease`, `:ease_in`, `:ease_out`, `:ease_in_out`,
`:ease_in_quad`, `:ease_out_quad`, `:ease_in_out_quad`,
`:ease_in_cubic`, `:ease_out_cubic`, `:ease_in_out_cubic`,
`:ease_in_elastic`, `:ease_out_elastic`,
`:ease_in_bounce`, `:ease_out_bounce`, `:ease_in_out_bounce`,
`:ease_in_back`, `:ease_out_back`

## Examples

    Drafter.animate(:my_button, :opacity, 0.5, duration: 500)
    Drafter.animate(:my_label, :background, {255, 0, 0}, duration: 1000, easing: :ease_out)

# `button`

```elixir
@spec button(
  String.t(),
  keyword()
) :: {Drafter.Widget.Button, map()}
```

Create a button widget

# `container`

```elixir
@spec container(
  [{module(), map()}],
  keyword()
) :: {Drafter.Widget.Container, map()}
```

Create a container widget

# `current_skin`

```elixir
@spec current_skin() :: atom()
```

Returns the currently active skin atom.

# `digits`

```elixir
@spec digits(
  String.t(),
  keyword()
) :: {Drafter.Widget.Digits, map()}
```

Create a digits widget for displaying large numbers

# `focus`

```elixir
@spec focus(term()) :: :ok
```

# `footer`

```elixir
@spec footer(
  String.t(),
  keyword()
) :: {Drafter.Widget.Footer, map()}
```

Create a footer widget

# `get_widget_state`

```elixir
@spec get_widget_state(atom()) :: struct() | nil
```

Get the full state of a widget by its ID.

Returns the complete widget state struct, useful for accessing
multiple fields or widget-specific data.

Returns `nil` if widget not found.

# `get_widget_value`

```elixir
@spec get_widget_value(atom()) :: term() | nil
```

Get the current value of a widget by its ID.

Returns the primary "value" of the widget:
- TextInput/TextArea: the text string
- Checkbox: boolean (checked?)
- Switch: boolean (enabled?)
- RadioSet: the selected option ID
- SelectionList: list of selected option IDs
- OptionList: the selected option ID
- Collapsible: boolean (expanded?)
- TabbedContent: the active tab index
- DataTable: list of selected row indices
- Tree: list of selected node IDs

Returns `nil` if widget not found.

# `grid`

```elixir
@spec grid(
  [{module(), map()}],
  keyword()
) :: {Drafter.Widget.Grid, map()}
```

Create a grid widget for layouts

# `horizontal`

```elixir
@spec horizontal(
  [{module(), map()}],
  keyword()
) :: {Drafter.Widget.Container, map()}
```

Create a horizontal layout container

# `label`

```elixir
@spec label(
  String.t(),
  keyword()
) :: {Drafter.Widget.Label, map()}
```

Create a label widget

# `markdown`

```elixir
@spec markdown(
  String.t(),
  keyword()
) :: {Drafter.Widget.Markdown, map()}
```

Create a markdown widget

# `placeholder`

```elixir
@spec placeholder(
  String.t(),
  keyword()
) :: {Drafter.Widget.Placeholder, map()}
```

Create a placeholder widget

# `query_all`

```elixir
@spec query_all(String.t()) :: [atom()]
```

Query all widgets matching CSS-like selector.

Returns list of widget_ids.

# `query_one`

```elixir
@spec query_one(String.t()) :: atom() | nil
```

Query a single widget by CSS-like selector.

Selector examples:
- "Button" - first Button widget
- "#submit" - widget with id :submit
- ".primary" - widget with class :primary
- "Button.primary" - Button with class :primary

Returns widget_id or nil if not found.

# `rule`

```elixir
@spec rule(keyword()) :: {Drafter.Widget.Rule, map()}
```

Create a rule (divider line) widget

# `run`

```elixir
@spec run(
  module(),
  keyword()
) :: :ok
```

Start a TUI application.

Options:
  * `:scroll_optimization` - `true` (default) uses a fast render path during
    scroll gestures (`render_hierarchy` from ETS) and defers a full `render_app`
    until 150 ms after the last scroll event. Set to `false` to disable and
    trigger a full `render_app` on every scroll tick — maximum freshness at the
    cost of higher CPU during scroll.
  * `:syntax_highlighting` - `true` to enable tree-sitter syntax highlighting.

# `run_session`

```elixir
@spec run_session(module(), map(), keyword()) :: :ok | {:error, term()}
```

Run an app module in an isolated or shared session using pre-started session services.

`session_ctx` must contain: `event_manager`, `compositor`, `screen_manager`,
`theme_manager`, `event_handler` as pid values.

Options:
  - `:mode` - `:isolated` (default) or `:shared`
  - `:shared_state` - pid of SharedState server when mode is `:shared`
  - All other opts are passed as mount props to the app module

# `send_app_event`

```elixir
@spec send_app_event(atom(), term()) :: term()
```

Send an app event to the active app loop.

Used by modal screens and sub-screens to communicate results back to the
parent application via `handle_event/3`.

# `set_interval`

```elixir
@spec set_interval(pos_integer(), atom()) :: :ok
```

Set an interval timer

# `set_skin`

```elixir
@spec set_skin(atom()) :: :ok
```

Switch the active rendering skin.

The skin controls which characters `Drafter.CharacterSet` returns for every
widget render. Built-in skins: `:graphical` (default), `:wireframe`, `:ascii`.

Can be called from inside `handle_event/2` or `on_timer/2` — takes effect on
the next frame.

# `set_theme`

```elixir
@spec set_theme(String.t()) :: :ok
```

Switches the active theme by name.

# `set_timeout`

```elixir
@spec set_timeout(pos_integer(), atom()) :: :ok
```

Set a one-time timeout timer

# `stop_all_animations`

```elixir
@spec stop_all_animations(atom()) :: :ok
```

Stop all animations for a widget.

# `stop_animation`

```elixir
@spec stop_animation(reference()) :: :ok
```

Stop an animation by its reference.

# `validate_widget`

```elixir
@spec validate_widget(atom()) :: :ok | {:error, String.t()}
```

Validate a widget's value.
Sends :validate event to widget, triggering its validators.

# `vertical`

```elixir
@spec vertical(
  [{module(), map()}],
  keyword()
) :: {Drafter.Widget.Container, map()}
```

Create a vertical layout container

---

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