Prompt Input
Un compositor de chat que empieza como una línea tranquila, crece hasta convertirse en una tarjeta mientras escribes y baja cuando empieza la conversación. Enter envía, de forma segura con entrada en japonés y chino. Pega, suelta o elige archivos con vistas previas, progreso y reintento. @ añade archivos y / ejecuta comandos desde un menú junto al cursor. Un selector de modelo con teclas numéricas, un control deslizante de esfuerzo que cobra vida en Max, un anillo de contexto, dictado con forma de onda en vivo, chips de herramientas, una cola para los mensajes escritos mientras se transmite una respuesta y borradores que sobreviven a una recarga.
El compositor es la parte del chat que más toca la gente, así que cada pulsación tiene que sentirse bien. Prompt Input empieza como una línea tranquila con el + a la izquierda y enviar a la derecha, crece hasta convertirse en una tarjeta cuando el texto se ajusta o se añaden archivos, y vuelve a su tamaño al vaciarse.
Enter envía y Shift+Enter añade una línea, y los métodos de entrada de japonés, chino y coreano nunca se interrumpen. En pantallas táctiles Enter añade una línea, ya que el teclado no tiene Shift. Las inserciones pasan por la pila de deshacer propia del navegador, así que ⌘Z siempre funciona, y los pegados largos se convierten en un adjunto que puedes previsualizar o devolver al texto.
Todo se compone a partir de partes que comparten un contexto. Usa solo el campo y el botón de enviar, o añade subida de archivos con progreso y reintento, menús @ y / junto al cursor, un selector de modelo, un control deslizante de esfuerzo, un anillo de contexto, dictado, chips de herramientas, una cola para los mensajes enviados mientras se transmite una respuesta y borradores que sobreviven a una recarga.
Prompt Input es gratis. Instálalo sin cuenta ni token, y úsalo bajo la Licencia Pro en tantos proyectos como quieras.
pnpm dlx shadcn@latest add https://hextaui.com/r/pro/prompt-input.jsonCon AI SDK
Pasa el status y el stop de useChat. Los archivos llegan como FileUIPart con una URL de datos, y un mensaje escrito mientras se transmite una respuesta se pone en cola y se envía cuando termina.
Modelo, esfuerzo y dictado
Coloca el selector de modelo, el control deslizante de esfuerzo y el anillo de contexto bajo el compositor con PromptInputMeta. Activa herramientas desde el menú + y muéstralas como chips. Pasa transcribe para enviar las grabaciones a tu propio modelo de voz, y autoSend para enviar en cuanto llegue el texto.
Menciones y comandos
Añade un menú por disparador. @ convierte una selección en un chip sobre el texto, y / inserta el comando. Las teclas de flecha se mueven, Enter o Tab eligen y Escape cierra, todo sin salir del texto.
Subir archivos
Dale a upload una función que informe del progreso y respete la señal de aborto. Lanza UploadError con retryable: false para los errores que un reintento no puede arreglar, como un archivo demasiado grande para el servidor.
Arnés de agente
Envuelve el cuerpo en PromptInputInset y añade un PromptInputFooter. Usa PromptInputSelect para el modo, dónde se ejecuta y en qué carpeta trabaja.
Anatomía
Las partes que compones, de fuera hacia dentro.
| Parte | Descripción |
|---|---|
PromptInput | El formulario y el estado compartido: texto, archivos, menciones, cola y estado. |
PromptInputBody | La superficie redondeada que cambia entre compacta y expandida. |
PromptInputTextarea | El campo. Aquí reside toda la gestión del teclado. |
PromptInputTools | Lado izquierdo: el menú + y los chips de herramientas. |
PromptInputActions | Lado derecho: dictado y enviar. |
PromptInputSubmit | Enviar, detener o poner en cola, según el estado y el texto. |
PromptInputAttachments | Chips de archivos y menciones sobre el texto. |
PromptInputMenu | Un menú junto al cursor para un carácter disparador. |
PromptInputMeta | La fila bajo el compositor para los controles de modelo, esfuerzo y contexto. |
PromptInputModel | Un solo control para el modelo y el esfuerzo, con el switch de razonamiento. |
PromptInputInset | Una carcasa atenuada alrededor del cuerpo que contiene una fila de pie, para arneses de agentes. |
PromptInputFooter | La fila dentro de la carcasa para los controles de ubicación, carpeta y sesión. |
PromptInputSelect | Un selector compacto para modos, ubicación de ejecución, carpetas o repositorios. |
PromptInputQueue, PromptInputSuggestions, PromptInputMeter | Mensajes en cola, prompts iniciales y un medidor de caracteres cerca de maxLength. |
PromptInput
También acepta todas las props de form excepto onSubmit y defaultValue.
| Prop | Tipo | Predeterminado |
|---|---|---|
onSubmitRecibe { text, files, mentions }. Devuelve una promesa para conservar el texto hasta que se resuelva. | (message: PromptMessage) => void | Promise<unknown> | – |
statusPasa el status de useChat. Mientras está ocupado, enviar se convierte en detener o en cola. | "ready" | "submitted" | "streaming" | "error" | "ready" |
onStopSe llama desde el botón de detener o Escape. | () => void | – |
onEditLastDevuelve el último mensaje para cargarlo con ↑ en un campo vacío. | () => string | void | – |
valueTexto controlado. | string | – |
defaultValueTexto inicial. | string | "" |
onValueChangeSe llama cuando cambia el texto. | (value: string) => void | – |
submitOnQué tecla envía. ⌘↵ siempre envía. | "enter" | "mod+enter" | "enter" |
pasteLimitCaracteres antes de que un pegado se convierta en un adjunto. | number | false | 5000 |
maxLengthLímite estricto, mostrado por PromptInputMeter. | number | – |
draftKeyGuarda el texto sin enviar en el almacenamiento local bajo esta clave. | string | – |
globalDropAcepta archivos soltados en cualquier parte de la página. | boolean | false |
focusOnTypeEscribir mientras nada más tiene el foco empieza a escribir aquí. | boolean | false |
layoutFuerza un diseño en lugar de alternar. | "auto" | "compact" | "expanded" | "auto" |
acceptTipos de archivo aceptados, como el atributo del input. | string | – |
maxFilesMáximo de archivos a la vez. | number | – |
maxFileSizeArchivo más grande en bytes. | number | – |
uploadSube cada archivo. Lanza UploadError con retryable: false para fallos permanentes. | (file, { signal, onProgress }) => Promise<unknown> | – |
onRejectSe llama para archivos que superan un límite o son de tipo incorrecto. | (file: File, reason: string) => void | – |
disabledDeshabilita todo el compositor. | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
triggerEl carácter que lo abre, como @ o /. | string | – |
items{ value, label, description?, icon?, hint?, keywords?, insert? } | PromptMenuItem[] | – |
modeLas menciones añaden un chip; el texto inserta insert ?? label. | "mention" | "text" | – |
labelEtiqueta de sección en la parte superior del menú. | string | – |
limitMáximo de filas mostradas. | number | – |
onSelectSe llama tras una selección. | (item: PromptMenuItem) => void | – |
PromptInputModel
El selector de modelo y el control deslizante de esfuerzo en un solo control. También acepta todas las props de PromptInputEffort excepto value y onValueChange.
| Prop | Tipo | Predeterminado |
|---|---|---|
modelsLos nueve primeros obtienen atajos 1–9. | { value, label }[] | – |
modelModelo seleccionado. | string | – |
onModelChangeSe llama al elegir. | (value: string) => void | – |
levelsNiveles de esfuerzo, de menos a más. | { value, label }[] | – |
effortEsfuerzo seleccionado. | string | – |
onEffortChangeSe llama mientras se mueve el control deslizante. | (value: string) => void | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
modelsLos nueve primeros obtienen atajos 1–9. | { value, label }[] | – |
valueModelo seleccionado. | string | – |
onValueChangeSe llama al elegir. | (value: string) => void | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
levelsDe menos a más. | { value, label }[] | – |
valueNivel seleccionado. | string | – |
onValueChangeSe llama mientras se mueve el control deslizante. | (value: string) => void | – |
recommendedMarca un nivel como recomendado. | string | – |
thinkingMuestra el switch de razonamiento extendido cuando está definido. | boolean | – |
onThinkingChangeSe llama desde el switch. | (thinking: boolean) => void | – |
thinkingLabelEtiqueta del switch. | string | – |
descriptionTexto de ayuda en el tooltip. | string | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
usedTokens usados. | number | – |
limitTamaño de la ventana de contexto. | number | – |
limitsFilas adicionales, como el uso del plan. | { label, used, detail? }[] | – |
limitsLabelEncabezado de esas filas. | string | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
transcribeEnvía la grabación a tu modelo de voz. Sin esto, se usa el reconocimiento de voz del navegador. | (audio: Blob) => Promise<string> | – |
shortcutInicia y termina una grabación desde cualquier parte. | string | false | "ctrl+shift+d" |
autoSendEnvía en cuanto llega la transcripción. | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
iconSe muestra en el chip, y se sustituye por × al pasar el cursor. | ReactNode | – |
childrenNombre de la herramienta. | string | – |
toneColor del chip. | "blue" | "green" | "amber" | "violet" | "pink" | "blue" |
onRemoveSe llama al hacer clic en el chip. | () => void | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
optionsLas opciones. Las descripciones se muestran bajo cada etiqueta. | { value, label, icon?, description? }[] | – |
valueOpción seleccionada. Déjala sin definir para mostrar el placeholder. | string | – |
onValueChangeSe llama al elegir. | (value: string) => void | – |
labelNombre accesible y tooltip, como Mode o Run on. | string | – |
placeholderSe muestra cuando no hay nada seleccionado. | string | – |
iconSe muestra cuando la opción seleccionada no tiene icono. | ReactNode | – |
headingEtiqueta en la parte superior del menú. | string | – |
shortcutRecorre las opciones desde cualquier parte, como alt+m. | string | – |
childrenElementos de menú adicionales bajo las opciones, como Open folder. | ReactNode | – |
| Key | Acción |
|---|---|
| Enter | Envía. En pantallas táctiles añade una línea en su lugar. |
| ShiftEnter | Añade una línea. |
| ⌘Enter | Siempre envía, incluso cuando submitOn es mod+enter. |
| Esc | Detiene una respuesta en streaming, cierra un menú o cancela una grabación. |
| ↑ | En un campo vacío, recupera tu último mensaje cuando onEditLast está definido. |
| ↑↓ | Recorre un menú @ o / abierto. |
| EnterTab | Elige la fila resaltada del menú. |
| 1–9 | Elige un modelo mientras el menú de modelos está abierto. |
| ←→ | Mueve el control deslizante de esfuerzo. Home y End saltan a los extremos. |
| CtrlShiftD | Inicia el dictado, e inserta la transcripción al pulsar de nuevo. |
| AltM | Recorre un PromptInputSelect que tiene shortcut="alt+m", como el modo de agente. |
- El campo tiene un placeholder visible y un nombre accesible, y cada botón de icono tiene una etiqueta y un tooltip con su atajo.
- El menú junto al cursor es un combobox con aria-activedescendant, así que el foco nunca sale del texto mientras te mueves por él.
- Las subidas, los rechazos, los cambios de cola y el dictado se anuncian mediante una región live polite.
- El control de esfuerzo es un slider con un texto de valor, y sigue funcionando con las teclas de flecha y Home y End.
- Los inputs miden al menos 16px en pantallas táctiles, para que iOS nunca haga zoom al enfocar.
- Con movimiento reducido, los cambios de altura, la forma de onda y el relleno de esfuerzo se asientan sin animarse.
Construido con
Los componentes gratuitos de HextaUI con los que está hecho Prompt Input. Cada uno se instala por separado.
Código
10 archivos, añadidos a components/blocks/prompt-input.