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

# `lr-calendar-viewer`

- **Import** `import '@aceshooting/lyra-ui/components/lr-calendar-viewer.js';` (stable tag alias; registers the tag)
- **Class** `LyraCalendarViewer`, also available unregistered from `@aceshooting/lyra-ui/components/viewers/calendar-viewer/calendar-viewer.class.js`
- **Family** `components/viewers/` — 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)
- **Deprecations** none
- **Optional peers** `ical.js` — see `llms/peers.md`
- **Themeable via** 11 parts, 1 custom property — see this component's own `@csspart`/`@cssprop` list below
- **Library-wide behavior** (events, form association, `locale`/`strings`, tokens, TS types): `llms/shared.md`

---

## `lr-calendar-viewer`

Fetches and parses `.ics` calendars with the optional `ical.js` peer and renders each VEVENT as
plain text, including its title, start/end time, location, and description. RFC 5545 `DATE` values
remain all-day dates rather than fabricated midnight times, and an all-day `DTEND` is displayed as
the exclusive boundary it represents (14–17 renders as 14–16). No HTML is injected.

Valid early all-day dates, including years `0001`, `0099`, and `0100`, retain their UTC calendar
year when parsed through `ical.js`; the exclusive `DTEND` display rule remains unchanged. The peer
may normalize malformed raw date fields before Lyra receives them.

**Properties:** `src: string = ''`, `name: string = ''`, and `maxHeight: string = ''` (attribute
`max-height`); invalid CSS
`max-height` values, declaration breaks, and `url()` are ignored. A host `aria-label` takes
precedence over `name` by attribute presence, including an explicitly empty value. `highlights`,
`activeHighlightId`, `anchor`, and
`anchorKinds` (`['text-quote', 'fragment']`) provide the shared text-viewer contract. Fragment
resolution is an exact DOM `id` lookup, but generated event markup defines no fragment ids, so a
fragment jump reports `found: false`. Use a text-quote anchor for event content.

**Methods:** `search(query)`, `searchNext()`, `searchPrevious()`, `clearSearch()`, and
`scrollToAnchor()` operate on rendered event text and emit `lr-search-change`/`lr-anchor-result`.

**Events:**

- `lr-render-error` with `detail.error` when fetching or parsing fails.
- `lr-search-change` — `detail: { query: string; matchCount: number; matchCountExact: boolean; activeIndex: number }` — fired
  whenever rendered-calendar search state changes.
- `lr-anchor-result` — `detail: { found: boolean }` — fired after an `anchor` assignment or
  `scrollToAnchor()` call is applied.
- `lr-text-select` — `detail: TextSelectDetail` (`{ text: string; anchor: LyraAnchor | null; rects:
DOMRect[] }`) — fired after a selection ends inside the rendered calendar.

`lr-highlight-activate` is not part of this viewer's event contract: painted text highlights are
passive and cannot be activated.

The three shared text-viewer events bubble and compose and are non-cancelable.

**CSS parts:** `base`, `body`, `event-list`, `event`, `event-summary`, `event-time`, `event-location`,
`event-description`, `spinner`, `error`, and `anchor-live-region` (an aria-hidden, non-live shadow
mirror of the latest anchor-jump message; the spoken copy is appended to the shared document-level
polite sink only while the viewer and its composed ancestors are exposed to the accessibility tree).

**Themeable custom properties:** `--lr-calendar-viewer-max-height` (default `none`) — maximum block
size of `[part="body"]`; also settable via the `max-height` property, which writes this token inline.

**Optional peer dependency:** install `ical.js` with `pnpm add ical.js`. The component registers
`text/calendar` and falls back to matching `.ics` filenames in `<lr-document-viewer>`.

Remote resources are capped at 25 MB; exceeding it surfaces the localized
`documentPreviewResourceTooLarge` message instead of the calendar. The accepted model is further
capped at 250 events and 2 MiB of rendered event text; this keeps the complete accepted document in
the DOM so search, selection and text-quote anchors remain truthful without the former 10,000-event
eager tree.
