Accessibility
ChatInput, ChatInputLayout, hasSendableText from @prepared911/ui/chat-input.
The typed area is a textbox with aria-multiline. ChatInput renders no label; the screen names it with aria-label or aria-labelledby. The placeholder is exposed as aria-placeholder, a hint and not a name. The add, Send and Stop controls are icon-only Buttons named by addLabel, sendLabel and stopLabel, each also shown as a tooltip. The context chips and the suggestions are lists named by chipsLabel and suggestionsLabel.
enterKeyHint="send" labels the Enter key on mobile keyboards.removedAnnouncement politely; a removal by cut or select-all announces nothing, since the person made that edit on purpose. Context chips are in a named list above the text.
A disabled Send cannot be focused, so sendDisabledAnnouncement is announced politely when the person empties the text and when they press Enter in an empty composer. While a response generates and there is no Stop, Send shows a spinner, sets aria-busy, stays focusable, and announces its pending name. It is not disabled.
aria-disabled, and disables every control (ADR 0015), including Stop and Send while a response generates: a disabled composer shows Send disabled, not pending.tabindex="0", aria-readonly) and never sends. While a response generates, Stop stays usable (stopping is not editing the text) and a pending Send stays focusable and ignores presses.aria-invalid; the surface edge changes weight and, under forced colors, color. The error text belongs to Field or the screen, wired with aria-describedby.forced-colors: active the surface border stays, the focused surface takes Highlight, and the invalid state adds a strong Mark border.
ChatInput adds none. The controls keep their own: Send swaps its arrow and spinner at once under reduced motion, and the menu and tooltips follow the preference. The height follows the text with no transition.