Mob.Nav.Registry (mob v0.7.39)

Copy Markdown View Source

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.

Summary

Functions

Returns a specification to start this module under a supervisor.

Return the navigation layout declared for platform, or nil.

Look up the module registered under name.

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

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).

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

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

layout(platform)

@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(name)

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

Look up the module registered under name.

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

lookup_route(name)

@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(name, module, params \\ %{})

@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(app_module)

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