# `StatifierUI.EventInjection.Palette`
[🔗](https://github.com/riddler/statifier-ui/blob/v0.11.0/lib/statifier_ui/event_injection/palette.ex#L1)

A fixture bundle's `events` map (ADR-0003), turned into a sorted list of
`StatifierUI.EventInjection.Entry.t()` a form can render as buttons.

`build/1` accepts a `StatifierUI.Fixtures.t()` or `nil`. `nil` (or a bundle
with no events at all) yields an empty palette with no diagnostics - the
degraded mode `StatifierUI.EventInjection` turns into its
`free_form_only?` flag.

Every entry's payload is encoded through `StatifierUI.Value.encode/1` and
then `StatifierUI.Trace.Json.encode_to_string/1` - the same canonical,
byte-stable JSON encoder the trace wire format uses, reused here because a
`Value.encode/1` result is exactly the "JSON-ready term" shape that encoder
is typed against. Nothing about the trace wire format itself is touched;
an injected event is an input, not a trace message.

A fixture event whose payload falls outside predicator's value domain (a
tuple, a pid, a struct other than `Date`/`DateTime`) does not fail the
whole build: the entry is omitted and a diagnostic is appended, in the same
`StatifierUI.Fixtures.diagnostic()` shape a bundle itself already carries.
One bad sample takes down one button, not the pane.

## Atom-keyed payloads do not round-trip

`StatifierUI.Fixtures` validates scenario datamodels deeply but leaves
event payloads verbatim, so a behaviour source can hand over an
atom-keyed payload map. ADR-0005 says atom keys "serializ[e] as their
names", which is exactly what `StatifierUI.Trace.Json.encode_to_string/1`
produces and what `StatifierUI.Value.decode/1` reads back as strings. An
entry's `payload` field keeps the atoms; its `payload_text`, and therefore
any event actually sent from it, carries the string-keyed form. This is
correct rather than lossy: the engine's datamodel is string-keyed, and a
JSON sidecar could never have expressed the atoms in the first place.

# `t`

```elixir
@type t() :: %StatifierUI.EventInjection.Palette{
  diagnostics: [StatifierUI.Fixtures.diagnostic()],
  entries: [StatifierUI.EventInjection.Entry.t()]
}
```

# `build`

```elixir
@spec build(StatifierUI.Fixtures.t() | nil) :: {:ok, t()} | {:error, term()}
```

Builds a palette from a fixture bundle's `events` map, or an empty palette
from `nil`.

Walks `StatifierUI.Fixtures.event_names/1` (already sorted, ADR-0005's
canonical order), so entries and diagnostics both come back in event-name
order. Returns `{:error, {:invalid_fixtures, other}}` for anything that is
neither a `StatifierUI.Fixtures.t()` nor `nil`.

# `entry`

```elixir
@spec entry(t(), String.t()) :: {:ok, StatifierUI.EventInjection.Entry.t()} | :error
```

Fetches an entry by event name. Mirrors `StatifierUI.Fixtures.event/2`'s
`{:ok, _} | :error` shape.

# `names`

```elixir
@spec names(t()) :: [String.t()]
```

Event names in the palette, sorted.

---

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