The unified event emission API for Mob.
See guides/event_model.md for the full event model.
Two responsibilities:
Emit — given an
%Address{}, an event atom, and a payload, deliver the canonical envelope{:mob_event, addr, event, payload}to the right pid (resolving in-tree or external targets).Match — small helpers (
is_event?/1,match_address?/2) for handler code that wants to filter incoming events by address fields.
This module is the single doorway between native event sources and
user-level handler code. Every emitter (taps, gestures, lifecycle, custom
components) eventually calls Mob.Event.emit/4 (or dispatch/4, for
pre-resolved pids).
Summary
Types
The shape of every event message delivered to a handler.
Functions
Send the event to an already-resolved pid.
Resolve target and deliver the event.
True if msg matches the canonical event envelope shape.
True if addr matches all the given filters.
Synthesize an event delivery to pid. Useful for tests — bypasses the
native side entirely.
Types
@type envelope() :: {:mob_event, Mob.Event.Address.t(), atom(), term()}
The shape of every event message delivered to a handler.
Functions
@spec dispatch(pid(), Mob.Event.Address.t(), atom(), term()) :: :ok
Send the event to an already-resolved pid.
Used when the renderer pre-resolved the target at registration time and passes the pid directly. Skips re-resolution.
Also broadcasts to any Mob.Event.Trace subscribers (zero cost when no
tracers are registered).
@spec emit( Mob.Event.Address.t(), atom(), term(), Mob.Event.Target.spec(), Mob.Event.Target.render_scope() ) :: :ok
Resolve target and deliver the event.
Best-effort delivery: if the target can't be resolved (dead pid, unknown registered name, component not in the ancestor chain), logs a debug message and drops the event.
Returns :ok always. Errors from resolution are logged, not raised — losing
one event from a stale handle should never crash the BEAM.
True if msg matches the canonical event envelope shape.
iex> Mob.Event.is_event?({:mob_event, %Mob.Event.Address{screen: S, widget: :x, id: :y}, :tap, nil})
true
iex> Mob.Event.is_event?({:tap, :something})
false
@spec match_address?( Mob.Event.Address.t(), keyword() ) :: boolean()
True if addr matches all the given filters.
Filters is a keyword list of address fields and the values they must equal.
Useful for one-off matches in handle_info/2 clauses where you don't want
to write a full struct pattern.
iex> addr = %Mob.Event.Address{screen: S, widget: :button, id: :save}
iex> Mob.Event.match_address?(addr, widget: :button)
true
iex> addr = %Mob.Event.Address{screen: S, widget: :button, id: :save}
iex> Mob.Event.match_address?(addr, widget: :button, id: :cancel)
false
@spec send_test( pid(), atom() | pid(), atom(), Mob.Event.Address.id(), atom(), term(), keyword() ) :: :ok
Synthesize an event delivery to pid. Useful for tests — bypasses the
native side entirely.
Mob.Event.send_test(self(), MyScreen, :button, :save, :tap, nil)
assert_receive {:mob_event, %Address{id: :save}, :tap, nil}