使用法
ChatReasoningコンポーネントは、AIの推論や思考コンテンツを表示する折りたたみ可能なブロックをレンダリングします。ストリーミング中は自動開き、ストリーミング後は自動閉じます。
<script setup lang="ts">
const streaming = ref(false)
const text = ref('')
async function simulateStreaming() {
streaming.value = true
text.value = ''
const content =
'The user is asking about Vue components. I should explain the Composition API pattern and how it relates to their question about reactive state management. Let me think about the best way to structure this response.\n\nFirst, I need to consider the key differences between the Options API and Composition API. The Composition API was introduced in Vue 3 to address limitations of the Options API when building large-scale applications.\n\nFor reactive state management specifically, the Composition API offers ref() for primitive values and reactive() for objects.'
for (const char of content) {
text.value += char
await new Promise((resolve) => setTimeout(resolve, 10))
}
streaming.value = false
}
onMounted(simulateStreaming)
</script>
<template>
<UChatReasoning :text="text" :streaming="streaming" class="w-60" />
</template><script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
const streaming = ref(false)
const text = ref('')
async function simulateStreaming() {
streaming.value = true
text.value = ''
const content =
'The user is asking about Vue components. I should explain the Composition API pattern and how it relates to their question about reactive state management. Let me think about the best way to structure this response.\n\nFirst, I need to consider the key differences between the Options API and Composition API. The Composition API was introduced in Vue 3 to address limitations of the Options API when building large-scale applications.\n\nFor reactive state management specifically, the Composition API offers ref() for primitive values and reactive() for objects.'
for (const char of content) {
text.value += char
await new Promise((resolve) => setTimeout(resolve, 10))
}
streaming.value = false
}
onMounted(simulateStreaming)
</script>
<template>
<UChatReasoning :text="text" :streaming="streaming" class="w-60" />
</template>Text
textプロパティを使用して推論内容を設定します。テキストは折りたたみ可能なボディ内に表示されます。
<template>
<UChatReasoning text="The user is asking about Vue components..." />
</template>ストリーミング
streamingプロパティを使用してアクティブな推論を示します。コンポーネントはストリーミング開始時に自動的に開き、終了時に自動的に閉じます。
<template>
<UChatReasoning streaming text="The user is asking about Vue components..." />
</template>@nuxt/ui/utils/aiのisPartStreamingユーティリティを使用して、部品が現在ストリーミング中かどうかを判断します。シマー
ストリーミング時、トリガーラベルはChatShimmerコンポーネントを使用します。shimmerプロパティを使用してdurationとspreadをカスタマイズします。
<template>
<UChatReasoning
streaming
text="The user is asking about Vue components..."
:shimmer="{
duration: 2,
spread: 2
}"
/>
</template>Icon
iconプロパティを使用して、Iconコンポーネントをトリガーの横に表示します。
<template>
<UChatReasoning icon="i-lucide-brain" text="The user is asking about Vue components..." />
</template>Chevron
chevronアイコンの位置を変更するには、chevronプロパティを使用します。
chevronがiconでleadingに設定されている場合、アイコンはホバーと開いたときにシェブロンと切り替わります。<template>
<UChatReasoning
chevron="leading"
icon="i-lucide-brain"
text="The user is asking about Vue components..."
/>
</template>Chevronアイコン
chevron-iconプロパティを使用して、シェブロンIconをカスタマイズします。デフォルトはi-lucide-chevron-downです。
<template>
<UChatReasoning
chevron-icon="i-lucide-arrow-down"
text="The user is asking about Vue components..."
/>
</template>例
API
Props
| Prop | Default | Type |
|---|---|---|
text | stringThe reasoning text content to display. | |
streaming | false | boolean Whether the reasoning content is currently streaming. |
duration | numberThe duration in seconds that the AI spent reasoning. If not provided, it will be calculated automatically based on streaming time. | |
icon | anyThe icon displayed next to the trigger. | |
chevron | 'trailing' | "leading" | "trailing"The position of the chevron icon. |
chevronIcon | appConfig.ui.icons.chevronDown | anyThe icon displayed as the chevron. |
autoCloseDelay | 500 | numberThe delay in milliseconds before auto-closing when streaming ends.
Set to |
shimmer | Partial<Omit<ChatShimmerProps, "text">>Customize the | |
disabled | boolean When | |
open | undefined | boolean The controlled open state of the collapsible. Can be binded with |
defaultOpen | boolean The open state of the collapsible when it is initially rendered. | |
unmountOnHide | false | boolean When |
ui | { root?: SlotClass; trigger?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; chevronIcon?: SlotClass; label?: SlotClass; trailingIcon?: SlotClass; content?: SlotClass; body?: SlotClass; } |
スロット
| Slot | Type |
|---|---|
default | { open: boolean; } |
Emits
| Event | Type |
|---|---|
update:open | [value: boolean] |
Theme
export default defineAppConfig({
ui: {
chatReasoning: {
slots: {
root: '',
trigger: [
'group flex w-full items-center gap-1.5 text-muted text-sm disabled:cursor-default disabled:hover:text-muted hover:text-default rounded-sm outline-primary/25 focus-visible:outline-3 min-w-0',
'transition-colors'
],
leading: 'relative size-4 shrink-0',
leadingIcon: 'size-4 shrink-0',
chevronIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200 ease-out motion-reduce:transition-none',
label: 'truncate',
trailingIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200 ease-out motion-reduce:transition-none',
content: 'data-[state=open]:animate-[collapsible-down_200ms_var(--ease-out)] data-[state=closed]:animate-[collapsible-up_200ms_var(--ease-out)] data-[state=closed]:overflow-hidden rounded-sm outline-primary/25 has-focus-visible:outline-3',
body: 'max-h-[200px] pt-2 overflow-y-auto text-sm text-dimmed whitespace-pre-wrap focus:outline-none'
},
variants: {
chevron: {
leading: {
leadingIcon: 'group-hover:opacity-0'
},
trailing: ''
},
alone: {
false: {
leadingIcon: [
'absolute inset-0 group-data-[state=open]:opacity-0',
'transition-opacity duration-200 ease-out'
],
chevronIcon: [
'absolute inset-0 opacity-0 group-hover:opacity-100 group-data-[state=open]:opacity-100',
'transition-[rotate,opacity] duration-200 ease-out motion-reduce:transition-none'
]
}
}
}
}
}
})import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'
export default defineConfig({
plugins: [
vue(),
ui({
ui: {
chatReasoning: {
slots: {
root: '',
trigger: [
'group flex w-full items-center gap-1.5 text-muted text-sm disabled:cursor-default disabled:hover:text-muted hover:text-default rounded-sm outline-primary/25 focus-visible:outline-3 min-w-0',
'transition-colors'
],
leading: 'relative size-4 shrink-0',
leadingIcon: 'size-4 shrink-0',
chevronIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200 ease-out motion-reduce:transition-none',
label: 'truncate',
trailingIcon: 'size-4 shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200 ease-out motion-reduce:transition-none',
content: 'data-[state=open]:animate-[collapsible-down_200ms_var(--ease-out)] data-[state=closed]:animate-[collapsible-up_200ms_var(--ease-out)] data-[state=closed]:overflow-hidden rounded-sm outline-primary/25 has-focus-visible:outline-3',
body: 'max-h-[200px] pt-2 overflow-y-auto text-sm text-dimmed whitespace-pre-wrap focus:outline-none'
},
variants: {
chevron: {
leading: {
leadingIcon: 'group-hover:opacity-0'
},
trailing: ''
},
alone: {
false: {
leadingIcon: [
'absolute inset-0 group-data-[state=open]:opacity-0',
'transition-opacity duration-200 ease-out'
],
chevronIcon: [
'absolute inset-0 opacity-0 group-hover:opacity-100 group-data-[state=open]:opacity-100',
'transition-[rotate,opacity] duration-200 ease-out motion-reduce:transition-none'
]
}
}
}
}
}
})
]
})