Prompt Input
Um campo de conversa que começa como uma linha discreta, cresce até virar um card conforme você escreve e desce quando a conversa começa. Enter envia, de forma segura com entrada em japonês e chinês. Cole, solte ou escolha arquivos com prévias, progresso e nova tentativa. @ adiciona arquivos e / executa comandos a partir de um menu no cursor. Um seletor de modelo com teclas numéricas, um slider de esforço que ganha vida no Max, um anel de contexto, ditado com forma de onda ao vivo, chips de ferramentas, uma fila para mensagens digitadas enquanto uma resposta é transmitida e rascunhos que sobrevivem a um recarregamento.
O composer é a parte de um chat que as pessoas mais tocam, então cada tecla precisa passar a sensação certa. O Prompt Input começa como uma linha discreta com o + à esquerda e enviar à direita, cresce até virar um card quando o texto quebra ou arquivos são adicionados e volta ao normal quando é limpo.
Enter envia e Shift+Enter adiciona uma linha, e os métodos de entrada para japonês, chinês e coreano nunca são interrompidos. Em telas de toque, Enter adiciona uma linha, já que o teclado não tem Shift. As inserções passam pela pilha de desfazer do próprio navegador, então ⌘Z sempre funciona, e colagens longas viram um anexo que você pode visualizar ou recolocar inline.
Tudo é composto a partir de partes que compartilham um único contexto. Use apenas o campo e o botão de enviar, ou adicione uploads de arquivo com progresso e nova tentativa, menus @ e / no cursor, um seletor de modelo, um slider de esforço, um anel de contexto, ditado, chips de ferramentas, uma fila para mensagens enviadas enquanto uma resposta chega em streaming e rascunhos que sobrevivem a um recarregamento.
O Prompt Input é gratuito. Instale-o sem conta nem token e use-o sob a Licença Pro em quantos projetos quiser.
pnpm dlx shadcn@latest add https://hextaui.com/r/pro/prompt-input.jsonCom o AI SDK
Passe o status e o stop do useChat. Os arquivos chegam como FileUIPart com uma data URL, e uma mensagem digitada enquanto uma resposta chega em streaming entra na fila e é enviada quando ela termina.
Modelo, esforço e ditado
Coloque o seletor de modelo, o slider de esforço e o anel de contexto sob o composer com PromptInputMeta. Ative ferramentas pelo menu + e mostre-as como chips. Passe transcribe para enviar as gravações ao seu próprio modelo de fala e autoSend para enviar assim que o texto chegar.
Menções e comandos
Adicione um menu por gatilho. @ transforma uma escolha em um chip acima do texto, e / insere o comando. As setas movem, Enter ou Tab escolhem e Escape fecha, tudo sem sair do texto.
Enviando arquivos
Dê ao upload uma função que informe o progresso e respeite o sinal de cancelamento. Lance UploadError com retryable: false para erros que uma nova tentativa não resolve, como um arquivo grande demais para o servidor.
Harness de agente
Envolva o corpo em PromptInputInset e adicione um PromptInputFooter. Use PromptInputSelect para o modo, onde ele roda e em qual pasta trabalha.
Anatomia
As partes que você compõe, de fora para dentro.
| Parte | Descrição |
|---|---|
PromptInput | O formulário e o estado compartilhado: texto, arquivos, menções, fila e status. |
PromptInputBody | A superfície arredondada que alterna entre compacta e expandida. |
PromptInputTextarea | O campo. Todo o tratamento de teclado fica aqui. |
PromptInputTools | Lado esquerdo: o menu + e os chips de ferramentas. |
PromptInputActions | Lado direito: ditado e enviar. |
PromptInputSubmit | Enviar, parar ou enfileirar, dependendo do status e do texto. |
PromptInputAttachments | Chips de arquivos e menções acima do texto. |
PromptInputMenu | Um menu no cursor para um caractere de gatilho. |
PromptInputMeta | A linha sob o composer para os controles de modelo, esforço e contexto. |
PromptInputModel | Um único controle para o modelo e o esforço, com o switch de thinking. |
PromptInputInset | Uma casca discreta ao redor do corpo que abriga uma linha de rodapé, para harnesses de agentes. |
PromptInputFooter | A linha dentro da casca inset para os controles de local, pasta e sessão. |
PromptInputSelect | Um seletor compacto para modos, local de execução, pastas ou repositórios. |
PromptInputQueue, PromptInputSuggestions, PromptInputMeter | Mensagens na fila, prompts iniciais e um medidor de caracteres perto de maxLength. |
PromptInput
Também aceita todas as props de form, exceto onSubmit e defaultValue.
| Prop | Tipo | Padrão |
|---|---|---|
onSubmitRecebe { text, files, mentions }. Retorne uma promise para manter o texto até ela ser resolvida. | (message: PromptMessage) => void | Promise<unknown> | – |
statusPasse o status do useChat. Enquanto ocupado, enviar vira parar ou enfileirar. | "ready" | "submitted" | "streaming" | "error" | "ready" |
onStopChamado pelo botão de parar ou por Escape. | () => void | – |
onEditLastRetorne a última mensagem para carregá-la com ↑ em um campo vazio. | () => string | void | – |
valueTexto controlado. | string | – |
defaultValueTexto inicial. | string | "" |
onValueChangeChamado conforme o texto muda. | (value: string) => void | – |
submitOnQual tecla envia. ⌘↵ sempre envia. | "enter" | "mod+enter" | "enter" |
pasteLimitCaracteres antes de uma colagem virar um anexo. | number | false | 5000 |
maxLengthLimite rígido, exibido pelo PromptInputMeter. | number | – |
draftKeySalva o texto não enviado no armazenamento local sob esta chave. | string | – |
globalDropAceita arquivos soltos em qualquer lugar da página. | boolean | false |
focusOnTypeDigitar enquanto nada mais tem o foco começa a digitar aqui. | boolean | false |
layoutForça um layout em vez de alternar. | "auto" | "compact" | "expanded" | "auto" |
acceptTipos de arquivo aceitos, como o atributo do input. | string | – |
maxFilesMáximo de arquivos de uma vez. | number | – |
maxFileSizeMaior arquivo em bytes. | number | – |
uploadEnvia cada arquivo. Lance UploadError com retryable: false para falhas permanentes. | (file, { signal, onProgress }) => Promise<unknown> | – |
onRejectChamado para arquivos acima de um limite ou do tipo errado. | (file: File, reason: string) => void | – |
disabledDesabilita o composer inteiro. | boolean | false |
| Prop | Tipo | Padrão |
|---|---|---|
triggerO caractere que o abre, como @ ou /. | string | – |
items{ value, label, description?, icon?, hint?, keywords?, insert? } | PromptMenuItem[] | – |
modeAs menções adicionam um chip; text insere insert ?? label. | "mention" | "text" | – |
labelRótulo de seção no topo do menu. | string | – |
limitMáximo de linhas exibidas. | number | – |
onSelectChamado após uma escolha. | (item: PromptMenuItem) => void | – |
PromptInputModel
O seletor de modelo e o slider de esforço em um só controle. Também aceita todas as props do PromptInputEffort, exceto value e onValueChange.
| Prop | Tipo | Padrão |
|---|---|---|
modelsOs nove primeiros ganham os atalhos 1–9. | { value, label }[] | – |
modelModelo selecionado. | string | – |
onModelChangeChamado ao escolher. | (value: string) => void | – |
levelsNíveis de esforço, do menor ao maior. | { value, label }[] | – |
effortEsforço selecionado. | string | – |
onEffortChangeChamado enquanto o slider se move. | (value: string) => void | – |
| Prop | Tipo | Padrão |
|---|---|---|
modelsOs nove primeiros ganham os atalhos 1–9. | { value, label }[] | – |
valueModelo selecionado. | string | – |
onValueChangeChamado ao escolher. | (value: string) => void | – |
| Prop | Tipo | Padrão |
|---|---|---|
levelsDo menor ao maior. | { value, label }[] | – |
valueNível selecionado. | string | – |
onValueChangeChamado enquanto o slider se move. | (value: string) => void | – |
recommendedMarca um nível como recomendado. | string | – |
thinkingMostra o switch de extended-thinking quando definido. | boolean | – |
onThinkingChangeChamado pelo switch. | (thinking: boolean) => void | – |
thinkingLabelRótulo do switch. | string | – |
descriptionTexto de ajuda no tooltip. | string | – |
| Prop | Tipo | Padrão |
|---|---|---|
usedTokens usados. | number | – |
limitTamanho da janela de contexto. | number | – |
limitsLinhas extras, como o uso do plano. | { label, used, detail? }[] | – |
limitsLabelTítulo dessas linhas. | string | – |
| Prop | Tipo | Padrão |
|---|---|---|
transcribeEnvia a gravação ao seu modelo de fala. Sem isso, o reconhecimento de fala do navegador é usado. | (audio: Blob) => Promise<string> | – |
shortcutInicia e finaliza uma gravação de qualquer lugar. | string | false | "ctrl+shift+d" |
autoSendEnvia assim que a transcrição chegar. | boolean | false |
| Prop | Tipo | Padrão |
|---|---|---|
iconExibido no chip, e substituído por × no hover. | ReactNode | – |
childrenNome da ferramenta. | string | – |
toneCor do chip. | "blue" | "green" | "amber" | "violet" | "pink" | "blue" |
onRemoveChamado quando o chip é clicado. | () => void | – |
| Prop | Tipo | Padrão |
|---|---|---|
optionsAs opções. As descrições aparecem sob cada rótulo. | { value, label, icon?, description? }[] | – |
valueOpção selecionada. Deixe sem definir para mostrar o placeholder. | string | – |
onValueChangeChamado ao escolher. | (value: string) => void | – |
labelNome acessível e tooltip, como Mode ou Run on. | string | – |
placeholderExibido quando nada está selecionado. | string | – |
iconExibido quando a opção selecionada não tem ícone. | ReactNode | – |
headingRótulo no topo do menu. | string | – |
shortcutPercorre as opções de qualquer lugar, como alt+m. | string | – |
childrenItens de menu extras abaixo das opções, como Open folder. | ReactNode | – |
| Tecla | Ação |
|---|---|
| Enter | Envia. Em telas de toque, adiciona uma linha. |
| ShiftEnter | Adiciona uma linha. |
| ⌘Enter | Sempre envia, mesmo quando submitOn é mod+enter. |
| Esc | Interrompe uma resposta em streaming, fecha um menu ou cancela uma gravação. |
| ↑ | Em um campo vazio, traz de volta sua última mensagem quando onEditLast está definido. |
| ↑↓ | Percorre um menu @ ou / aberto. |
| EnterTab | Escolhe a linha do menu em destaque. |
| 1–9 | Escolhe um modelo enquanto o menu de modelos está aberto. |
| ←→ | Move o slider de esforço. Home e End saltam para as extremidades. |
| CtrlShiftD | Inicia o ditado e insere a transcrição quando pressionado de novo. |
| AltM | Alterna um PromptInputSelect que tem shortcut="alt+m", como o modo do agente. |
- O campo tem um placeholder visível e um nome acessível, e todo botão de ícone tem um rótulo e um tooltip com seu atalho.
- O menu no cursor é um combobox com aria-activedescendant, então o foco nunca sai do texto enquanto você o percorre.
- Os uploads, as rejeições, as mudanças na fila e o ditado são anunciados por uma região live polite.
- O controle de esforço é um slider com um texto de valor e continua funcionando com as setas, Home e End.
- Os inputs têm pelo menos 16px em telas de toque, para que o iOS nunca dê zoom ao focar.
- Com movimento reduzido, as mudanças de altura, a forma de onda e o preenchimento do esforço se assentam sem animação.
Construído com
Os componentes gratuitos do HextaUI de que Prompt Input é feito. Cada um é instalado separadamente.
Código
10 arquivos, adicionados a components/blocks/prompt-input.