@nuxt/ui 4.5.1 → 4.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +7 -0
- package/dist/module.json +2 -2
- package/dist/module.mjs +78 -67
- package/dist/runtime/components/Avatar.vue +10 -12
- package/dist/runtime/components/Banner.vue +1 -1
- package/dist/runtime/components/BlogPost.vue +3 -2
- package/dist/runtime/components/Calendar.d.vue.ts +4 -4
- package/dist/runtime/components/Calendar.vue.d.ts +4 -4
- package/dist/runtime/components/ChangelogVersion.vue +3 -2
- package/dist/runtime/components/ChangelogVersions.vue +1 -1
- package/dist/runtime/components/ChatMessage.d.vue.ts +4 -1
- package/dist/runtime/components/ChatMessage.vue +5 -0
- package/dist/runtime/components/ChatMessage.vue.d.ts +4 -1
- package/dist/runtime/components/ChatReasoning.d.vue.ts +78 -0
- package/dist/runtime/components/ChatReasoning.vue +162 -0
- package/dist/runtime/components/ChatReasoning.vue.d.ts +78 -0
- package/dist/runtime/components/ChatShimmer.d.vue.ts +34 -0
- package/dist/runtime/components/ChatShimmer.vue +37 -0
- package/dist/runtime/components/ChatShimmer.vue.d.ts +34 -0
- package/dist/runtime/components/ChatTool.d.vue.ts +88 -0
- package/dist/runtime/components/ChatTool.vue +105 -0
- package/dist/runtime/components/ChatTool.vue.d.ts +88 -0
- package/dist/runtime/components/Checkbox.d.vue.ts +22 -19
- package/dist/runtime/components/Checkbox.vue +9 -8
- package/dist/runtime/components/Checkbox.vue.d.ts +22 -19
- package/dist/runtime/components/DashboardGroup.d.vue.ts +1 -1
- package/dist/runtime/components/DashboardGroup.vue.d.ts +1 -1
- package/dist/runtime/components/DashboardSearchButton.vue +2 -2
- package/dist/runtime/components/Drawer.vue +1 -1
- package/dist/runtime/components/DropdownMenu.d.vue.ts +29 -3
- package/dist/runtime/components/DropdownMenu.vue +9 -0
- package/dist/runtime/components/DropdownMenu.vue.d.ts +29 -3
- package/dist/runtime/components/DropdownMenuContent.d.vue.ts +9 -3
- package/dist/runtime/components/DropdownMenuContent.vue +62 -9
- package/dist/runtime/components/DropdownMenuContent.vue.d.ts +9 -3
- package/dist/runtime/components/EditorDragHandle.d.vue.ts +4 -4
- package/dist/runtime/components/EditorDragHandle.vue.d.ts +4 -4
- package/dist/runtime/components/Error.vue +5 -5
- package/dist/runtime/components/FileUpload.d.vue.ts +6 -0
- package/dist/runtime/components/FileUpload.vue +11 -7
- package/dist/runtime/components/FileUpload.vue.d.ts +6 -0
- package/dist/runtime/components/Icon.d.vue.ts +2 -1
- package/dist/runtime/components/Icon.vue +1 -1
- package/dist/runtime/components/Icon.vue.d.ts +2 -1
- package/dist/runtime/components/InputDate.d.vue.ts +4 -4
- package/dist/runtime/components/InputDate.vue.d.ts +4 -4
- package/dist/runtime/components/InputMenu.d.vue.ts +7 -1
- package/dist/runtime/components/InputMenu.vue +67 -48
- package/dist/runtime/components/InputMenu.vue.d.ts +7 -1
- package/dist/runtime/components/InputTime.d.vue.ts +53 -27
- package/dist/runtime/components/InputTime.vue +52 -27
- package/dist/runtime/components/InputTime.vue.d.ts +53 -27
- package/dist/runtime/components/Kbd.vue +1 -1
- package/dist/runtime/components/Modal.vue +1 -1
- package/dist/runtime/components/NavigationMenu.vue +1 -0
- package/dist/runtime/components/Popover.vue +1 -1
- package/dist/runtime/components/Progress.d.vue.ts +1 -1
- package/dist/runtime/components/Progress.vue.d.ts +1 -1
- package/dist/runtime/components/SelectMenu.d.vue.ts +1 -1
- package/dist/runtime/components/SelectMenu.vue +1 -1
- package/dist/runtime/components/SelectMenu.vue.d.ts +1 -1
- package/dist/runtime/components/Sidebar.d.vue.ts +131 -0
- package/dist/runtime/components/Sidebar.vue +222 -0
- package/dist/runtime/components/Sidebar.vue.d.ts +131 -0
- package/dist/runtime/components/Slideover.vue +1 -1
- package/dist/runtime/components/Switch.d.vue.ts +22 -19
- package/dist/runtime/components/Switch.vue +7 -6
- package/dist/runtime/components/Switch.vue.d.ts +22 -19
- package/dist/runtime/components/Table.d.vue.ts +1 -1
- package/dist/runtime/components/Table.vue +12 -4
- package/dist/runtime/components/Table.vue.d.ts +1 -1
- package/dist/runtime/components/Tooltip.d.vue.ts +2 -0
- package/dist/runtime/components/Tooltip.vue +3 -2
- package/dist/runtime/components/Tooltip.vue.d.ts +2 -0
- package/dist/runtime/components/color-mode/ColorModeSelect.d.vue.ts +1 -1
- package/dist/runtime/components/color-mode/ColorModeSelect.vue.d.ts +1 -1
- package/dist/runtime/components/color-mode/ColorModeSwitch.vue +3 -1
- package/dist/runtime/components/content/ContentNavigation.vue +9 -2
- package/dist/runtime/components/content/ContentSurround.vue +6 -2
- package/dist/runtime/components/content/ContentToc.d.vue.ts +5 -0
- package/dist/runtime/components/content/ContentToc.vue +57 -11
- package/dist/runtime/components/content/ContentToc.vue.d.ts +5 -0
- package/dist/runtime/components/locale/LocaleSelect.d.vue.ts +1 -1
- package/dist/runtime/components/locale/LocaleSelect.vue.d.ts +1 -1
- package/dist/runtime/components/prose/Pre.vue +0 -4
- package/dist/runtime/composables/index.d.ts +11 -0
- package/dist/runtime/composables/index.js +11 -0
- package/dist/runtime/composables/useEditorMenu.js +1 -1
- package/dist/runtime/composables/useFileUpload.d.ts +2 -2
- package/dist/runtime/composables/useFileUpload.js +3 -3
- package/dist/runtime/composables/{internal/useFilter.js → useFilter.js} +1 -1
- package/dist/runtime/composables/useScrollShadow.d.ts +23 -0
- package/dist/runtime/composables/useScrollShadow.js +36 -0
- package/dist/runtime/index.css +1 -1
- package/dist/runtime/keyframes.css +1 -1
- package/dist/runtime/locale/ar.js +13 -0
- package/dist/runtime/locale/az.js +13 -0
- package/dist/runtime/locale/be.js +13 -0
- package/dist/runtime/locale/bg.js +13 -0
- package/dist/runtime/locale/bn.js +13 -0
- package/dist/runtime/locale/ca.js +13 -0
- package/dist/runtime/locale/ckb.js +13 -0
- package/dist/runtime/locale/cs.js +13 -0
- package/dist/runtime/locale/da.js +13 -0
- package/dist/runtime/locale/de.js +13 -0
- package/dist/runtime/locale/de_ch.js +13 -0
- package/dist/runtime/locale/el.js +13 -0
- package/dist/runtime/locale/en.js +13 -0
- package/dist/runtime/locale/es.js +13 -0
- package/dist/runtime/locale/et.js +13 -0
- package/dist/runtime/locale/eu.js +13 -0
- package/dist/runtime/locale/fa_ir.js +13 -0
- package/dist/runtime/locale/fi.js +13 -0
- package/dist/runtime/locale/fr.js +13 -0
- package/dist/runtime/locale/gl.js +13 -0
- package/dist/runtime/locale/he.js +13 -0
- package/dist/runtime/locale/hi.js +13 -0
- package/dist/runtime/locale/hr.js +13 -0
- package/dist/runtime/locale/hu.js +13 -0
- package/dist/runtime/locale/hy.js +13 -0
- package/dist/runtime/locale/id.js +13 -0
- package/dist/runtime/locale/index.d.ts +1 -0
- package/dist/runtime/locale/index.js +1 -0
- package/dist/runtime/locale/is.d.ts +3 -0
- package/dist/runtime/locale/is.js +142 -0
- package/dist/runtime/locale/it.js +13 -0
- package/dist/runtime/locale/ja.js +13 -0
- package/dist/runtime/locale/ka.js +13 -0
- package/dist/runtime/locale/kk.js +13 -0
- package/dist/runtime/locale/km.js +13 -0
- package/dist/runtime/locale/ko.js +13 -0
- package/dist/runtime/locale/ky.js +13 -0
- package/dist/runtime/locale/lb.js +13 -0
- package/dist/runtime/locale/lo.js +13 -0
- package/dist/runtime/locale/lt.js +13 -0
- package/dist/runtime/locale/mn.js +13 -0
- package/dist/runtime/locale/ms.js +13 -0
- package/dist/runtime/locale/nb_no.js +13 -0
- package/dist/runtime/locale/nl.js +13 -0
- package/dist/runtime/locale/pl.js +13 -0
- package/dist/runtime/locale/pt.js +13 -0
- package/dist/runtime/locale/pt_br.js +13 -0
- package/dist/runtime/locale/ro.js +13 -0
- package/dist/runtime/locale/ru.js +13 -0
- package/dist/runtime/locale/sk.js +13 -0
- package/dist/runtime/locale/sl.js +13 -0
- package/dist/runtime/locale/sq.js +13 -0
- package/dist/runtime/locale/sv.js +13 -0
- package/dist/runtime/locale/th.js +13 -0
- package/dist/runtime/locale/tj.js +13 -0
- package/dist/runtime/locale/tr.js +13 -0
- package/dist/runtime/locale/ug_cn.js +13 -0
- package/dist/runtime/locale/uk.js +13 -0
- package/dist/runtime/locale/ur.js +13 -0
- package/dist/runtime/locale/uz.js +13 -0
- package/dist/runtime/locale/vi.js +13 -0
- package/dist/runtime/locale/zh_cn.js +13 -0
- package/dist/runtime/locale/zh_tw.js +13 -0
- package/dist/runtime/types/index.d.ts +4 -0
- package/dist/runtime/types/index.js +4 -0
- package/dist/runtime/types/locale.d.ts +13 -0
- package/dist/runtime/utils/ai.d.ts +18 -0
- package/dist/runtime/utils/ai.js +13 -0
- package/dist/runtime/utils/editor.js +17 -5
- package/dist/runtime/vue/components/Icon.d.vue.ts +1 -4
- package/dist/runtime/vue/components/Icon.vue +28 -3
- package/dist/runtime/vue/components/Icon.vue.d.ts +1 -4
- package/dist/runtime/vue/components/color-mode/ColorModeSelect.d.vue.ts +1 -1
- package/dist/runtime/vue/components/color-mode/ColorModeSelect.vue.d.ts +1 -1
- package/dist/runtime/vue/components/color-mode/ColorModeSwitch.vue +3 -1
- package/dist/shared/{ui.DI_ypO2T.mjs → ui.DJUbBpE2.mjs} +298 -39
- package/dist/unplugin.d.mts +15 -5
- package/dist/unplugin.mjs +53 -30
- package/dist/vite.d.mts +1 -0
- package/dist/vite.mjs +1 -1
- package/package.json +49 -46
- /package/dist/runtime/composables/{internal/useFilter.d.ts → useFilter.d.ts} +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import theme from "#build/ui/chat-reasoning";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { ref, computed, watch, onUnmounted, nextTick, useTemplateRef } from "vue";
|
|
7
|
+
import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent } from "reka-ui";
|
|
8
|
+
import { useAppConfig } from "#imports";
|
|
9
|
+
import { useComponentUI } from "../composables/useComponentUI";
|
|
10
|
+
import { useLocale } from "../composables/useLocale";
|
|
11
|
+
import { useScrollShadow } from "../composables/useScrollShadow";
|
|
12
|
+
import { tv } from "../utils/tv";
|
|
13
|
+
import UIcon from "./Icon.vue";
|
|
14
|
+
import UChatShimmer from "./ChatShimmer.vue";
|
|
15
|
+
const props = defineProps({
|
|
16
|
+
text: { type: String, required: false },
|
|
17
|
+
streaming: { type: Boolean, required: false, default: false },
|
|
18
|
+
duration: { type: Number, required: false },
|
|
19
|
+
icon: { type: null, required: false },
|
|
20
|
+
chevron: { type: String, required: false, default: "trailing" },
|
|
21
|
+
chevronIcon: { type: null, required: false },
|
|
22
|
+
autoCloseDelay: { type: Number, required: false, default: 500 },
|
|
23
|
+
shimmer: { type: Object, required: false },
|
|
24
|
+
class: { type: null, required: false },
|
|
25
|
+
ui: { type: Object, required: false },
|
|
26
|
+
defaultOpen: { type: Boolean, required: false },
|
|
27
|
+
open: { type: Boolean, required: false, default: void 0 },
|
|
28
|
+
disabled: { type: Boolean, required: false },
|
|
29
|
+
unmountOnHide: { type: Boolean, required: false, default: false }
|
|
30
|
+
});
|
|
31
|
+
const emits = defineEmits(["update:open"]);
|
|
32
|
+
defineSlots();
|
|
33
|
+
const { t, code } = useLocale();
|
|
34
|
+
const appConfig = useAppConfig();
|
|
35
|
+
const uiProp = useComponentUI("chatReasoning", props);
|
|
36
|
+
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.chatReasoning || {} })({
|
|
37
|
+
chevron: props.chevron
|
|
38
|
+
}));
|
|
39
|
+
const isControlled = computed(() => props.open !== void 0);
|
|
40
|
+
const internalOpen = ref(props.defaultOpen ?? props.streaming);
|
|
41
|
+
const startTime = ref(props.streaming ? Date.now() : null);
|
|
42
|
+
const internalDuration = ref(void 0);
|
|
43
|
+
const autoCloseTimeout = ref(null);
|
|
44
|
+
watch(() => props.streaming, (streaming, wasStreaming) => {
|
|
45
|
+
if (streaming) {
|
|
46
|
+
if (autoCloseTimeout.value) {
|
|
47
|
+
clearTimeout(autoCloseTimeout.value);
|
|
48
|
+
autoCloseTimeout.value = null;
|
|
49
|
+
}
|
|
50
|
+
if (!wasStreaming) {
|
|
51
|
+
setOpen(true);
|
|
52
|
+
startTime.value = Date.now();
|
|
53
|
+
}
|
|
54
|
+
} else if (wasStreaming) {
|
|
55
|
+
if (startTime.value !== null) {
|
|
56
|
+
internalDuration.value = Math.ceil((Date.now() - startTime.value) / 1e3);
|
|
57
|
+
startTime.value = null;
|
|
58
|
+
}
|
|
59
|
+
if (props.autoCloseDelay > 0) {
|
|
60
|
+
autoCloseTimeout.value = setTimeout(() => {
|
|
61
|
+
setOpen(false);
|
|
62
|
+
}, props.autoCloseDelay);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}, { immediate: true });
|
|
66
|
+
const actualDuration = computed(() => props.duration ?? internalDuration.value);
|
|
67
|
+
const thinkingText = computed(() => {
|
|
68
|
+
if (props.streaming || actualDuration.value === 0) {
|
|
69
|
+
return t("chatReasoning.thinking");
|
|
70
|
+
}
|
|
71
|
+
if (actualDuration.value === void 0) {
|
|
72
|
+
return t("chatReasoning.thought");
|
|
73
|
+
}
|
|
74
|
+
const d = actualDuration.value;
|
|
75
|
+
const unit = d < 60 ? "second" : "minute";
|
|
76
|
+
const value = d < 60 ? d : Math.floor(d / 60);
|
|
77
|
+
const duration = new Intl.NumberFormat(code.value, { style: "unit", unit, unitDisplay: "long" }).format(value);
|
|
78
|
+
return t("chatReasoning.thoughtFor", { duration });
|
|
79
|
+
});
|
|
80
|
+
const resolvedOpen = computed(() => isControlled.value ? props.open : internalOpen.value);
|
|
81
|
+
function setOpen(value) {
|
|
82
|
+
if (autoCloseTimeout.value) {
|
|
83
|
+
clearTimeout(autoCloseTimeout.value);
|
|
84
|
+
autoCloseTimeout.value = null;
|
|
85
|
+
}
|
|
86
|
+
internalOpen.value = value;
|
|
87
|
+
emits("update:open", value);
|
|
88
|
+
}
|
|
89
|
+
onUnmounted(() => {
|
|
90
|
+
if (autoCloseTimeout.value) {
|
|
91
|
+
clearTimeout(autoCloseTimeout.value);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const hasContent = computed(() => !!props.text || props.streaming);
|
|
95
|
+
const chevronIconName = computed(() => props.chevronIcon || appConfig.ui.icons?.chevronDown);
|
|
96
|
+
const bodyRef = useTemplateRef("bodyRef");
|
|
97
|
+
const { style: scrollShadowStyle } = useScrollShadow(bodyRef);
|
|
98
|
+
watch(() => props.text, () => {
|
|
99
|
+
if (!props.streaming || !bodyRef.value) return;
|
|
100
|
+
const el = bodyRef.value;
|
|
101
|
+
const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
102
|
+
if (distanceFromBottom < 50) {
|
|
103
|
+
nextTick(() => {
|
|
104
|
+
el.scrollTop = el.scrollHeight;
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
</script>
|
|
109
|
+
|
|
110
|
+
<template>
|
|
111
|
+
<CollapsibleRoot
|
|
112
|
+
v-if="hasContent"
|
|
113
|
+
v-slot="{ open: isOpen }"
|
|
114
|
+
:open="resolvedOpen"
|
|
115
|
+
:disabled="disabled"
|
|
116
|
+
:unmount-on-hide="unmountOnHide"
|
|
117
|
+
data-slot="root"
|
|
118
|
+
:class="ui.root({ class: [uiProp?.root, props.class] })"
|
|
119
|
+
@update:open="setOpen"
|
|
120
|
+
>
|
|
121
|
+
<CollapsibleTrigger as-child :disabled="!hasContent">
|
|
122
|
+
<button
|
|
123
|
+
type="button"
|
|
124
|
+
data-slot="trigger"
|
|
125
|
+
:class="ui.trigger({ class: uiProp?.trigger })"
|
|
126
|
+
>
|
|
127
|
+
<span v-if="icon || hasContent && chevron === 'leading'" data-slot="leading" :class="ui.leading({ class: uiProp?.leading })">
|
|
128
|
+
<UIcon
|
|
129
|
+
v-if="icon"
|
|
130
|
+
:name="icon"
|
|
131
|
+
data-slot="leadingIcon"
|
|
132
|
+
:class="ui.leadingIcon({ class: uiProp?.leadingIcon, alone: !(hasContent && chevron === 'leading') })"
|
|
133
|
+
/>
|
|
134
|
+
<UIcon
|
|
135
|
+
v-if="hasContent && chevron === 'leading'"
|
|
136
|
+
:name="chevronIconName"
|
|
137
|
+
data-slot="chevronIcon"
|
|
138
|
+
:class="ui.chevronIcon({ class: uiProp?.chevronIcon, alone: !icon })"
|
|
139
|
+
/>
|
|
140
|
+
</span>
|
|
141
|
+
|
|
142
|
+
<UChatShimmer v-if="streaming" :text="thinkingText" v-bind="props.shimmer" data-slot="label" :class="ui.label({ class: uiProp?.label })" />
|
|
143
|
+
<span v-else data-slot="label" :class="ui.label({ class: uiProp?.label })">{{ thinkingText }}</span>
|
|
144
|
+
|
|
145
|
+
<UIcon
|
|
146
|
+
v-if="hasContent && chevron === 'trailing'"
|
|
147
|
+
:name="chevronIconName"
|
|
148
|
+
data-slot="trailingIcon"
|
|
149
|
+
:class="ui.trailingIcon({ class: uiProp?.trailingIcon })"
|
|
150
|
+
/>
|
|
151
|
+
</button>
|
|
152
|
+
</CollapsibleTrigger>
|
|
153
|
+
|
|
154
|
+
<CollapsibleContent data-slot="content" :class="ui.content({ class: uiProp?.content })">
|
|
155
|
+
<div ref="bodyRef" data-slot="body" :class="ui.body({ class: uiProp?.body })" :style="scrollShadowStyle">
|
|
156
|
+
<slot :open="isOpen">
|
|
157
|
+
{{ text }}
|
|
158
|
+
</slot>
|
|
159
|
+
</div>
|
|
160
|
+
</CollapsibleContent>
|
|
161
|
+
</CollapsibleRoot>
|
|
162
|
+
</template>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { CollapsibleRootProps } from 'reka-ui';
|
|
2
|
+
import type { VNode } from 'vue';
|
|
3
|
+
import type { AppConfig } from '@nuxt/schema';
|
|
4
|
+
import theme from '#build/ui/chat-reasoning';
|
|
5
|
+
import type { IconProps } from '../types';
|
|
6
|
+
import type { ChatShimmerProps } from './ChatShimmer.vue';
|
|
7
|
+
import type { ComponentConfig } from '../types/tv';
|
|
8
|
+
type ChatReasoning = ComponentConfig<typeof theme, AppConfig, 'chatReasoning'>;
|
|
9
|
+
export interface ChatReasoningProps extends Pick<CollapsibleRootProps, 'defaultOpen' | 'open' | 'disabled' | 'unmountOnHide'> {
|
|
10
|
+
/**
|
|
11
|
+
* The reasoning text content to display.
|
|
12
|
+
*/
|
|
13
|
+
text?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether the reasoning content is currently streaming.
|
|
16
|
+
* @defaultValue false
|
|
17
|
+
*/
|
|
18
|
+
streaming?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* The duration in seconds that the AI spent reasoning.
|
|
21
|
+
* If not provided, it will be calculated automatically based on streaming time.
|
|
22
|
+
*/
|
|
23
|
+
duration?: number;
|
|
24
|
+
/**
|
|
25
|
+
* The icon displayed next to the trigger.
|
|
26
|
+
* @IconifyIcon
|
|
27
|
+
*/
|
|
28
|
+
icon?: IconProps['name'];
|
|
29
|
+
/**
|
|
30
|
+
* The position of the chevron icon.
|
|
31
|
+
* @defaultValue 'trailing'
|
|
32
|
+
*/
|
|
33
|
+
chevron?: 'leading' | 'trailing';
|
|
34
|
+
/**
|
|
35
|
+
* The icon displayed as the chevron.
|
|
36
|
+
* @defaultValue appConfig.ui.icons.chevronDown
|
|
37
|
+
* @IconifyIcon
|
|
38
|
+
*/
|
|
39
|
+
chevronIcon?: IconProps['name'];
|
|
40
|
+
/**
|
|
41
|
+
* The delay in milliseconds before auto-closing when streaming ends.
|
|
42
|
+
* Set to `0` to disable auto-close.
|
|
43
|
+
* @defaultValue 500
|
|
44
|
+
*/
|
|
45
|
+
autoCloseDelay?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Customize the [`ChatShimmer`](https://ui.nuxt.com/docs/components/chat-shimmer) component when streaming.
|
|
48
|
+
*/
|
|
49
|
+
shimmer?: Partial<Omit<ChatShimmerProps, 'text'>>;
|
|
50
|
+
class?: any;
|
|
51
|
+
ui?: ChatReasoning['slots'];
|
|
52
|
+
}
|
|
53
|
+
export interface ChatReasoningEmits {
|
|
54
|
+
'update:open': [value: boolean];
|
|
55
|
+
}
|
|
56
|
+
export interface ChatReasoningSlots {
|
|
57
|
+
default?(props: {
|
|
58
|
+
open: boolean;
|
|
59
|
+
}): VNode[];
|
|
60
|
+
}
|
|
61
|
+
declare const _default: typeof __VLS_export;
|
|
62
|
+
export default _default;
|
|
63
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ChatReasoningProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
64
|
+
"update:open": (value: boolean) => any;
|
|
65
|
+
}, string, import("vue").PublicProps, Readonly<ChatReasoningProps> & Readonly<{
|
|
66
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
67
|
+
}>, {
|
|
68
|
+
open: boolean;
|
|
69
|
+
streaming: boolean;
|
|
70
|
+
unmountOnHide: boolean;
|
|
71
|
+
chevron: "leading" | "trailing";
|
|
72
|
+
autoCloseDelay: number;
|
|
73
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ChatReasoningSlots>;
|
|
74
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
75
|
+
new (): {
|
|
76
|
+
$slots: S;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AppConfig } from '@nuxt/schema';
|
|
2
|
+
import theme from '#build/ui/chat-shimmer';
|
|
3
|
+
import type { ComponentConfig } from '../types/tv';
|
|
4
|
+
type ChatShimmer = ComponentConfig<typeof theme, AppConfig, 'chatShimmer'>;
|
|
5
|
+
export interface ChatShimmerProps {
|
|
6
|
+
/**
|
|
7
|
+
* The element or component this component should render as.
|
|
8
|
+
* @defaultValue 'span'
|
|
9
|
+
*/
|
|
10
|
+
as?: any;
|
|
11
|
+
/**
|
|
12
|
+
* The text to display with the shimmer effect.
|
|
13
|
+
*/
|
|
14
|
+
text: string;
|
|
15
|
+
/**
|
|
16
|
+
* The duration of the shimmer animation in seconds.
|
|
17
|
+
* @defaultValue 2
|
|
18
|
+
*/
|
|
19
|
+
duration?: number;
|
|
20
|
+
/**
|
|
21
|
+
* The spread multiplier for the shimmer highlight. The actual spread is computed as `text.length * spread` in pixels.
|
|
22
|
+
* @defaultValue 2
|
|
23
|
+
*/
|
|
24
|
+
spread?: number;
|
|
25
|
+
class?: any;
|
|
26
|
+
ui?: ChatShimmer['slots'];
|
|
27
|
+
}
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
30
|
+
declare const __VLS_export: import("vue").DefineComponent<ChatShimmerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ChatShimmerProps> & Readonly<{}>, {
|
|
31
|
+
as: any;
|
|
32
|
+
duration: number;
|
|
33
|
+
spread: number;
|
|
34
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import theme from "#build/ui/chat-shimmer";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { computed } from "vue";
|
|
7
|
+
import { Primitive } from "reka-ui";
|
|
8
|
+
import { useAppConfig } from "#imports";
|
|
9
|
+
import { useComponentUI } from "../composables/useComponentUI";
|
|
10
|
+
import { tv } from "../utils/tv";
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
as: { type: null, required: false, default: "span" },
|
|
13
|
+
text: { type: String, required: true },
|
|
14
|
+
duration: { type: Number, required: false, default: 2 },
|
|
15
|
+
spread: { type: Number, required: false, default: 2 },
|
|
16
|
+
class: { type: null, required: false },
|
|
17
|
+
ui: { type: Object, required: false }
|
|
18
|
+
});
|
|
19
|
+
const appConfig = useAppConfig();
|
|
20
|
+
const uiProp = useComponentUI("chatShimmer", props);
|
|
21
|
+
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.chatShimmer || {} }));
|
|
22
|
+
const spread = computed(() => props.text.length * props.spread);
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<Primitive
|
|
27
|
+
:as="as"
|
|
28
|
+
:style="{
|
|
29
|
+
'--spread': `${spread}px`,
|
|
30
|
+
'--duration': `${duration}s`
|
|
31
|
+
}"
|
|
32
|
+
data-slot="base"
|
|
33
|
+
:class="ui({ class: [uiProp?.base, props.class] })"
|
|
34
|
+
>
|
|
35
|
+
{{ text }}
|
|
36
|
+
</Primitive>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AppConfig } from '@nuxt/schema';
|
|
2
|
+
import theme from '#build/ui/chat-shimmer';
|
|
3
|
+
import type { ComponentConfig } from '../types/tv';
|
|
4
|
+
type ChatShimmer = ComponentConfig<typeof theme, AppConfig, 'chatShimmer'>;
|
|
5
|
+
export interface ChatShimmerProps {
|
|
6
|
+
/**
|
|
7
|
+
* The element or component this component should render as.
|
|
8
|
+
* @defaultValue 'span'
|
|
9
|
+
*/
|
|
10
|
+
as?: any;
|
|
11
|
+
/**
|
|
12
|
+
* The text to display with the shimmer effect.
|
|
13
|
+
*/
|
|
14
|
+
text: string;
|
|
15
|
+
/**
|
|
16
|
+
* The duration of the shimmer animation in seconds.
|
|
17
|
+
* @defaultValue 2
|
|
18
|
+
*/
|
|
19
|
+
duration?: number;
|
|
20
|
+
/**
|
|
21
|
+
* The spread multiplier for the shimmer highlight. The actual spread is computed as `text.length * spread` in pixels.
|
|
22
|
+
* @defaultValue 2
|
|
23
|
+
*/
|
|
24
|
+
spread?: number;
|
|
25
|
+
class?: any;
|
|
26
|
+
ui?: ChatShimmer['slots'];
|
|
27
|
+
}
|
|
28
|
+
declare const _default: typeof __VLS_export;
|
|
29
|
+
export default _default;
|
|
30
|
+
declare const __VLS_export: import("vue").DefineComponent<ChatShimmerProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<ChatShimmerProps> & Readonly<{}>, {
|
|
31
|
+
as: any;
|
|
32
|
+
duration: number;
|
|
33
|
+
spread: number;
|
|
34
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { CollapsibleRootProps } from 'reka-ui';
|
|
2
|
+
import type { VNode } from 'vue';
|
|
3
|
+
import type { AppConfig } from '@nuxt/schema';
|
|
4
|
+
import theme from '#build/ui/chat-tool';
|
|
5
|
+
import type { IconProps } from '../types';
|
|
6
|
+
import type { ChatShimmerProps } from './ChatShimmer.vue';
|
|
7
|
+
import type { ComponentConfig } from '../types/tv';
|
|
8
|
+
type ChatTool = ComponentConfig<typeof theme, AppConfig, 'chatTool'>;
|
|
9
|
+
export interface ChatToolProps extends Pick<CollapsibleRootProps, 'defaultOpen' | 'open' | 'disabled' | 'unmountOnHide'> {
|
|
10
|
+
/**
|
|
11
|
+
* The text content to display.
|
|
12
|
+
*/
|
|
13
|
+
text?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The suffix text displayed after the main text.
|
|
16
|
+
*/
|
|
17
|
+
suffix?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The icon displayed next to the trigger.
|
|
20
|
+
* @IconifyIcon
|
|
21
|
+
*/
|
|
22
|
+
icon?: IconProps['name'];
|
|
23
|
+
/**
|
|
24
|
+
* Whether the tool is in a loading state.
|
|
25
|
+
* @defaultValue false
|
|
26
|
+
*/
|
|
27
|
+
loading?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The icon displayed when loading.
|
|
30
|
+
* @defaultValue appConfig.ui.icons.loading
|
|
31
|
+
* @IconifyIcon
|
|
32
|
+
*/
|
|
33
|
+
loadingIcon?: IconProps['name'];
|
|
34
|
+
/**
|
|
35
|
+
* Whether the tool content is currently streaming.
|
|
36
|
+
* @defaultValue false
|
|
37
|
+
*/
|
|
38
|
+
streaming?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The visual variant of the tool display.
|
|
41
|
+
* @defaultValue 'inline'
|
|
42
|
+
*/
|
|
43
|
+
variant?: ChatTool['variants']['variant'];
|
|
44
|
+
/**
|
|
45
|
+
* The position of the chevron icon.
|
|
46
|
+
* @defaultValue 'trailing'
|
|
47
|
+
*/
|
|
48
|
+
chevron?: 'leading' | 'trailing';
|
|
49
|
+
/**
|
|
50
|
+
* The icon displayed as the chevron.
|
|
51
|
+
* @defaultValue appConfig.ui.icons.chevronDown
|
|
52
|
+
* @IconifyIcon
|
|
53
|
+
*/
|
|
54
|
+
chevronIcon?: IconProps['name'];
|
|
55
|
+
/**
|
|
56
|
+
* Customize the [`ChatShimmer`](https://ui.nuxt.com/docs/components/chat-shimmer) component when streaming.
|
|
57
|
+
*/
|
|
58
|
+
shimmer?: Partial<Omit<ChatShimmerProps, 'text'>>;
|
|
59
|
+
class?: any;
|
|
60
|
+
ui?: ChatTool['slots'];
|
|
61
|
+
}
|
|
62
|
+
export interface ChatToolEmits {
|
|
63
|
+
'update:open': [value: boolean];
|
|
64
|
+
}
|
|
65
|
+
export interface ChatToolSlots {
|
|
66
|
+
default?(props: {
|
|
67
|
+
open: boolean;
|
|
68
|
+
}): VNode[];
|
|
69
|
+
}
|
|
70
|
+
declare const _default: typeof __VLS_export;
|
|
71
|
+
export default _default;
|
|
72
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ChatToolProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
73
|
+
"update:open": (value: boolean) => any;
|
|
74
|
+
}, string, import("vue").PublicProps, Readonly<ChatToolProps> & Readonly<{
|
|
75
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
76
|
+
}>, {
|
|
77
|
+
loading: boolean;
|
|
78
|
+
variant: ChatTool["variants"]["variant"];
|
|
79
|
+
open: boolean;
|
|
80
|
+
streaming: boolean;
|
|
81
|
+
unmountOnHide: boolean;
|
|
82
|
+
chevron: "leading" | "trailing";
|
|
83
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ChatToolSlots>;
|
|
84
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
85
|
+
new (): {
|
|
86
|
+
$slots: S;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import theme from "#build/ui/chat-tool";
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script setup>
|
|
6
|
+
import { ref, computed } from "vue";
|
|
7
|
+
import { CollapsibleRoot, CollapsibleTrigger, CollapsibleContent } from "reka-ui";
|
|
8
|
+
import { useAppConfig } from "#imports";
|
|
9
|
+
import { useComponentUI } from "../composables/useComponentUI";
|
|
10
|
+
import { tv } from "../utils/tv";
|
|
11
|
+
import UIcon from "./Icon.vue";
|
|
12
|
+
import UChatShimmer from "./ChatShimmer.vue";
|
|
13
|
+
const props = defineProps({
|
|
14
|
+
text: { type: String, required: false },
|
|
15
|
+
suffix: { type: String, required: false },
|
|
16
|
+
icon: { type: null, required: false },
|
|
17
|
+
loading: { type: Boolean, required: false, default: false },
|
|
18
|
+
loadingIcon: { type: null, required: false },
|
|
19
|
+
streaming: { type: Boolean, required: false, default: false },
|
|
20
|
+
variant: { type: null, required: false, default: "inline" },
|
|
21
|
+
chevron: { type: String, required: false, default: "trailing" },
|
|
22
|
+
chevronIcon: { type: null, required: false },
|
|
23
|
+
shimmer: { type: Object, required: false },
|
|
24
|
+
class: { type: null, required: false },
|
|
25
|
+
ui: { type: Object, required: false },
|
|
26
|
+
defaultOpen: { type: Boolean, required: false },
|
|
27
|
+
open: { type: Boolean, required: false, default: void 0 },
|
|
28
|
+
disabled: { type: Boolean, required: false },
|
|
29
|
+
unmountOnHide: { type: Boolean, required: false, default: false }
|
|
30
|
+
});
|
|
31
|
+
const emits = defineEmits(["update:open"]);
|
|
32
|
+
const slots = defineSlots();
|
|
33
|
+
const appConfig = useAppConfig();
|
|
34
|
+
const uiProp = useComponentUI("chatTool", props);
|
|
35
|
+
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.chatTool || {} })({
|
|
36
|
+
variant: props.variant,
|
|
37
|
+
chevron: props.chevron,
|
|
38
|
+
loading: props.loading
|
|
39
|
+
}));
|
|
40
|
+
const isControlled = computed(() => props.open !== void 0);
|
|
41
|
+
const internalOpen = ref(props.defaultOpen ?? false);
|
|
42
|
+
const resolvedOpen = computed(() => isControlled.value ? props.open : internalOpen.value);
|
|
43
|
+
function setOpen(value) {
|
|
44
|
+
internalOpen.value = value;
|
|
45
|
+
emits("update:open", value);
|
|
46
|
+
}
|
|
47
|
+
const hasContent = computed(() => !!slots.default);
|
|
48
|
+
const resolvedLoadingIcon = computed(() => props.loadingIcon || appConfig.ui.icons?.loading);
|
|
49
|
+
const resolvedIcon = computed(() => props.loading ? resolvedLoadingIcon.value : props.icon);
|
|
50
|
+
const chevronIconName = computed(() => props.chevronIcon || appConfig.ui.icons?.chevronDown);
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<CollapsibleRoot
|
|
55
|
+
v-slot="{ open: isOpen }"
|
|
56
|
+
:open="resolvedOpen"
|
|
57
|
+
:disabled="disabled"
|
|
58
|
+
:unmount-on-hide="unmountOnHide"
|
|
59
|
+
data-slot="root"
|
|
60
|
+
:class="ui.root({ class: [uiProp?.root, props.class] })"
|
|
61
|
+
@update:open="setOpen"
|
|
62
|
+
>
|
|
63
|
+
<CollapsibleTrigger as-child :disabled="!hasContent">
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
data-slot="trigger"
|
|
67
|
+
:class="ui.trigger({ class: uiProp?.trigger })"
|
|
68
|
+
>
|
|
69
|
+
<span v-if="resolvedIcon || hasContent && chevron === 'leading'" data-slot="leading" :class="ui.leading({ class: uiProp?.leading })">
|
|
70
|
+
<UIcon
|
|
71
|
+
v-if="resolvedIcon"
|
|
72
|
+
:name="resolvedIcon"
|
|
73
|
+
data-slot="leadingIcon"
|
|
74
|
+
:class="ui.leadingIcon({ class: uiProp?.leadingIcon, alone: !(hasContent && chevron === 'leading') })"
|
|
75
|
+
/>
|
|
76
|
+
<UIcon
|
|
77
|
+
v-if="hasContent && chevron === 'leading'"
|
|
78
|
+
:name="chevronIconName"
|
|
79
|
+
data-slot="chevronIcon"
|
|
80
|
+
:class="ui.chevronIcon({ class: uiProp?.chevronIcon, alone: !resolvedIcon })"
|
|
81
|
+
/>
|
|
82
|
+
</span>
|
|
83
|
+
|
|
84
|
+
<span data-slot="label" :class="ui.label({ class: uiProp?.label })">
|
|
85
|
+
<UChatShimmer v-if="streaming && text" :text="text" v-bind="props.shimmer" />
|
|
86
|
+
<template v-else>{{ text }}</template>
|
|
87
|
+
<span v-if="suffix" data-slot="suffix" :class="ui.suffix({ class: uiProp?.suffix })">{{ suffix }}</span>
|
|
88
|
+
</span>
|
|
89
|
+
|
|
90
|
+
<UIcon
|
|
91
|
+
v-if="hasContent && chevron === 'trailing'"
|
|
92
|
+
:name="chevronIconName"
|
|
93
|
+
data-slot="trailingIcon"
|
|
94
|
+
:class="ui.trailingIcon({ class: uiProp?.trailingIcon })"
|
|
95
|
+
/>
|
|
96
|
+
</button>
|
|
97
|
+
</CollapsibleTrigger>
|
|
98
|
+
|
|
99
|
+
<CollapsibleContent data-slot="content" :class="ui.content({ class: uiProp?.content })">
|
|
100
|
+
<div data-slot="body" :class="ui.body({ class: uiProp?.body })">
|
|
101
|
+
<slot :open="isOpen" />
|
|
102
|
+
</div>
|
|
103
|
+
</CollapsibleContent>
|
|
104
|
+
</CollapsibleRoot>
|
|
105
|
+
</template>
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { CollapsibleRootProps } from 'reka-ui';
|
|
2
|
+
import type { VNode } from 'vue';
|
|
3
|
+
import type { AppConfig } from '@nuxt/schema';
|
|
4
|
+
import theme from '#build/ui/chat-tool';
|
|
5
|
+
import type { IconProps } from '../types';
|
|
6
|
+
import type { ChatShimmerProps } from './ChatShimmer.vue';
|
|
7
|
+
import type { ComponentConfig } from '../types/tv';
|
|
8
|
+
type ChatTool = ComponentConfig<typeof theme, AppConfig, 'chatTool'>;
|
|
9
|
+
export interface ChatToolProps extends Pick<CollapsibleRootProps, 'defaultOpen' | 'open' | 'disabled' | 'unmountOnHide'> {
|
|
10
|
+
/**
|
|
11
|
+
* The text content to display.
|
|
12
|
+
*/
|
|
13
|
+
text?: string;
|
|
14
|
+
/**
|
|
15
|
+
* The suffix text displayed after the main text.
|
|
16
|
+
*/
|
|
17
|
+
suffix?: string;
|
|
18
|
+
/**
|
|
19
|
+
* The icon displayed next to the trigger.
|
|
20
|
+
* @IconifyIcon
|
|
21
|
+
*/
|
|
22
|
+
icon?: IconProps['name'];
|
|
23
|
+
/**
|
|
24
|
+
* Whether the tool is in a loading state.
|
|
25
|
+
* @defaultValue false
|
|
26
|
+
*/
|
|
27
|
+
loading?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The icon displayed when loading.
|
|
30
|
+
* @defaultValue appConfig.ui.icons.loading
|
|
31
|
+
* @IconifyIcon
|
|
32
|
+
*/
|
|
33
|
+
loadingIcon?: IconProps['name'];
|
|
34
|
+
/**
|
|
35
|
+
* Whether the tool content is currently streaming.
|
|
36
|
+
* @defaultValue false
|
|
37
|
+
*/
|
|
38
|
+
streaming?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* The visual variant of the tool display.
|
|
41
|
+
* @defaultValue 'inline'
|
|
42
|
+
*/
|
|
43
|
+
variant?: ChatTool['variants']['variant'];
|
|
44
|
+
/**
|
|
45
|
+
* The position of the chevron icon.
|
|
46
|
+
* @defaultValue 'trailing'
|
|
47
|
+
*/
|
|
48
|
+
chevron?: 'leading' | 'trailing';
|
|
49
|
+
/**
|
|
50
|
+
* The icon displayed as the chevron.
|
|
51
|
+
* @defaultValue appConfig.ui.icons.chevronDown
|
|
52
|
+
* @IconifyIcon
|
|
53
|
+
*/
|
|
54
|
+
chevronIcon?: IconProps['name'];
|
|
55
|
+
/**
|
|
56
|
+
* Customize the [`ChatShimmer`](https://ui.nuxt.com/docs/components/chat-shimmer) component when streaming.
|
|
57
|
+
*/
|
|
58
|
+
shimmer?: Partial<Omit<ChatShimmerProps, 'text'>>;
|
|
59
|
+
class?: any;
|
|
60
|
+
ui?: ChatTool['slots'];
|
|
61
|
+
}
|
|
62
|
+
export interface ChatToolEmits {
|
|
63
|
+
'update:open': [value: boolean];
|
|
64
|
+
}
|
|
65
|
+
export interface ChatToolSlots {
|
|
66
|
+
default?(props: {
|
|
67
|
+
open: boolean;
|
|
68
|
+
}): VNode[];
|
|
69
|
+
}
|
|
70
|
+
declare const _default: typeof __VLS_export;
|
|
71
|
+
export default _default;
|
|
72
|
+
declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<ChatToolProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
73
|
+
"update:open": (value: boolean) => any;
|
|
74
|
+
}, string, import("vue").PublicProps, Readonly<ChatToolProps> & Readonly<{
|
|
75
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
76
|
+
}>, {
|
|
77
|
+
loading: boolean;
|
|
78
|
+
variant: ChatTool["variants"]["variant"];
|
|
79
|
+
open: boolean;
|
|
80
|
+
streaming: boolean;
|
|
81
|
+
unmountOnHide: boolean;
|
|
82
|
+
chevron: "leading" | "trailing";
|
|
83
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, ChatToolSlots>;
|
|
84
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
85
|
+
new (): {
|
|
86
|
+
$slots: S;
|
|
87
|
+
};
|
|
88
|
+
};
|