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

# `lr-prompt-input`

- **Import** `import '@aceshooting/lyra-ui/components/lr-prompt-input.js';` (stable tag alias; registers the tag)
- **Class** `LyraPromptInput`, also available unregistered from `@aceshooting/lyra-ui/components/conversation/prompt-input/prompt-input.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** 10 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-prompt-input`

The composed prompt surface: chat composer, attachment controls/chips, model and voice pickers,
retrieval-source scope, mention/slash-command popup, and queued follow-up prompts. It performs no
upload, retrieval, or model call. It is deliberately not form-associated: the complete interaction
state includes attachments, source scope, model, voice, and queued turns rather than one successful
string form entry. Observe `lr-input` for controlled text and handle `lr-submit` as the submission
request. `label` names the prompt section; it is not generic field chrome.

**Properties:** `value: string = ''`; `status: 'idle' | 'sending' | 'streaming' = 'idle'`;
`placeholder: string = ''`; `disabled: boolean = false` (reflected); `readOnly: boolean = false`
(attribute `readonly`, reflected); `minLength?: number` (attribute `minlength`) and
`maxLength?: number` (attribute `maxlength`);
`submitOnEnter: boolean = true` (attribute `submit-on-enter`, string-aware true-default converter);
`spellcheck: boolean = true` (string-aware true-default converter), `autocapitalize: string = ''`,
`autocorrect: boolean = true` (legacy string writes `'off'`/`'false'` normalize to `false`),
`wrap: 'hard' | 'soft' | 'off' = 'soft'`,
`autocomplete: string = ''`, `inputMode: string = ''` (attribute `inputmode`), and
`enterKeyHint: string = ''` (attribute `enterkeyhint`) forward unchanged to the composed native
textarea; empty string hints preserve the browser default.
Invalid `status` values read as `idle` without rewriting the host attribute.
`attachments: readonly LyraPromptInputAttachment[] = []` — `attachmentId` must be nonempty and
unique; malformed rows and later duplicates are omitted first-wins before rendering and attachment
events, and surviving chips reconcile by `attachmentId`. `attachmentCapabilities: readonly
LyraAttachmentCapability[] = ['files', 'image', 'audio']`, `mentionItems: readonly LyraPromptSuggestion[] =
[]`, `commandItems: readonly LyraPromptSuggestion[] = []`,
`modelCatalog?: LyraCatalog<LyraModelCatalogEntry>`,
`voiceCatalog?: LyraCatalog<LyraVoiceCatalogEntry>`,
`sources: readonly LyraSourceEntry[] = []`, `selectedSourceIds: readonly string[] = []`, and `queue:
readonly PromptQueueItem[] = []` (all attribute: false); `model: string = ''`; `voice: string = ''`;
`label: string = ''`; `accessibleLabel: string | null = null` (attribute `aria-label`).
Source roots and queued prompts require unique nonblank `id` values; malformed rows and later
duplicates are omitted first-wins before section gating and child forwarding. Controlled selected
source ids use the same unique nonblank projection.

Every array-valued property above is a clone-owned, bounded, frozen readonly snapshot, including
nested source children and queued attachments. Mutating a previously assigned collection has no
effect; create and reassign a new array after changes.

`LyraPromptSuggestion` extends `LyraMentionItem { suggestionId, label, description?, icon?, disabled? }`
with optional `insertText` (defaults to `label`). The selected occurrence's original, pre-filter `index`
is preserved in the event detail. `LyraPromptInputAttachment` replaces `DocumentRef.id` with
`attachmentId` and adds `file?`, `bytes?`, `status?: 'pending' | 'uploading' | 'error' | 'success'`,
and numeric `progress?`.

**Methods:** `focus(options?)`, `blur()`, and `click()` forward to the composed chat input;
`select()` selects its native text surface. `click()` is inert while disabled. `input:
HTMLTextAreaElement | null`, `selectionStart: number | null`, `selectionEnd: number | null`, and
`selectionDirection: ChatComposerSelectionDirection | null` mirror the composed textarea.
`setSelectionRange(start, end, direction?)` and overloaded
`setRangeText(replacement[, start, end, selectMode])` use the same native range-editing contract;
`setRangeText()` synchronizes outer `value` without emitting `lr-input`. Selection and range calls
are no-ops before the textarea has rendered.

**Events:** native `input`, `change`, `focus`, and `blur` are each relayed once from the primary
textarea, paired with `lr-input` and `lr-change`; `lr-submit` (`{ value }`),
`lr-stop` (`null`), `lr-mention-select` (`{ suggestionId, index, label, trigger }`),
`lr-attachments-add` (`{ capability, files }`), `lr-attachment-remove` (`{ attachmentId }`),
`lr-model-change`/`lr-voice-change`
(`{ value, inCatalog }`), `lr-sources-change` (`{ selectedSourceIds }`), `lr-queue-change`
(`{ items, reason, itemId }`), `lr-send-now` (`{ item }`), `lr-camera-request`,
`lr-audio-request`, `lr-attachment-retry` (`{ attachmentId }`), and cancelable
`lr-attachment-preview-request` (`{ attachmentId, name, mimeType, src }`). Child events are stopped
and re-emitted from `lr-prompt-input`; all composed interactions are suppressed while `disabled`,
including a child event dispatched in the same turn that disables the host.

**Slots:** `controls`; `start` (attachment-control content before the textarea); `chips`; `end`
(custom send/stop action); and `footer`. `start` replaces the default attachment trigger and `end`
replaces the built-in composer action.

**CSS parts:** `base`, `controls`, `sources`, `sources-summary`, `source-picker`, `queue`,
`composer`, `start`, `chips`, `footer`.

**Themeable custom properties:** `--lr-prompt-input-control-width` (default `--lr-size-12rem`) is
the preferred width of each generated model, voice, and source control before wrapping.

An open mention or command popup remains open only while focus is in the primary textarea or that
popup; moving focus to another prompt control or outside closes it. Arrow keys move focus to the
active option. Enter or Tab accepting an option is handled before textarea submission. Escape
restores the textarea's prior ARIA and selection. If the popup closes, becomes unavailable, or its
input/items change before focus moves, no move occurs. Empty `chips` and `footer` wrappers are not rendered, so an absent optional region cannot
create phantom spacing.

**Optional peer deps:** none of its own.

```ts
import "@aceshooting/lyra-ui/components/conversation/prompt-input/prompt-input.js";
```
