# `MingaEditor.UI.Picker.Candidate`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/ui/picker/candidate.ex#L1)

Lean, pre-normalized scoring representation of a picker `%Item{}`.

The picker's filtering hot path used to re-downcase the label, strip the icon
prefix, and rebuild the searchable text for every candidate on every keystroke.
A `Candidate` precomputes those fields once when the item list is set, so
scoring a large set only does the match work, not the normalization work.

A candidate carries a reference to its source `item` (for late display
enrichment) and a stable `index` reflecting the source's original ordering,
which `Scorer` uses to break score ties exactly as the previous brute-force
sort did.

Match positions and per-render display state deliberately do not live here;
they are derived for the bounded winners only.

# `t`

```elixir
@type t() :: %MingaEditor.UI.Picker.Candidate{
  index: non_neg_integer(),
  item: MingaEditor.UI.Picker.Item.t(),
  label_length: non_neg_integer(),
  norm_label: String.t(),
  norm_search: String.t()
}
```

# `from_item`

```elixir
@spec from_item(MingaEditor.UI.Picker.Item.t(), non_neg_integer()) :: t()
```

Builds a single candidate from an item and its index.

# `from_items`

```elixir
@spec from_items([MingaEditor.UI.Picker.Item.t()]) :: [t()]
```

Builds the candidate cache for a list of items, preserving order and tagging
each candidate with its original index.

---

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