O componente ChatPrompt renderiza um elemento <form> e estende o componente Textarea, então você pode passar qualquer propriedade como icon, placeholder, autofocus, etc.
submit-on-enter prop to false to submit with + ↵ (or cmd + ↵ on macOS) instead, allowing ↵ to insert a newline.close event.Use a prop variant para alterar o estilo do prompt. O padrão é outline.
<template>
<NChatPrompt variant="soft" />
</template>
Componha os slots #header, #body e #footer para construir um prompt rico: anexos de arquivo, um Editor com menções @ e comandos / por meio do EditorMentionMenu, e um seletor de modo.
#body substitui o textarea interno e expõe os handlers submit e close, então você pode conectar os atalhos de teclado do editor ao formulário. Quando um menu de menções está aberto, pressionar ↵ seleciona o item destacado em vez de enviar.Você também pode usá-lo na página inicial da sua interface de chat.
<script setup lang="ts">
import { useChat } from '@ai-sdk/vue'
const input = ref('')
const { messages, status, sendMessage } = useChat()
async function onSubmit() {
sendMessage({ text: input.value })
// Navigate to chat page after first message
if (messages.value.length === 1) {
await navigateTo('/chat')
}
}
</script>
<template>
<NDashboardPanel>
<template #body>
<NContainer>
<h1>How can I help you today?</h1>
<NChatPrompt v-model="input" @submit="onSubmit">
<NChatPromptSubmit :status="status" />
</NChatPrompt>
</NContainer>
</template>
</NDashboardPanel>
</template>
| Prop | Default | Type |
|---|---|---|
as | 'form' | anyThe element or component this component should render as. |
placeholder | t('chatPrompt.placeholder') | stringThe placeholder text for the textarea. |
color | 'primary' | "error" | "primary" | "secondary" | "accent" | "success" | "info" | "warning" | "neutral" |
variant | 'outline' | "outline" | "soft" | "subtle" | "naked" |
submitOnEnter | true | boolean When |
error | Error | |
rows | 1 | number |
autofocus | true | boolean |
autofocusDelay | number | |
autoresize | true | boolean |
autoresizeDelay | number | |
maxrows | number | |
icon | anyDisplay an icon based on the | |
avatar | AvatarPropsDisplay an avatar on the left side. | |
loading | boolean When | |
loadingIcon | appConfig.ui.icons.loading | anyThe icon when the |
disabled | boolean | |
modelValue | '' | string |
ui | { root?: SlotClass; header?: SlotClass; body?: SlotClass; footer?: SlotClass; base?: SlotClass; } & { root?: SlotClass; base?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; leadingAvatar?: SlotClass; leadingAvatarSize?: SlotClass; trailing?: SlotClass; trailingIcon?: SlotClass; } |
| Slot | Type |
|---|---|
header | {} |
footer | {} |
body | { submit: (event?: Event | undefined) => void; close: (event?: Event | undefined) => void; placeholder: string; disabled: boolean; ui: object; }Replace the internal textarea, e.g. to render an Editor with mentions. |
leading | { ui: { root: (props?: Record<string, any> | undefined) => string; base: (props?: Record<string, any> | undefined) => string; leading: (props?: Record<string, any> | undefined) => string; leadingIcon: (props?: Record<string, any> | undefined) => string; leadingAvatar: (props?: Record<string, any> | undefined) => string; leadingAvatarSize: (props?: Record<string, any> | undefined) => string; trailing: (props?: Record<string, any> | undefined) => string; trailingIcon: (props?: Record<string, any> | undefined) => string; }; } |
default | { ui: { root: (props?: Record<string, any> | undefined) => string; base: (props?: Record<string, any> | undefined) => string; leading: (props?: Record<string, any> | undefined) => string; leadingIcon: (props?: Record<string, any> | undefined) => string; leadingAvatar: (props?: Record<string, any> | undefined) => string; leadingAvatarSize: (props?: Record<string, any> | undefined) => string; trailing: (props?: Record<string, any> | undefined) => string; trailingIcon: (props?: Record<string, any> | undefined) => string; }; } |
trailing | { ui: { root: (props?: Record<string, any> | undefined) => string; base: (props?: Record<string, any> | undefined) => string; leading: (props?: Record<string, any> | undefined) => string; leadingIcon: (props?: Record<string, any> | undefined) => string; leadingAvatar: (props?: Record<string, any> | undefined) => string; leadingAvatarSize: (props?: Record<string, any> | undefined) => string; trailing: (props?: Record<string, any> | undefined) => string; trailingIcon: (props?: Record<string, any> | undefined) => string; }; } |
| Event | Type |
|---|---|
close | [event: Event] |
submit | [event: Event] |
update:modelValue | [value: string] |
Ao acessar o componente por meio de um template ref, você pode usar o seguinte:
| Name | Type |
|---|---|
textareaRef | Ref<HTMLTextAreaElement | null> |
export default defineAppConfig({
ui: {
chatPrompt: {
slots: {
root: 'relative flex flex-col items-stretch gap-2 px-2.5 py-2 w-full rounded-lg backdrop-blur',
header: 'flex items-center gap-1.5',
body: 'items-start gap-1.5',
footer: 'flex items-center justify-between gap-1.5',
base: 'px-0'
},
variants: {
color: {
primary: '',
secondary: '',
accent: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
variant: {
outline: {
root: 'bg-default/75 ring ring-default'
},
soft: {
root: 'bg-elevated/50'
},
subtle: {
root: 'bg-elevated/50 ring ring-default'
},
naked: {
root: ''
}
}
},
compoundVariants: [
{
color: 'primary',
variant: [
'outline',
'subtle'
],
class: {
root: 'outline-primary/25 has-[textarea:focus-visible]:outline-3 has-[textarea:focus-visible]:ring-primary has-[[contenteditable]:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:ring-primary'
}
},
{
color: 'primary',
variant: 'soft',
class: {
root: 'outline-primary/25 has-[textarea:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:outline-3'
}
},
{
color: 'neutral',
variant: [
'outline',
'subtle'
],
class: {
root: 'outline-inverted/25 has-[textarea:focus-visible]:outline-3 has-[textarea:focus-visible]:ring-inverted has-[[contenteditable]:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:ring-inverted'
}
},
{
color: 'neutral',
variant: 'soft',
class: {
root: 'outline-inverted/25 has-[textarea:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:outline-3'
}
}
],
defaultVariants: {
color: 'primary',
variant: 'outline'
}
}
}
})
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
chatPrompt: {
slots: {
root: 'relative flex flex-col items-stretch gap-2 px-2.5 py-2 w-full rounded-lg backdrop-blur',
header: 'flex items-center gap-1.5',
body: 'items-start gap-1.5',
footer: 'flex items-center justify-between gap-1.5',
base: 'px-0'
},
variants: {
color: {
primary: '',
secondary: '',
accent: '',
success: '',
info: '',
warning: '',
error: '',
neutral: ''
},
variant: {
outline: {
root: 'bg-default/75 ring ring-default'
},
soft: {
root: 'bg-elevated/50'
},
subtle: {
root: 'bg-elevated/50 ring ring-default'
},
naked: {
root: ''
}
}
},
compoundVariants: [
{
color: 'primary',
variant: [
'outline',
'subtle'
],
class: {
root: 'outline-primary/25 has-[textarea:focus-visible]:outline-3 has-[textarea:focus-visible]:ring-primary has-[[contenteditable]:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:ring-primary'
}
},
{
color: 'primary',
variant: 'soft',
class: {
root: 'outline-primary/25 has-[textarea:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:outline-3'
}
},
{
color: 'neutral',
variant: [
'outline',
'subtle'
],
class: {
root: 'outline-inverted/25 has-[textarea:focus-visible]:outline-3 has-[textarea:focus-visible]:ring-inverted has-[[contenteditable]:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:ring-inverted'
}
},
{
color: 'neutral',
variant: 'soft',
class: {
root: 'outline-inverted/25 has-[textarea:focus-visible]:outline-3 has-[[contenteditable]:focus-visible]:outline-3'
}
}
],
defaultVariants: {
color: 'primary',
variant: 'outline'
}
}
}
})
]
})