Rich event struct with DOM-like three-phase dispatch and propagation control.
An Event.Object carries an event's type and payload alongside phase tracking,
propagation control, and a monotonic timestamp. Events travel through
three phases: :capture (root → target), :target, then :bubble
(target → root). Any handler may call prevent_default/1,
stop_propagation/1, or stop_immediate_propagation/1 to modify how
the event continues.
from_tuple/1 builds one from a Drafter.Event tuple and to_tuple/1 returns
that form, for code that pattern-matches on raw tuples. The round trip is not
lossless: phase, target and propagation flags are dropped by to_tuple/1.
Struct fields:
:type— event type atom (:key,:char,:mouse,:focus,:blur,:focus_in,:focus_out,:mount,:unmount,:show,:hide,:load,:custom,:resize,:timer):data— event payload, format varies by type:target— widget id that is the final event target:current_target— widget id currently processing the event:phase— current dispatch phase (:capture,:target, or:bubble):default_prevented— true afterprevent_default/1:propagation_stopped— true afterstop_propagation/1orstop_immediate_propagation/1:immediate_propagation_stopped— true afterstop_immediate_propagation/1:timestamp—System.monotonic_time(:millisecond)at creation
Summary
Functions
Wrap an event tuple in an event object.
Build an event object of type carrying data.
Mark the event's default action as prevented.
Stop the event travelling further, including to other handlers on the current widget.
Stop the event travelling to the next widget in the dispatch path.
Unwrap an event object back to the event tuple form.
Types
@type event_type() ::
:key
| :char
| :mouse
| :focus
| :blur
| :focus_in
| :focus_out
| :mount
| :unmount
| :show
| :hide
| :load
| :custom
| :resize
| :timer
@type phase() :: :capture | :target | :bubble
Functions
Wrap an event tuple in an event object.
Recognised tuples are the ones listed in Drafter.Event; a bare atom becomes an
event of that type with nil data, any other two-element tuple becomes an event
whose type is its first element, and anything else becomes :custom carrying the
whole term. {:key, key, modifiers} is folded into %{key: key, modifiers: mods}
data and {:resize, {w, h}} into %{width: w, height: h}, both of which
to_tuple/1 restores.
The phase starts at :bubble and the timestamp is taken now. :target and
:current_target are left nil, so a caller that needs them must set them
afterwards.
Examples
iex> event = Drafter.Event.Object.from_tuple({:key, :enter})
iex> {event.type, event.data, event.phase}
{:key, :enter, :bubble}
iex> Drafter.Event.Object.from_tuple({:key, :a, [:ctrl]}).data
%{key: :a, modifiers: [:ctrl]}
iex> Drafter.Event.Object.from_tuple({:resize, {80, 24}}).data
%{width: 80, height: 24}
iex> event = Drafter.Event.Object.from_tuple(:tick)
iex> {event.type, event.data}
{:tick, nil}
iex> event = Drafter.Event.Object.from_tuple({:scroll, :up})
iex> {event.type, event.data}
{:scroll, :up}
iex> event = Drafter.Event.Object.from_tuple({:a, :b, :c, :d})
iex> {event.type, event.data}
{:custom, {:a, :b, :c, :d}}
@spec new(event_type(), term(), keyword()) :: t()
Build an event object of type carrying data.
Options:
:target— widget id the event is aimed at, defaultnil:current_target— widget id currently handling it, defaultnil:phase—:capture,:targetor:bubble, default:bubble:timestamp— defaultSystem.monotonic_time(:millisecond)
The propagation flags always start false. Nothing is validated: type is
stored as given, even when it is not one of event_type/0.
Examples
iex> Drafter.Event.Object.new(:key, :enter, timestamp: 0)
%Drafter.Event.Object{
type: :key,
data: :enter,
target: nil,
current_target: nil,
phase: :bubble,
default_prevented: false,
propagation_stopped: false,
immediate_propagation_stopped: false,
timestamp: 0
}
iex> event = Drafter.Event.Object.new(:key, :enter, target: :save, phase: :capture)
iex> {event.target, event.phase}
{:save, :capture}
Mark the event's default action as prevented.
Does not stop the event travelling; handlers further along still see it and can
read :default_prevented.
Examples
iex> Drafter.Event.Object.new(:key, :enter)
...> |> Drafter.Event.Object.prevent_default()
...> |> Map.fetch!(:default_prevented)
true
Stop the event travelling further, including to other handlers on the current widget.
Sets both :immediate_propagation_stopped and :propagation_stopped.
Examples
iex> event = Drafter.Event.Object.new(:key, :enter)
iex> event = Drafter.Event.Object.stop_immediate_propagation(event)
iex> {event.propagation_stopped, event.immediate_propagation_stopped}
{true, true}
Stop the event travelling to the next widget in the dispatch path.
Handlers already reached on the current widget are unaffected, and
:immediate_propagation_stopped stays false.
Examples
iex> event = Drafter.Event.Object.stop_propagation(Drafter.Event.Object.new(:key, :enter))
iex> {event.propagation_stopped, event.immediate_propagation_stopped}
{true, false}
Unwrap an event object back to the event tuple form.
The inverse of from_tuple/1 for every tuple it recognises. Phase, target and
propagation flags are dropped, so a caller that needs them must read them from
the object before converting.
:focus, :blur, :focus_in and :focus_out with nil data give the
one-element tuple {:focus} and friends. An event of any type this function does
not name gives the bare type atom when its data is nil, and {type, data}
otherwise. A named type with nil data still gives a tuple: :key with nil
data is {:key, nil}, not :key.
Examples
iex> Drafter.Event.Object.new(:key, %{key: :a, modifiers: [:ctrl]})
...> |> Drafter.Event.Object.to_tuple()
{:key, :a, [:ctrl]}
iex> Drafter.Event.Object.new(:resize, %{width: 80, height: 24})
...> |> Drafter.Event.Object.to_tuple()
{:resize, {80, 24}}
iex> Drafter.Event.Object.to_tuple(Drafter.Event.Object.new(:focus, nil))
{:focus}
iex> Drafter.Event.Object.to_tuple(Drafter.Event.Object.new(:custom, nil))
:custom
iex> Drafter.Event.Object.to_tuple(Drafter.Event.Object.new(:key, nil))
{:key, nil}