# `Mob.Event.NativeInput`
[🔗](https://github.com/genericjam/mob/blob/master/lib/mob/event/native_input.ex#L1)

Which messages are native input, and what each one is called outside the
screen it was meant for.

Native input never goes through `Mob.Event.dispatch/4`. The NIF delivers the
legacy tuples listed in `Mob.Listener` — `{:tap, tag}`, `{:change, tag,
value}`, `{event, tag}`, `{event, tag, payload}` — and the listener forwards
them to the screen as they are. So the two things that observe actions,
`Mob.Agent.Receipts` and `Mob.Event.Trace`, have to recognise them where they
land: in `Mob.Screen.Server`, and in `Mob.Listener` when the screen is gone.
This module is the one place that says which tuples those are.

## Discrete and stream

| Kind | Messages | Receipt | Trace |
|---|---|---|---|
| `:discrete` | `:tap` (list-row select included), `:focus`, `:blur`, `:submit`, `:select`, `:dismiss`, `:long_press`, `:double_tap`, `:press_in`, `:press_out`, `:swipe_left`/`_right`/`_up`/`_down`, `{:swipe, tag, direction}`, `{:change, tag, value}` except a float | yes | yes |
| `:stream` | `:scroll`, `:drag`, `:pinch`, `:rotate`, `:pointer_move`, `:compose`, a float `:change`, and the scroll lifecycle (`:scroll_began`, `:scroll_ended`, `:scroll_settled`, `:top_reached`, `:scrolled_past`) | no | yes |

A stream fires at up to display rate, or several times per gesture. The
receipt store keeps 256, so one scroll would evict the tap an agent is about
to ask about, and a receipt costs an assigns comparison and an ETS write per
frame. A float `:change` is a slider — the only native sender of a float
value — which reports every step of a drag. Text, toggle and tab changes stay
discrete: one per keystroke or flip is the rate a person acts at.

## Naming

An input is named by its canonical address and event atom, from
`Mob.Event.Bridge.legacy_to_canonical/3` where the Bridge models the shape.
Where it does not, the same rule applies with the widget kind the event
implies (`:text_field` for focus, blur and submit, `:sheet` for dismiss,
`:button` otherwise, as for a tap). A `:change` takes its widget from the
value's type, which is all native tells us about the control: a boolean is a
`:toggle`, a binary a `:text_field` (anything else keeps the Bridge's
default). A tag that is not a valid address id
(`Mob.Event.Address.validate_id/1`) is named `:opaque`.

A receipt carries the name and never the payload: a text field's value is
user data, and a receipt is written to ETS and handed to telemetry. A trace
carries the payload, as `Mob.Event.dispatch/4` always has — subscribing is an
explicit debugging act.

# `kind`

```elixir
@type kind() :: :discrete | :stream | :none
```

# `canonical`

```elixir
@spec canonical(tuple(), term()) :: {Mob.Event.Address.t() | :opaque, atom(), term()}
```

The canonical `{address, event, payload}` for a native input message, with
`:opaque` in place of the address when the tag is not a valid id.

# `kind`

```elixir
@spec kind(term()) :: kind()
```

Whether `message` is discrete native input, a stream, or not native input.

# `receipt_event`

```elixir
@spec receipt_event(tuple(), term()) :: {atom(), Mob.Event.Address.t() | :opaque}
```

What a receipt records for a native input: `{event, address}`, or
`{event, :opaque}`. Never the payload.

---

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