# `Keyfob.Components`
[🔗](https://github.com/alexdont/keyfob/blob/v0.1.0/lib/keyfob/components.ex#L1)

Unstyled, headless-ish function components for the two surfaces of the
flow: the desktop QR `panel/1` and the phone `confirm_screen/1`.

They ship minimal structural markup and Tailwind/daisyUI-friendly
classes but assume nothing about your design system — override via the
`class` slots or wrap them. All copy is passed in (or defaulted in
English) so the host owns i18n.

# `confirm_screen`

The phone confirm screen. Shows the requesting device (from the
request's `meta`) and Approve / Deny buttons.

**Never** auto-approve — the whole point of this screen is the human
check against QR-jacking.

Attributes:

  * `:meta` — the request meta map (`:browser`, `:os`, `:ip`, etc.;
    all optional). Whatever keys you put in `create_request/1`.
  * `:state` — `:pending | :approved | :denied | :expired`
  * `:approve_event` / `:deny_event` — `phx-click` names.
  * `:labels` — copy overrides.

## Attributes

* `meta` (`:map`) - Defaults to `%{}`.
* `state` (`:atom`) (required)
* `approve_event` (`:string`) - Defaults to `"keyfob_approve"`.
* `deny_event` (`:string`) - Defaults to `"keyfob_deny"`.
* `class` (`:string`) - Defaults to `nil`.
* `labels` (`:map`) - Defaults to `%{}`.

# `panel`

The desktop QR panel. Render the SVG produced by `Keyfob.QR.svg/2` and
reflect the waiting state.

Attributes:

  * `:qr_svg` — the inline SVG string (required unless `state != :waiting`)
  * `:state` — `:waiting | :approved | :denied | :expired` (required)
  * `:refresh_event` — `phx-click` event name for the "New code" button
    shown on `:expired`. Default `"keyfob_refresh"`.
  * `:labels` — map overriding the default copy.

## Attributes

* `qr_svg` (`:string`) - Defaults to `nil`.
* `state` (`:atom`) (required)
* `refresh_event` (`:string`) - Defaults to `"keyfob_refresh"`.
* `class` (`:string`) - Defaults to `nil`.
* `labels` (`:map`) - Defaults to `%{}`.

---

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