Prompt Bar
A composer with real controls, where typing @ or / opens a menu by the word, and what you pick sits in the text on a plate.
Usage
import { PromptBar } from '@wdzyi/ui';
<PromptBar
sources={[{ id: 'roadmap', name: 'Roadmap', kind: 'file' }]}
commands={[{ name: 'summarise', note: 'The key points' }]}
models={[
{ id: 'fast', name: 'Fast' },
{ id: 'deep', name: 'Deep' },
]}
busy={replying}
onStop={stop}
onSend={(message) => ask(message)}
/>Part of @wdzyi/ui. See setup to install it, or copy the code above.
Props
- value, defaultValue, onValueChangestring
- The text. Pass value and onValueChange to hold it yourself, or leave them out and it keeps its own.
- sourcesPromptBarSource[]
- Offered when @ is typed. Each has an id, a name, a note beside it, and a kind, which is file, folder, web or data, for its icon.
- commandsPromptBarCommand[]
- Offered when / is typed: a name without the slash, and a note.
- models, model, defaultModel, onModelChangePromptBarModel[], string
- The models to choose from, each with an id, a name and a note, and the chosen one’s id. Without one, it’s the first.
- recentPromptBarFile[]
- Files to offer under the attach button, beside uploading one.
- files, onFilesChangePromptBarFile[]
- What’s attached, if you’d rather hold it yourself. Files uploaded or dropped on the bar carry the File itself.
- onSend(message: PromptBarMessage) => void
- Called with the text, the same text in parts with what was picked marked, the files and the model. The bar empties itself after.
- onDictate(signal: AbortSignal) => Promise<string>
- Called when the microphone is pressed, and aborted if it’s pressed again. Resolve with what was heard. Without it, there’s no microphone.
- busy, onStopboolean, () => void = false
- A reply is on its way. Send waits, and becomes Stop if there’s an onStop.
- placeholder, labelstring = 'Ask anything', 'Message'
- What the empty field says, and its name for screen readers.
Notes
- The plates are painted by a copy of the text under the field, in clear ink, so a plate can never move a letter. Backspace just after one takes it out whole.
- Menus float in a portal, above the bar or below it if there’s more room, and start where the word does. The field keeps the focus while one is open, so typing narrows it, and one plate glides between the rows.
- The caret is drawn, so it glides as you type and blinks once you stop. On touch, it’s the field’s own.
- Under 360px wide, the @ and / buttons go, since typing does the same. Files can be dropped on the bar as well as attached.
- The demo types at a person’s pace, 70 to 140ms a key with a pause before a long word, and each model thinks before it answers, from 0.6 seconds for Fast to 2 for Deep, then streams its reply with Streaming Text. With reduced motion, the caret is the field’s own, menus appear without rising, and the light on Stop holds still.