# `Mob.Screen`
[🔗](https://github.com/genericjam/mob/blob/main/lib/mob/screen.ex#L1)

The behaviour and process wrapper for a Mob screen.

A screen is a supervised GenServer. Its state is a `Mob.Socket`. Lifecycle
callbacks (`mount`, `render`, `handle_event`, `handle_info`, `terminate`) map
directly to the GenServer lifecycle.

## Usage

    defmodule MyApp.CounterScreen do
      use Mob.Screen

      def mount(_params, _session, socket) do
        {:ok, Mob.Socket.assign(socket, :count, 0)}
      end

      def render(assigns) do
        %{
          type: :column,
          props: %{},
          children: [
            %{type: :text, props: %{text: "Count: #{assigns.count}"}, children: []}
          ]
        }
      end

      def handle_event("increment", _params, socket) do
        {:noreply, Mob.Socket.assign(socket, :count, socket.assigns.count + 1)}
      end
    end

## Starting a screen

    {:ok, pid} = Mob.Screen.start_link(MyApp.CounterScreen, %{})

## Dispatching events

    :ok = Mob.Screen.dispatch(pid, "increment", %{})

# `socket`

```elixir
@type socket() :: Mob.Socket.t()
```

# `handle_event`
*optional* 

```elixir
@callback handle_event(event :: String.t(), params :: map(), socket :: socket()) ::
  {:noreply, socket()} | {:reply, map(), socket()}
```

# `handle_info`
*optional* 

```elixir
@callback handle_info(message :: term(), socket :: socket()) :: {:noreply, socket()}
```

# `mount`

```elixir
@callback mount(params :: map(), session :: map(), socket :: socket()) ::
  {:ok, socket()} | {:error, term()}
```

# `render`

```elixir
@callback render(assigns :: map()) :: map()
```

# `terminate`
*optional* 

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

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `dispatch`

```elixir
@spec dispatch(pid(), String.t(), map()) :: :ok
```

Dispatch a UI event to the screen process. Returns `:ok` synchronously once
the event has been processed and the state updated.

# `get_current_module`

```elixir
@spec get_current_module(pid()) :: module()
```

Return the module of the currently active screen in the navigation stack.
Intended for testing and debugging.

# `get_nav_history`

```elixir
@spec get_nav_history(pid()) :: [{module(), Mob.Socket.t()}]
```

Return the navigation history (list of `{module, socket}` pairs, head = most recent).
Intended for testing and debugging.

# `get_socket`

```elixir
@spec get_socket(pid()) :: socket()
```

Return the current socket state of a running screen.
Intended for testing and debugging — not for production app logic.

# `handle_call`

Apply a navigation action directly. Used by `Mob.Test` to drive navigation
programmatically without needing a UI event. Synchronous — the caller blocks
until the navigation (and re-render, in production mode) completes.

Valid actions mirror the `Mob.Socket` navigation functions:
- `{:push, dest, params}` — push a new screen
- `{:pop}` — pop to the previous screen
- `{:pop_to, dest}` — pop to a specific screen in history
- `{:pop_to_root}` — pop to the root of the current stack
- `{:reset, dest, params}` — replace the entire nav stack

# `start_link`

```elixir
@spec start_link(module(), map(), keyword()) :: GenServer.on_start()
```

Start a screen process linked to the calling process.

`params` is passed as the first argument to `mount/3`.

# `start_root`

```elixir
@spec start_root(module(), map(), keyword()) :: GenServer.on_start()
```

Start a screen as the root UI screen. Calls mount, renders the component tree
via `Mob.Renderer`, and calls `set_root` on the resulting view.

This is the main entry point for production use. `start_link/2` is for tests
(no NIF calls).

---

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