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

# `lr-flow-node`

- **Import** `import '@aceshooting/lyra-ui/components/lr-flow-node.js';` (stable tag alias; registers the tag)
- **Class** `LyraFlowNode`, also available unregistered from `@aceshooting/lyra-ui/components/data/flow-node/flow-node.class.js`
- **Family** `components/data/` — 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** 12 parts, 14 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-flow-node`

The card a workflow node renders as: header/body/toolbar chrome, tool-lifecycle status tones, and
the named connection-handle elements edges anchor to. Used as `lr-flow-canvas`'s default card and
as a slotted override; also renders standalone (palette previews, docs). Purely presentational —
activation, selection, movement, and connection are all `lr-flow-canvas` events; this component
owns none of that.

**Properties:**

- `nodeId: string = ''` (attribute `node-id`, reflected) — identity used to match an authored card
  to a canvas node; the empty default leaves the attribute absent
- `flowType: string = ''` (attribute `data-node-type`, reflected) — consumer taxonomy forwarded by
  the canvas; use this stable hook or the canvas's normalized `node-type-*` part for type-specific
  presentation
- `heading: string = ''`
- `status: 'pending' | 'running' | 'success' | 'error' | 'denied' | null = null` (reflected)
- `progress: number | null = null` — renders a determinate `[part="progress"]` bar when set
- `statusDetail: string = ''` (attribute `status-detail`) — appended to the status line
- `durationMs: number | null = null` (attribute `duration-ms`) — formatted into the status line
- `selected: boolean = false` (reflected)
- `compact: boolean = false` (reflected) — tighter card padding for dense canvases and palette
  previews; the border, background, shadow and the `selected`/`status="running"` treatments all stay
- `inputs: readonly FlowHandle[] = [{ id: 'in' }]`, `outputs: readonly FlowHandle[] = [{ id: 'out'
}]` (attribute: false) — detached, frozen snapshots of at most the first 10,000 readonly
  `{ id, label? }` handles; blank ids and later duplicates are omitted first-valid/first-wins
  (a record rejected for an unreadable optional label does not reserve its ID);
  reassign a collection after changes
- `orientation: 'horizontal' | 'vertical' = 'horizontal'` (reflected) — which physical edge handles
  render on; mirrors the adopting canvas's own `orientation`

**Events:** none — purely presentational, activation/drag/connect all live on `lr-flow-canvas`.

**Slots:** default (body content), `icon` (leading header glyph), `header` (replaces the built-in
heading row entirely), `toolbar` (action row at the block-end edge; revealed by hover/focus on
hover-capable devices and always visible with a coarse pointer or no hover).

**CSS parts:** `base` (the row wrapping the input handles, the card and the output handles — it
carries no card chrome of its own), `card` (the bordered, filled node card), `header`, `icon`,
`heading`, `status` (never color-only — always paired with text), `progress`, `body`, `toolbar`,
`handle` (every handle dot), `handle-input`, `handle-output`.

**Themeable custom properties:** `--lr-flow-node-min-inline-size` (default `11rem`),
`--lr-flow-node-compact-padding` (default `var(--lr-space-xs)`) and `--lr-flow-node-compact-gap`
(default `var(--lr-space-2xs)`) — `[part="card"]`'s padding and row gap while `compact` — and
`--lr-flow-node-selected-outline-color` (default `var(--lr-color-brand)`) — the card's outline color
while `selected`. Like the other state-scoped custom properties here, it is an inline `var()`
fallback at its point of use rather than a `:host` declaration, so it can be set on the element _or any
ancestor_ (a canvas retunes every card at once); overriding the selection color otherwise means
hijacking the library-wide `--lr-color-brand` token and repainting everything else that reads it.
`--lr-flow-node-running-border` (default `var(--lr-color-brand)`) — the card's border color while
`status="running"`, independent of `--lr-flow-node-selected-outline-color` so a consumer can retint
just one of the two states without the other following along — and `--lr-flow-node-running-glow` (default
`var(--lr-color-brand-quiet)`) — the box-shadow color of the running-state ring around the card, and
the pulse keyframes' peak color. The status dot uses the shared
`--lr-flow-status-{pending|running|success|error|denied}-color` hooks, defaulting respectively
to border-strong, brand, success, danger, and warning; `--lr-flow-status-color` is the no-status
fallback. The explicit status hooks are `--lr-flow-status-pending-color`,
`--lr-flow-status-running-color`, `--lr-flow-status-success-color`,
`--lr-flow-status-error-color`, and `--lr-flow-status-denied-color`.
`--lr-flow-node-progress-track-color` (default
`var(--lr-color-border)`) and `--lr-flow-node-progress-fill-color` (default
`var(--lr-color-brand)`) independently retint the determinate progress track and fill. All of
these hooks inherit, so one canvas-level override can retint every descendant node without
changing a library-wide semantic token.

**Optional peer deps:** none.

```html
<lr-flow-node
  node-id="a"
  heading="Fetch"
  status="running"
  progress="40"
></lr-flow-node>
```

**Known gotchas:**

- A running node's card pulses (`?data-pulse`) unless `prefers-reduced-motion` is set — the same
  reduced-motion exception every animated surface in this library follows.
- `status` drives a status chip with a localized label plus `statusDetail`/`durationMs`, never a
  color-only indicator.
- All card chrome lives on `[part="card"]`, not `[part="base"]` — `base` is only the flex row that
  holds the input handles, the card and the output handles. Style the box through `::part(card)`.
- Empty `header`, body, and toolbar rows are removed from layout and update when slot contents are
  added or removed. A populated toolbar remains visible on coarse-pointer/no-hover devices rather
  than depending on an unavailable hover gesture. Invalid status/orientation inputs normalize to
  the documented canonical values.
- Selection uses an outline, while the running lifecycle uses its own border and glow; the two
  remain simultaneously visible.
- `--lr-flow-node-min-inline-size` was previously overridden by a duplicate declaration and had no
  effect. It now sets the card's minimum inline size again, so a node that was relying on the card
  collapsing below `11rem` will render wider than it used to.

---
