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

# `lr-selection-toolbar`

- **Import** `import '@aceshooting/lyra-ui/components/lr-selection-toolbar.js';` (stable tag alias; registers the tag)
- **Class** `LyraSelectionToolbar`, also available unregistered from `@aceshooting/lyra-ui/components/conversation/selection-toolbar/selection-toolbar.class.js`
- **Family** `components/conversation/` — see `llms/index.md` for its siblings
- **Status** `stable` since `7.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, 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-selection-toolbar`

Nonmodal, Escape-dismissible text-selection toolbar carrying selected text plus a format-neutral
`DocumentLocator` into ask, quote, cite, and copy actions.

**Properties:** `open: boolean = false` (reflected); `text: string = ''`;
clone-owned `anchor: DocumentLocator | null = null`, `rect: DOMRectReadOnly | null = null`, and
clone-owned `actions: readonly SelectionAction[] = ['ask', 'quote', 'cite', 'copy']` (attribute: false);
`label: string = ''`; `accessibleLabel: string | null = null` (attribute `aria-label`).
`SelectionAction = 'ask' | 'quote' | 'cite' | 'copy'`. Duplicate built-in names are omitted
first-wins before rendering, roving focus, and action events. The anchor (including any path) and
actions are bounded frozen snapshots; reassign a new record or array after changes.

When a controlled `actions` refresh replaces the focused action, focus follows the same action id
through reordering, otherwise moves to the nearest surviving action, or to the stable toolbar when
the action set becomes empty. The same repair applies when a slotted action is removed or becomes
disabled, hidden, inert, `aria-disabled`, or no longer actionable. Availability and `tabindex`
changes are observed live, stale stops are cleared, and a newer focus destination is never
overridden. Observation is rebound to the current document realm when the toolbar is adopted.

**Events:** `lr-selection-action` (`SelectionActionDetail = { action, text, anchor }`);
`lr-dismiss` (`null`, Escape); `lr-copy` (frozen `{ ok: true, text }`, only after the clipboard
write fulfills); and, on failure, `lr-error` (`null`) plus frozen `lr-copy-error`
(`{ ok: false, text, reason, error }`). A failed copy does not emit the action event.
Detaching and later reinserting the same open instance re-establishes positioning and Escape
ownership even when the detach lasts past an event-loop turn.

**CSS parts:** `toolbar`, `action`, `action-ask`, `action-quote`, `action-cite`, `action-copy`.

The four built-in actions are the shipped set, and `actions` only reorders or subsets them. A
product-specific fifth action ("translate", "define", "search web") goes in the `actions` slot
instead: slotted elements render after the built-ins **inside** the same `role="toolbar"` element
and join the same roving-tabindex group (Home/End/Arrow, RTL-mirrored), so adding one does not mean
reimplementing the toolbar's positioning, keyboard, and dismissal behavior. A slotted action brings
its own accessible name and click handling; this component only manages its tab stop, and re-derives
the group whenever the slot's assigned elements change. The group resolves actual composed action
targets through open shadow roots and forwarding slots; decorative wrappers are not accepted as
stops, while multiple actionable descendants remain independently arrow-reachable. Keyboard
movement starts from the action that received the event rather than stale controlled state.

`rect` is the sole public positioning input. Internal computed coordinates are intentionally
private so controlled rect updates cannot be silently overridden by stale authored CSS.
**Themeable custom properties:** `--lr-selection-toolbar-placement-gap` (default
`var(--lr-space-s)`) is the non-negative distance from the selection and from viewport edges while
the toolbar avoids collisions. It accepts unitless pixel values and `px`, `rem`, and `em` values; unsupported
values fall back to the default and negative values clamp to `0`. Collision math uses the active
`visualViewport` bounds and offsets when available, including after visual-viewport changes.

The toolbar is a floating surface and paints from the **shared overlay-surface family** (16.0.0):
`--lr-overlay-surface` (default `var(--lr-color-surface-overlay)`), `--lr-overlay-border` (default
`var(--lr-color-border)`) and `--lr-overlay-shadow-anchored` (default `var(--lr-shadow-m)`). None is
declared on `:host`, so one declaration on `:root` — or on any ancestor, to scope it — retints this
surface together with every other floating surface in the library. `--lr-overlay-radius` (default `var(--lr-radius)`) is the matching corner radius.

**Slots:** `actions` — extra actions rendered after the built-in ask/quote/cite/copy buttons,
inside the same `role="toolbar"` element and roving-tabindex group. **Optional peer deps:** none.

```ts
import "@aceshooting/lyra-ui/components/conversation/selection-toolbar/selection-toolbar.js";
```
