<!-- GENERATED by scripts/build-llms.mjs from llms/utility.md — do not edit this file. -->

# `lr-poll-status`

- **Import** `import '@aceshooting/lyra-ui/components/lr-poll-status.js';` (stable tag alias; registers the tag)
- **Class** `LyraPollStatus`, also available unregistered from `@aceshooting/lyra-ui/components/utility/poll-status/poll-status.class.js`
- **Family** `components/utility/` — see `llms/index.md` for its siblings
- **Status** `stable` since `4.0.0` — see the maturity and deprecation policy in `llms/shared.md`
- **Release history** [CHANGELOG.md](../../CHANGELOG.md); family-wide breaking-change summaries: [llms-full.txt](../../llms-full.txt)
- **Deprecations** none
- **Optional peers** none
- **Themeable via** 4 parts, 5 custom properties — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-poll-status`

A "next scheduled refresh" countdown with a built-in pause control: a ticking `M:SS` display counting
down to the next scheduled action, a "Refreshing…" state at zero, and a pause/resume toggle.
First-party invention (no Web Awesome equivalent); the closest existing component,
`<lr-stream-status>`, is scoped to transport/connection-health phases, a different concern from a
scheduled-interval countdown — this mirrors its internal `<lr-live-region>` composition for
accessible phase-transition announcements.

Long localized status labels, including unbroken words, wrap within the component’s allocated inline
size in LTR and RTL. The indicator and pause/resume action retain their size; the 320px example
shows both inactive and refreshing states.

**Properties:**

- `nextInMs?: number` (attribute `next-in-ms`) — milliseconds until the next scheduled action, as of
  whenever this was last set; setting it (re)starts the countdown from "now." Unset (the default)
  shows no countdown.
- `active: boolean = true` (reflected) — whether the poll cycle is running at all.
- `paused: boolean = false` (reflected) — user-toggled pause; while `true`, the countdown display
  freezes and `lr-poll-due` never fires.

**Events:** `lr-poll-due` (no detail — fired once when the countdown reaches zero, not fired while
`paused`), `lr-pause-change` (`detail: { paused: boolean }` — fired when `paused` changes via the
built-in button).

**Methods:** `restart(): void` — restarts the currently configured `nextInMs` delay from now,
including after its previous deadline fired. With `nextInMs` unset it simply clears the due state.

**Slots:** none.

**CSS parts:** `base`, `indicator` (the pulsing status dot), `countdown` (the `M:SS`, or
"Refreshing…", text), `pause-button` (the built-in pause/resume toggle).

**Themeable custom properties:** `--lr-poll-status-due-bg` (default `var(--lr-color-success)`) —
background of `indicator` while `data-due` is set. Component-scoped indirection over the shared
`--lr-color-success` token, so a consumer can retheme just this due-state indicator without
repainting every other component that reuses the same shared success token. `--lr-poll-status-pause-hover-bg`/`--lr-poll-status-pause-hover-color` (defaults
`var(--lr-color-brand-quiet)`/`var(--lr-color-brand)`) and
`--lr-poll-status-pause-active-bg`/`--lr-poll-status-pause-active-color` (defaults the former
brand-quiet active `color-mix()`/`var(--lr-color-brand)`) retheme the built-in `pause-button`'s
hover/pressed paint independently of those same shared brand tokens. Plus shared tokens —
`--lr-space-xs`, `--lr-font-size-sm`,
`--lr-color-text-quiet`, `--lr-color-brand`, `--lr-color-success`, `--lr-radius`/`-pill`,
`--lr-focus-ring-*`.

**Optional peer deps:** none.

```html
<lr-poll-status next-in-ms="30000"></lr-poll-status>
<script type="module">
  const status = document.querySelector("lr-poll-status");
  status.addEventListener("lr-poll-due", () => refreshData());
  status.addEventListener("lr-pause-change", (e) =>
    console.log("paused:", e.detail.paused)
  );
</script>
```

Internally, owner-window timeouts schedule both the exact deadline and the next displayed-second
boundary from a captured target timestamp, so a zero/short delay does not wait for a one-second
poll and the countdown stays accurate after background throttling. Assigning a _changed_
`nextInMs` value starts a fresh deadline; assigning the same value is a normal Lit no-op, so use
`restart()` for a new cycle with the same delay. Entering `paused` captures the bounded remaining
duration; every resume establishes a new deadline from that frozen value. Changing `nextInMs` or
calling `restart()` while paused replaces the frozen duration without starting time. Toggling
`active`, disconnecting/reconnecting, or toggling either after the due event stops/starts only an
unconsumed ticker: a consumed deadline never replays until `nextInMs` changes or `restart()` is
called. Phase transitions ("Paused.", "Resumed.", "Refreshing now.") are announced via an internal
`<lr-live-region>` in polite mode.

**Known gotchas:**

- `restart()` is the explicit reset/extend path when the configured delay value itself has not
  changed.
- `active="false"` and `paused` both stop the ticker independently, but only `paused` fires
  `lr-pause-change` — that event is scoped to the built-in pause button's own toggle, not to
  `active`.
- the countdown rounds up while time remains. If a deadline is already elapsed when the ticker is
  armed — including a due-immediately or sufficiently short cycle — it can render "0:00" for one
  update before the scheduled due tick advances it to "Refreshing…".

---
