Prompt Input
Un champ de discussion qui démarre sur une seule ligne sobre, grandit en carte à mesure que vous écrivez et descend une fois la conversation lancée. Entrée envoie, sans risque avec la saisie japonaise et chinoise. Collez, déposez ou choisissez des fichiers avec aperçus, progression et nouvel essai. @ ajoute des fichiers et / lance des commandes depuis un menu au niveau du curseur. Un sélecteur de modèle avec touches numériques, un curseur d’effort qui s’anime à Max, un anneau de contexte, la dictée avec forme d’onde en direct, des chips d’outils, une file pour les messages saisis pendant qu’une réponse arrive en streaming, et des brouillons qui survivent à un rechargement.
Le champ de saisie est la partie d’un chat que l’on touche le plus, donc chaque frappe doit être juste. Prompt Input démarre sur une seule ligne sobre avec le + à gauche et l’envoi à droite, grandit en carte quand le texte passe à la ligne ou qu’on ajoute des fichiers, et se replie une fois vidé.
Enter envoie et Shift+Enter ajoute une ligne, et les méthodes de saisie pour le japonais, le chinois et le coréen ne sont jamais interrompues. Sur les écrans tactiles, Enter ajoute une ligne, puisque le clavier n’a pas de Shift. Les insertions passent par la pile d’annulation propre au navigateur, donc ⌘Z fonctionne toujours, et les longs collages deviennent une pièce jointe que vous pouvez prévisualiser ou remettre en ligne.
Tout est composé de parties qui partagent un seul contexte. Utilisez seulement le champ et le bouton d’envoi, ou ajoutez des envois de fichiers avec progression et nouvel essai, des menus @ et / au curseur, un sélecteur de modèle, un curseur d’effort, un anneau de contexte, la dictée, des chips d’outils, une file pour les messages envoyés pendant qu’une réponse arrive en streaming, et des brouillons qui survivent à un rechargement.
Prompt Input est gratuit. Installez-le sans compte ni token, et utilisez-le sous la Licence Pro dans autant de projets que vous voulez.
pnpm dlx shadcn@latest add https://hextaui.com/r/pro/prompt-input.jsonAvec AI SDK
Passez le status et stop de useChat. Les fichiers arrivent sous forme de FileUIPart avec une URL de données, et un message saisi pendant qu’une réponse arrive en streaming est mis en file et envoyé à la fin de celle-ci.
Modèle, effort et dictée
Placez le sélecteur de modèle, le curseur d’effort et l’anneau de contexte sous le champ de saisie avec PromptInputMeta. Activez des outils depuis le menu + et affichez-les en chips. Passez transcribe pour envoyer les enregistrements à votre propre modèle vocal, et autoSend pour envoyer dès que le texte arrive.
Mentions et commandes
Ajoutez un menu par déclencheur. @ transforme un choix en chip au-dessus du texte, et / insère la commande. Les flèches déplacent, Enter ou Tab choisit et Escape ferme, sans quitter le texte.
Envoi de fichiers
Donnez à upload une fonction qui rapporte la progression et respecte le signal d’abandon. Levez UploadError avec retryable: false pour les erreurs qu’un nouvel essai ne peut pas corriger, comme un fichier trop volumineux pour le serveur.
Harnais d’agent
Enveloppez le corps dans PromptInputInset et ajoutez un PromptInputFooter. Utilisez PromptInputSelect pour le mode, le lieu d’exécution et le dossier de travail.
Anatomie
Les parties à composer, de l’extérieur vers l’intérieur.
| Partie | Description |
|---|---|
PromptInput | Le formulaire et l’état partagé : texte, fichiers, mentions, file et statut. |
PromptInputBody | La surface arrondie qui passe du mode compact au mode étendu. |
PromptInputTextarea | Le champ. Toute la gestion du clavier se trouve ici. |
PromptInputTools | Côté gauche : le menu + et les chips d’outils. |
PromptInputActions | Côté droit : dictée et envoi. |
PromptInputSubmit | Envoyer, arrêter ou mettre en file, selon le status et le texte. |
PromptInputAttachments | Chips de fichiers et de mentions au-dessus du texte. |
PromptInputMenu | Un menu au curseur pour un caractère déclencheur. |
PromptInputMeta | La rangée sous le champ de saisie pour les contrôles de modèle, d’effort et de contexte. |
PromptInputModel | Un seul contrôle pour le modèle et l’effort, avec le switch de réflexion. |
PromptInputInset | Une coque discrète autour du corps qui contient une rangée de pied de page, pour les harnais d’agents. |
PromptInputFooter | La rangée à l’intérieur de la coque inset pour les contrôles de lieu, de dossier et de session. |
PromptInputSelect | Un sélecteur compact pour les modes, le lieu d’exécution, les dossiers ou les dépôts. |
PromptInputQueue, PromptInputSuggestions, PromptInputMeter | Messages en file, prompts de départ et compteur de caractères près de maxLength. |
PromptInput
Accepte aussi toutes les props de form sauf onSubmit et defaultValue.
| Prop | Type | Par défaut |
|---|---|---|
onSubmitReçoit { text, files, mentions }. Retournez une promesse pour conserver le texte jusqu’à sa résolution. | (message: PromptMessage) => void | Promise<unknown> | – |
statusPassez le status de useChat. Tant que c’est occupé, l’envoi devient arrêt ou mise en file. | "ready" | "submitted" | "streaming" | "error" | "ready" |
onStopAppelé depuis le bouton d’arrêt ou Escape. | () => void | – |
onEditLastRetournez le dernier message pour le charger avec ↑ dans un champ vide. | () => string | void | – |
valueTexte contrôlé. | string | – |
defaultValueTexte initial. | string | "" |
onValueChangeAppelé à chaque changement du texte. | (value: string) => void | – |
submitOnQuelle touche envoie. ⌘↵ envoie toujours. | "enter" | "mod+enter" | "enter" |
pasteLimitNombre de caractères avant qu’un collage devienne une pièce jointe. | number | false | 5000 |
maxLengthLimite stricte, affichée par PromptInputMeter. | number | – |
draftKeyEnregistre le texte non envoyé dans le stockage local sous cette clé. | string | – |
globalDropAccepte les fichiers déposés n’importe où sur la page. | boolean | false |
focusOnTypeTaper alors que rien d’autre n’a le focus commence la saisie ici. | boolean | false |
layoutForce une disposition au lieu de basculer. | "auto" | "compact" | "expanded" | "auto" |
acceptTypes de fichiers acceptés, comme l’attribut d’input. | string | – |
maxFilesNombre maximal de fichiers à la fois. | number | – |
maxFileSizePlus gros fichier en octets. | number | – |
uploadEnvoie chaque fichier. Levez UploadError avec retryable: false pour les échecs définitifs. | (file, { signal, onProgress }) => Promise<unknown> | – |
onRejectAppelé pour les fichiers dépassant une limite ou d’un mauvais type. | (file: File, reason: string) => void | – |
disabledDésactive tout le champ de saisie. | boolean | false |
| Prop | Type | Par défaut |
|---|---|---|
triggerLe caractère qui l’ouvre, comme @ ou /. | string | – |
items{ value, label, description?, icon?, hint?, keywords?, insert? } | PromptMenuItem[] | – |
modeLes mentions ajoutent une chip ; le texte insère insert ?? label. | "mention" | "text" | – |
labelLibellé de section en haut du menu. | string | – |
limitNombre maximal de lignes affichées. | number | – |
onSelectAppelé après un choix. | (item: PromptMenuItem) => void | – |
PromptInputModel
Le sélecteur de modèle et le curseur d’effort en un seul contrôle. Accepte aussi toutes les props de PromptInputEffort sauf value et onValueChange.
| Prop | Type | Par défaut |
|---|---|---|
modelsLes neuf premiers reçoivent les raccourcis 1 à 9. | { value, label }[] | – |
modelModèle sélectionné. | string | – |
onModelChangeAppelé au choix. | (value: string) => void | – |
levelsNiveaux d’effort, du plus faible au plus élevé. | { value, label }[] | – |
effortEffort sélectionné. | string | – |
onEffortChangeAppelé pendant le déplacement du curseur. | (value: string) => void | – |
| Prop | Type | Par défaut |
|---|---|---|
modelsLes neuf premiers reçoivent les raccourcis 1 à 9. | { value, label }[] | – |
valueModèle sélectionné. | string | – |
onValueChangeAppelé au choix. | (value: string) => void | – |
| Prop | Type | Par défaut |
|---|---|---|
levelsDu plus faible au plus élevé. | { value, label }[] | – |
valueNiveau sélectionné. | string | – |
onValueChangeAppelé pendant le déplacement du curseur. | (value: string) => void | – |
recommendedMarque un niveau comme recommandé. | string | – |
thinkingAffiche le switch de réflexion étendue lorsqu’il est défini. | boolean | – |
onThinkingChangeAppelé depuis le switch. | (thinking: boolean) => void | – |
thinkingLabelLibellé du switch. | string | – |
descriptionTexte d’aide dans l’infobulle. | string | – |
| Prop | Type | Par défaut |
|---|---|---|
usedTokens utilisés. | number | – |
limitTaille de la fenêtre de contexte. | number | – |
limitsLignes supplémentaires, comme l’utilisation du forfait. | { label, used, detail? }[] | – |
limitsLabelTitre de ces lignes. | string | – |
| Prop | Type | Par défaut |
|---|---|---|
transcribeEnvoie l’enregistrement à votre modèle vocal. Sans cela, la reconnaissance vocale du navigateur est utilisée. | (audio: Blob) => Promise<string> | – |
shortcutDémarre et termine un enregistrement de n’importe où. | string | false | "ctrl+shift+d" |
autoSendEnvoie dès que la transcription arrive. | boolean | false |
| Prop | Type | Par défaut |
|---|---|---|
iconAffiché dans la chip, et remplacé par × au survol. | ReactNode | – |
childrenNom de l’outil. | string | – |
toneCouleur de la chip. | "blue" | "green" | "amber" | "violet" | "pink" | "blue" |
onRemoveAppelé au clic sur la chip. | () => void | – |
| Prop | Type | Par défaut |
|---|---|---|
optionsLes choix. Les descriptions s’affichent sous chaque libellé. | { value, label, icon?, description? }[] | – |
valueOption sélectionnée. Laissez-la indéfinie pour afficher le placeholder. | string | – |
onValueChangeAppelé au choix. | (value: string) => void | – |
labelNom accessible et infobulle, comme Mode ou Run on. | string | – |
placeholderAffiché quand rien n’est sélectionné. | string | – |
iconAffiché quand l’option sélectionnée n’a pas d’icône. | ReactNode | – |
headingLibellé en haut du menu. | string | – |
shortcutParcourt les options de n’importe où, comme alt+m. | string | – |
childrenItems de menu supplémentaires sous les options, comme Open folder. | ReactNode | – |
| Touche | Action |
|---|---|
| Enter | Envoie. Sur les écrans tactiles, il ajoute une ligne à la place. |
| ShiftEnter | Ajoute une ligne. |
| ⌘Enter | Envoie toujours, même quand submitOn vaut mod+enter. |
| Esc | Arrête une réponse en streaming, ferme un menu ou annule un enregistrement. |
| ↑ | Dans un champ vide, rappelle votre dernier message lorsque onEditLast est défini. |
| ↑↓ | Parcourt un menu @ ou / ouvert. |
| EnterTab | Choisit la ligne de menu en surbrillance. |
| 1–9 | Choisit un modèle tant que le menu des modèles est ouvert. |
| ←→ | Déplace le curseur d’effort. Home et End sautent aux extrémités. |
| CtrlShiftD | Démarre la dictée, et insère la transcription à la deuxième pression. |
| AltM | Fait défiler un PromptInputSelect qui a shortcut="alt+m", comme le mode de l’agent. |
- Le champ a un placeholder visible et un nom accessible, et chaque bouton d’icône a un libellé et une infobulle avec son raccourci.
- Le menu au curseur est une combobox avec aria-activedescendant, donc le focus ne quitte jamais le texte pendant que vous le parcourez.
- Les envois, rejets, changements de file et la dictée sont annoncés via une région live polie.
- Le contrôle d’effort est un curseur avec un texte de valeur, et il continue de fonctionner avec les flèches, Home et End.
- Les champs de saisie font au moins 16px sur les écrans tactiles, donc iOS ne zoome jamais au focus.
- Avec réduction des animations, les changements de hauteur, la forme d’onde et le remplissage de l’effort se stabilisent sans animation.
Construit avec
Les composants HextaUI gratuits dont Prompt Input est constitué. Chacun s’installe séparément.
Code
10 fichiers, ajoutés à components/blocks/prompt-input.