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

# `lr-graph-legend`

- **Import** `import '@aceshooting/lyra-ui/components/lr-graph-legend.js';` (stable tag alias; registers the tag)
- **Class** `LyraGraphLegend`, also available unregistered from `@aceshooting/lyra-ui/components/retrieval/graph-legend/graph-legend.class.js`
- **Family** `components/retrieval/` — 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** 6 parts, 2 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-graph-legend`

A node-type legend for a paired `lr-graph`: one swatch + label + count row per node type, doubling
as visibility filters. Never reads or writes a graph directly — the host forwards `types` in from
`graph.nodeTypes` and `hiddenTypes` back out to `graph.hiddenTypes` on `lr-visibility-change`, the
same event-decoupled contract every sibling in this family follows.

**Properties:**

- `types: LyraNodeTypeStyle[] = []` (attribute: false) — `{ id: string; label: string; color?:
string; shape?: 'circle' | 'square' | 'diamond' }`, the shared `lr-graph.nodeTypes` entry shape. A color is used only
  when valid for CSS `color`; declaration breaks and `url()` fall back to the categorical palette.
  Rows require nonblank string `id` and `label` values, with later duplicate ids omitted first-wins
- `counts?: Record<string, number>` (attribute: false) — optional per-type count shown alongside the
  label; values are rendered as finite nonnegative integers (invalid or negative values become zero)
- `hiddenTypes: string[] = []` (attribute: false) — controlled; the host assigns this back from
  `lr-visibility-change`
- `interactive: boolean = true` (reflected) — renders each row as a toggle `<button>`; `false` renders
  plain, non-interactive rows
- `label: string = ''` — fallback accessible name for the `role="group"` wrapper. A non-empty host
  `aria-label` makes the host the sole overall owner (the wrapper omits its duplicate role/name);
  an explicitly empty host label stays empty on the wrapper

**Events:** cancelable `lr-before-visibility-change` (`detail: { hiddenTypes }`, a frozen complete
next array) fires before a toggle changes state or announces it. Preventing it suppresses all three.
`lr-visibility-change` (`detail: { hiddenTypes }`, the complete updated array) fires after an
accepted assignment and announcement.

**Slots:** none.

**CSS parts:** `base`, `item` (a `<button>` when `interactive`, a plain `<div>` otherwise), `swatch`,
`label`, `count`, `live-region` (the visually hidden filter-toggle announcement).

**Themeable custom properties:** `--lr-graph-legend-hidden-color` (default
`var(--lr-color-text-quiet)`) — text color of a filtered-out (hidden) row's `label`/`count`,
independent of the shared quiet-text token so a host can retint "hidden" rows without repainting
every other quiet-text surface; `--lr-graph-legend-hidden-swatch-opacity` (default `0.5`) controls
only that row's decorative swatch opacity. Also reads `--lr-graph-cat-1` through `-8`
(the same computed-style fallback palette `lr-graph`/`lr-word-cloud` use) plus shared tokens.

**Optional peer deps:** none.

```html
<lr-graph-legend id="legend"></lr-graph-legend>
<lr-graph id="graph" style="height:480px"></lr-graph>
<script>
  const graph = document.getElementById("graph");
  const legend = document.getElementById("legend");
  legend.types = [
    { id: "person", label: "Person", color: "#0969da" },
    { id: "org", label: "Organization" },
  ];
  legend.addEventListener("lr-visibility-change", (e) => {
    legend.hiddenTypes = e.detail.hiddenTypes;
    graph.hiddenTypes = e.detail.hiddenTypes;
  });
</script>
```

**Known gotchas:**

- Ships no coupling to `lr-graph`'s optional `d3-force`/`d3-drag`/`d3-zoom`/`d3-selection` peers —
  `types`/`counts`/`hiddenTypes` are plain data the host derives from a graph, never a live reference
  to one.
- Blank type ids and later duplicates are omitted first-wins. `hiddenTypes` is likewise projected
  to nonblank first occurrences before visibility checks or change events.

---
