# `Mob.Nav.Registry`
[🔗](https://github.com/genericjam/mob/blob/master/lib/mob/nav/registry.ex#L1)

ETS-backed registry mapping screen name atoms to their modules.

Populated at startup by walking an `Mob.App` module's `navigation/1`
declarations for both platforms. Hot-code-reload safe — the mapping stores
module atoms, not captured references.

`register/2` is available for runtime additions: A/B testing, library screens,
or dynamic feature flags.

## Two things are recorded, not one

Walking `navigation/1` produces a flat **route table** (`name -> {module,
params}`) that backs `push_screen/2,3` and friends, and a per-platform
**layout** that preserves the declaration tree — which stacks a `tab_bar/1`
or `drawer/1` contains, and in what order.

The route table alone records only that a stack name exists. That was the
whole of what this module kept, which is why `Mob.App.tab_bar/1` could be
declared but not backed by the runtime: nothing downstream could tell that
`:home` and `:settings` were sibling stacks rather than two unrelated routes.
`Mob.Nav.from_layout/2` consumes the layout to build one independent stack per
branch. See `decisions/2026-08-27-screen-process-architecture.md`.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `layout`

```elixir
@spec layout(atom()) :: map() | nil
```

Return the navigation layout declared for `platform`, or `nil`.

The layout is the raw map returned by the app's `navigation/1` — a
`Mob.App.stack/2`, `tab_bar/1`, or `drawer/1` declaration. `nil` when the
registry has not been started (tests that drive a screen directly) or when
the app declared nothing for this platform.

# `lookup`

```elixir
@spec lookup(atom()) :: {:ok, module()} | {:error, :not_found}
```

Look up the module registered under `name`.

Returns `{:ok, module}` or `{:error, :not_found}`.

# `lookup_route`

```elixir
@spec lookup_route(atom()) :: {:ok, module(), map()} | {:error, :not_found}
```

Look up the module AND route-bound params registered under `name`.

Route-bound params let N routes share one parameterized screen module (the
data-driven-plugin pattern — e.g. mob_ash registers `/ash/post/list` as
`{MobAsh.ListScreen, %{resource: MyApp.Post}}`). Navigation merges them
UNDER the caller's `push_screen` params, then passes the result to `mount/3`.

# `register`

```elixir
@spec register(atom(), module(), map()) :: :ok
```

Register a `name → module` mapping at runtime, optionally with route-bound
`params` delivered to the screen's `mount/3` whenever this route is the
navigation destination (see `lookup_route/1`).

Overwrites any existing entry for `name`.

# `start_link`

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

Start the registry, seeding it from the given App module.

Normally started by `Mob.Nav.Registry.start_link/1` in your application
supervisor. In tests, start it directly.

---

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