@nuxt/ui 4.5.1 → 4.6.1
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/README.md +1 -1
- package/dist/module.d.mts +7 -0
- package/dist/module.json +2 -2
- package/dist/module.mjs +79 -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/ChatMessages.vue +14 -1
- package/dist/runtime/components/ChatPrompt.vue +6 -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/DashboardSidebar.vue +6 -3
- package/dist/runtime/components/Drawer.vue +6 -4
- 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 +3 -3
- 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 +6 -4
- 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 +6 -4
- 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 +12 -0
- package/dist/runtime/composables/index.js +12 -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/useIMEGuard.d.ts +10 -0
- package/dist/runtime/composables/useIMEGuard.js +22 -0
- 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 +23 -0
- package/dist/runtime/utils/ai.js +16 -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 +50 -47
- /package/dist/runtime/composables/{internal/useFilter.d.ts → useFilter.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ Thank you for considering contributing to Nuxt UI. Here are a few ways you can g
|
|
|
126
126
|
- Suggestions: Have any thoughts to enhance Nuxt UI? We'd love to hear them! Check out the [contribution guide](https://ui.nuxt.com/docs/getting-started/contribution) to share your suggestions.
|
|
127
127
|
|
|
128
128
|
> [!TIP]
|
|
129
|
-
> We provide
|
|
129
|
+
> We provide contributing guidelines through [`AGENTS.md`](https://github.com/nuxt/ui/blob/v4/AGENTS.md) for AI assistants to help you contribute to Nuxt UI. It is automatically picked up by all AI coding agents and guides through component structure, theming patterns, testing conventions, and documentation guidelines.
|
|
130
130
|
|
|
131
131
|
## Local Development
|
|
132
132
|
|
package/dist/module.d.mts
CHANGED
|
@@ -66,11 +66,18 @@ interface ModuleOptions {
|
|
|
66
66
|
/**
|
|
67
67
|
* Force the import of prose components even if `@nuxtjs/mdc` or `@nuxt/content` are not installed
|
|
68
68
|
* @defaultValue false
|
|
69
|
+
* @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#prose
|
|
70
|
+
*/
|
|
71
|
+
prose?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* @deprecated Use `prose` instead
|
|
74
|
+
* @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#mdc
|
|
69
75
|
*/
|
|
70
76
|
mdc?: boolean;
|
|
71
77
|
/**
|
|
72
78
|
* Force the import of content & prose components even if `@nuxt/content` is not installed
|
|
73
79
|
* @defaultValue false
|
|
80
|
+
* @see https://ui.nuxt.com/docs/getting-started/installation/nuxt#content
|
|
74
81
|
*/
|
|
75
82
|
content?: boolean;
|
|
76
83
|
/**
|
package/dist/module.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/ui",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.1",
|
|
4
4
|
"docs": "https://ui.nuxt.com/docs/getting-started/installation/nuxt",
|
|
5
5
|
"configKey": "ui",
|
|
6
6
|
"compatibility": {
|
|
7
|
-
"nuxt": ">=4.
|
|
7
|
+
"nuxt": ">=4.1.0"
|
|
8
8
|
},
|
|
9
9
|
"builder": {
|
|
10
10
|
"@nuxt/module-builder": "1.0.2",
|
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defu } from 'defu';
|
|
2
|
-
import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addComponentsDir, addImportsDir,
|
|
3
|
-
import { d as defaultOptions, r as resolveColors, a as getDefaultConfig, b as addTemplates } from './shared/ui.
|
|
2
|
+
import { defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addComponentsDir, addImportsDir, addImports } from '@nuxt/kit';
|
|
3
|
+
import { d as defaultOptions, r as resolveColors, a as getDefaultConfig, p as publicComposables, b as addTemplates } from './shared/ui.DJUbBpE2.mjs';
|
|
4
4
|
import '../dist/runtime/utils/index.js';
|
|
5
5
|
import 'node:url';
|
|
6
6
|
import 'scule';
|
|
@@ -11,7 +11,7 @@ import 'pathe';
|
|
|
11
11
|
import 'tinyglobby';
|
|
12
12
|
|
|
13
13
|
const name = "@nuxt/ui";
|
|
14
|
-
const version = "4.
|
|
14
|
+
const version = "4.6.1";
|
|
15
15
|
|
|
16
16
|
const module$1 = defineNuxtModule({
|
|
17
17
|
meta: {
|
|
@@ -20,10 +20,76 @@ const module$1 = defineNuxtModule({
|
|
|
20
20
|
docs: "https://ui.nuxt.com/docs/getting-started/installation/nuxt",
|
|
21
21
|
configKey: "ui",
|
|
22
22
|
compatibility: {
|
|
23
|
-
nuxt: ">=4.
|
|
23
|
+
nuxt: ">=4.1.0"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
defaults: defaultOptions,
|
|
27
|
+
moduleDependencies(nuxt) {
|
|
28
|
+
const userUiOptions = nuxt.options.ui || {};
|
|
29
|
+
return {
|
|
30
|
+
"@nuxt/icon": {
|
|
31
|
+
defaults: {
|
|
32
|
+
cssLayer: "base"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
...userUiOptions.fonts !== false && {
|
|
36
|
+
"@nuxt/fonts": {
|
|
37
|
+
defaults: {
|
|
38
|
+
defaults: {
|
|
39
|
+
weights: [400, 500, 600, 700]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
...userUiOptions.colorMode !== false && {
|
|
45
|
+
"@nuxtjs/color-mode": {
|
|
46
|
+
defaults: {
|
|
47
|
+
classSuffix: "",
|
|
48
|
+
disableTransition: true
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"@nuxtjs/mdc": {
|
|
53
|
+
optional: !userUiOptions.mdc && !userUiOptions.content,
|
|
54
|
+
defaults: {
|
|
55
|
+
highlight: {
|
|
56
|
+
theme: {
|
|
57
|
+
light: "material-theme-lighter",
|
|
58
|
+
default: "material-theme",
|
|
59
|
+
dark: "material-theme-palenight"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
components: {
|
|
63
|
+
map: {
|
|
64
|
+
"accordion": "ProseAccordion",
|
|
65
|
+
"accordion-item": "ProseAccordionItem",
|
|
66
|
+
"badge": "ProseBadge",
|
|
67
|
+
"callout": "ProseCallout",
|
|
68
|
+
"card": "ProseCard",
|
|
69
|
+
"card-group": "ProseCardGroup",
|
|
70
|
+
"caution": "ProseCaution",
|
|
71
|
+
"code-collapse": "ProseCodeCollapse",
|
|
72
|
+
"code-group": "ProseCodeGroup",
|
|
73
|
+
"code-icon": "ProseCodeIcon",
|
|
74
|
+
"code-preview": "ProseCodePreview",
|
|
75
|
+
"code-tree": "ProseCodeTree",
|
|
76
|
+
"collapsible": "ProseCollapsible",
|
|
77
|
+
"field": "ProseField",
|
|
78
|
+
"field-group": "ProseFieldGroup",
|
|
79
|
+
"icon": "ProseIcon",
|
|
80
|
+
"kbd": "ProseKbd",
|
|
81
|
+
"note": "ProseNote",
|
|
82
|
+
"steps": "ProseSteps",
|
|
83
|
+
"tabs": "ProseTabs",
|
|
84
|
+
"tabs-item": "ProseTabsItem",
|
|
85
|
+
"tip": "ProseTip",
|
|
86
|
+
"warning": "ProseWarning"
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
},
|
|
27
93
|
async setup(options, nuxt) {
|
|
28
94
|
const { resolve } = createResolver(import.meta.url);
|
|
29
95
|
options.theme = options.theme || {};
|
|
@@ -31,6 +97,7 @@ const module$1 = defineNuxtModule({
|
|
|
31
97
|
nuxt.options.ui = options;
|
|
32
98
|
nuxt.options.alias["#ui"] = resolve("./runtime");
|
|
33
99
|
nuxt.options.appConfig.ui = defu(nuxt.options.appConfig.ui || {}, getDefaultConfig(options.theme));
|
|
100
|
+
nuxt.options.build.transpile.push("reka-ui");
|
|
34
101
|
nuxt.options.app.rootAttrs = nuxt.options.app.rootAttrs || {};
|
|
35
102
|
nuxt.options.app.rootAttrs.class = [nuxt.options.app.rootAttrs.class, `${options.theme?.prefix ? options.theme.prefix + ":" : ""}isolate`].filter(Boolean).join(" ");
|
|
36
103
|
nuxt.hook("vite:extend", async ({ config }) => {
|
|
@@ -41,67 +108,8 @@ const module$1 = defineNuxtModule({
|
|
|
41
108
|
if (nuxt.options.builder !== "@nuxt/vite-builder") {
|
|
42
109
|
nuxt.options.postcss.plugins["@tailwindcss/postcss"] = {};
|
|
43
110
|
}
|
|
44
|
-
async function registerModule(name2, key, options2) {
|
|
45
|
-
if (!hasNuxtModule(name2)) {
|
|
46
|
-
await installModule(name2, defu(nuxt.options[key], options2));
|
|
47
|
-
} else {
|
|
48
|
-
nuxt.options[key] = defu(nuxt.options[key], options2);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
await registerModule("@nuxt/icon", "icon", {
|
|
52
|
-
cssLayer: "base"
|
|
53
|
-
});
|
|
54
|
-
if (options.fonts) {
|
|
55
|
-
await registerModule("@nuxt/fonts", "fonts", {
|
|
56
|
-
defaults: {
|
|
57
|
-
weights: [400, 500, 600, 700]
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
if (options.colorMode) {
|
|
62
|
-
await registerModule("@nuxtjs/color-mode", "colorMode", {
|
|
63
|
-
classSuffix: "",
|
|
64
|
-
disableTransition: true
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
111
|
addPlugin({ src: resolve("./runtime/plugins/colors") });
|
|
68
|
-
if (hasNuxtModule("@nuxtjs/mdc") ||
|
|
69
|
-
nuxt.options.mdc = defu(nuxt.options.mdc, {
|
|
70
|
-
highlight: {
|
|
71
|
-
theme: {
|
|
72
|
-
light: "material-theme-lighter",
|
|
73
|
-
default: "material-theme",
|
|
74
|
-
dark: "material-theme-palenight"
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
components: {
|
|
78
|
-
map: {
|
|
79
|
-
"accordion": "ProseAccordion",
|
|
80
|
-
"accordion-item": "ProseAccordionItem",
|
|
81
|
-
"badge": "ProseBadge",
|
|
82
|
-
"callout": "ProseCallout",
|
|
83
|
-
"card": "ProseCard",
|
|
84
|
-
"card-group": "ProseCardGroup",
|
|
85
|
-
"caution": "ProseCaution",
|
|
86
|
-
"code-collapse": "ProseCodeCollapse",
|
|
87
|
-
"code-group": "ProseCodeGroup",
|
|
88
|
-
"code-icon": "ProseCodeIcon",
|
|
89
|
-
"code-preview": "ProseCodePreview",
|
|
90
|
-
"code-tree": "ProseCodeTree",
|
|
91
|
-
"collapsible": "ProseCollapsible",
|
|
92
|
-
"field": "ProseField",
|
|
93
|
-
"field-group": "ProseFieldGroup",
|
|
94
|
-
"icon": "ProseIcon",
|
|
95
|
-
"kbd": "ProseKbd",
|
|
96
|
-
"note": "ProseNote",
|
|
97
|
-
"steps": "ProseSteps",
|
|
98
|
-
"tabs": "ProseTabs",
|
|
99
|
-
"tabs-item": "ProseTabsItem",
|
|
100
|
-
"tip": "ProseTip",
|
|
101
|
-
"warning": "ProseWarning"
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
});
|
|
112
|
+
if (options.prose || options.mdc || options.content || hasNuxtModule("@nuxtjs/mdc") || hasNuxtModule("@nuxt/content")) {
|
|
105
113
|
addComponentsDir({
|
|
106
114
|
path: resolve("./runtime/components/prose"),
|
|
107
115
|
pathPrefix: false,
|
|
@@ -109,14 +117,14 @@ const module$1 = defineNuxtModule({
|
|
|
109
117
|
global: true
|
|
110
118
|
});
|
|
111
119
|
}
|
|
112
|
-
if (hasNuxtModule("@nuxt/content")
|
|
120
|
+
if (options.content || hasNuxtModule("@nuxt/content")) {
|
|
113
121
|
addComponentsDir({
|
|
114
122
|
path: resolve("./runtime/components/content"),
|
|
115
123
|
pathPrefix: false,
|
|
116
124
|
prefix: options.prefix
|
|
117
125
|
});
|
|
118
126
|
}
|
|
119
|
-
if (hasNuxtModule("@nuxtjs/color-mode")) {
|
|
127
|
+
if (options.colorMode || hasNuxtModule("@nuxtjs/color-mode")) {
|
|
120
128
|
addComponentsDir({
|
|
121
129
|
path: resolve("./runtime/components/color-mode"),
|
|
122
130
|
pathPrefix: false,
|
|
@@ -131,7 +139,11 @@ const module$1 = defineNuxtModule({
|
|
|
131
139
|
prefix: options.prefix,
|
|
132
140
|
ignore: ["color-mode/**", "content/**", "prose/**"]
|
|
133
141
|
});
|
|
134
|
-
|
|
142
|
+
addImports(
|
|
143
|
+
Object.entries(publicComposables).flatMap(
|
|
144
|
+
([file, exports$1]) => exports$1.map((name2) => ({ name: name2, from: resolve(`./runtime/composables/${file}`) }))
|
|
145
|
+
)
|
|
146
|
+
);
|
|
135
147
|
addTemplates(options, nuxt, resolve);
|
|
136
148
|
}
|
|
137
149
|
});
|
|
@@ -39,17 +39,15 @@ const { size } = useAvatarGroup(props);
|
|
|
39
39
|
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.avatar || {} })({
|
|
40
40
|
size: size.value
|
|
41
41
|
}));
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"3xl": 48
|
|
52
|
-
})[props.size || "md"]);
|
|
42
|
+
const rootClass = computed(() => ui.value.root({ class: [uiProp.value?.root, props.class] }));
|
|
43
|
+
const sizePx = computed(() => {
|
|
44
|
+
const sizeClass = rootClass.value.split(" ").find((c) => /^size-\d+$/.test(c));
|
|
45
|
+
if (sizeClass) {
|
|
46
|
+
const num = Number.parseFloat(sizeClass.split("-")[1] ?? "");
|
|
47
|
+
if (!Number.isNaN(num)) return num * 4;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
});
|
|
53
51
|
const error = ref(false);
|
|
54
52
|
watch(() => props.src, () => {
|
|
55
53
|
if (error.value) {
|
|
@@ -67,7 +65,7 @@ function onError() {
|
|
|
67
65
|
:as="as.root"
|
|
68
66
|
v-bind="props.chip ? typeof props.chip === 'object' ? { inset: true, ...props.chip } : { inset: true } : {}"
|
|
69
67
|
data-slot="root"
|
|
70
|
-
:class="
|
|
68
|
+
:class="rootClass"
|
|
71
69
|
:style="props.style"
|
|
72
70
|
>
|
|
73
71
|
<component
|
|
@@ -101,7 +101,7 @@ function onClose() {
|
|
|
101
101
|
tabindex="-1"
|
|
102
102
|
raw
|
|
103
103
|
>
|
|
104
|
-
<span class="absolute inset-0
|
|
104
|
+
<span class="absolute inset-0" aria-hidden="true" />
|
|
105
105
|
</ULink>
|
|
106
106
|
|
|
107
107
|
<UContainer data-slot="container" :class="ui.container({ class: uiProp?.container })">
|
|
@@ -5,9 +5,10 @@ import theme from "#build/ui/blog-post";
|
|
|
5
5
|
<script setup>
|
|
6
6
|
import { computed } from "vue";
|
|
7
7
|
import { Primitive, useDateFormatter } from "reka-ui";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import { useAppConfig } from "#imports";
|
|
9
|
+
import { useLocale } from "../composables/useLocale";
|
|
10
10
|
import { useComponentUI } from "../composables/useComponentUI";
|
|
11
|
+
import ImageComponent from "#build/ui-image-component";
|
|
11
12
|
import { getSlotChildrenText } from "../utils";
|
|
12
13
|
import { tv } from "../utils/tv";
|
|
13
14
|
import ULink from "./Link.vue";
|
|
@@ -86,8 +86,8 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
|
|
|
86
86
|
class?: any;
|
|
87
87
|
ui?: Calendar['slots'];
|
|
88
88
|
}
|
|
89
|
-
export interface CalendarEmits<R extends boolean, M extends boolean> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
|
|
90
|
-
'update:modelValue': [
|
|
89
|
+
export interface CalendarEmits<R extends boolean = false, M extends boolean = false> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
|
|
90
|
+
'update:modelValue': [value: CalendarModelValue<R, M>];
|
|
91
91
|
}
|
|
92
92
|
export interface CalendarSlots {
|
|
93
93
|
'heading'?: (props: {
|
|
@@ -102,7 +102,7 @@ declare const _default: typeof __VLS_export;
|
|
|
102
102
|
export default _default;
|
|
103
103
|
declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
104
104
|
props: import("vue").PublicProps & __VLS_PrettifyLocal<CalendarProps<R, M> & {
|
|
105
|
-
"onUpdate:modelValue"?: ((
|
|
105
|
+
"onUpdate:modelValue"?: ((value: CalendarModelValue<R, M>) => any) | undefined;
|
|
106
106
|
"onUpdate:placeholder"?: ((...args: DateValue[]) => any) | undefined;
|
|
107
107
|
"onUpdate:validModelValue"?: ((date: DateRange) => any) | undefined;
|
|
108
108
|
"onUpdate:startValue"?: ((date: DateValue | undefined) => any) | undefined;
|
|
@@ -112,7 +112,7 @@ declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props:
|
|
|
112
112
|
expose: (exposed: {}) => void;
|
|
113
113
|
attrs: any;
|
|
114
114
|
slots: CalendarSlots;
|
|
115
|
-
emit: ((evt: "update:modelValue",
|
|
115
|
+
emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", ...args: [date: DateValue] & [date: DateValue]) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
|
|
116
116
|
}>) => import("vue").VNode & {
|
|
117
117
|
__ctx?: Awaited<typeof __VLS_setup>;
|
|
118
118
|
};
|
|
@@ -86,8 +86,8 @@ export interface CalendarProps<R extends boolean = false, M extends boolean = fa
|
|
|
86
86
|
class?: any;
|
|
87
87
|
ui?: Calendar['slots'];
|
|
88
88
|
}
|
|
89
|
-
export interface CalendarEmits<R extends boolean, M extends boolean> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
|
|
90
|
-
'update:modelValue': [
|
|
89
|
+
export interface CalendarEmits<R extends boolean = false, M extends boolean = false> extends Omit<CalendarRootEmits & RangeCalendarRootEmits, 'update:modelValue'> {
|
|
90
|
+
'update:modelValue': [value: CalendarModelValue<R, M>];
|
|
91
91
|
}
|
|
92
92
|
export interface CalendarSlots {
|
|
93
93
|
'heading'?: (props: {
|
|
@@ -102,7 +102,7 @@ declare const _default: typeof __VLS_export;
|
|
|
102
102
|
export default _default;
|
|
103
103
|
declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
|
|
104
104
|
props: import("vue").PublicProps & __VLS_PrettifyLocal<CalendarProps<R, M> & {
|
|
105
|
-
"onUpdate:modelValue"?: ((
|
|
105
|
+
"onUpdate:modelValue"?: ((value: CalendarModelValue<R, M>) => any) | undefined;
|
|
106
106
|
"onUpdate:placeholder"?: ((...args: DateValue[]) => any) | undefined;
|
|
107
107
|
"onUpdate:validModelValue"?: ((date: DateRange) => any) | undefined;
|
|
108
108
|
"onUpdate:startValue"?: ((date: DateValue | undefined) => any) | undefined;
|
|
@@ -112,7 +112,7 @@ declare const __VLS_export: <R extends boolean, M extends boolean>(__VLS_props:
|
|
|
112
112
|
expose: (exposed: {}) => void;
|
|
113
113
|
attrs: any;
|
|
114
114
|
slots: CalendarSlots;
|
|
115
|
-
emit: ((evt: "update:modelValue",
|
|
115
|
+
emit: ((evt: "update:modelValue", value: CalendarModelValue<R, M>) => void) & ((evt: "update:placeholder", ...args: [date: DateValue] & [date: DateValue]) => void) & ((evt: "update:validModelValue", date: DateRange) => void) & ((evt: "update:startValue", date: DateValue | undefined) => void);
|
|
116
116
|
}>) => import("vue").VNode & {
|
|
117
117
|
__ctx?: Awaited<typeof __VLS_setup>;
|
|
118
118
|
};
|
|
@@ -6,9 +6,10 @@ import theme from "#build/ui/changelog-version";
|
|
|
6
6
|
import { computed } from "vue";
|
|
7
7
|
import { Primitive, useDateFormatter } from "reka-ui";
|
|
8
8
|
import { createReusableTemplate } from "@vueuse/core";
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
9
|
+
import { useAppConfig } from "#imports";
|
|
10
|
+
import { useLocale } from "../composables/useLocale";
|
|
11
11
|
import { useComponentUI } from "../composables/useComponentUI";
|
|
12
|
+
import ImageComponent from "#build/ui-image-component";
|
|
12
13
|
import { getSlotChildrenText } from "../utils";
|
|
13
14
|
import { tv } from "../utils/tv";
|
|
14
15
|
import ULink from "./Link.vue";
|
|
@@ -28,7 +28,7 @@ const springOptions = computed(() => defu(typeof props.indicatorMotion === "obje
|
|
|
28
28
|
const scrollOptions = computed(() => typeof props.indicator === "object" ? props.indicator : {});
|
|
29
29
|
const { scrollYProgress } = useScroll(scrollOptions.value);
|
|
30
30
|
const y = useSpring(scrollYProgress, springOptions);
|
|
31
|
-
const height = useTransform(() => `${y.get() * 100}%`);
|
|
31
|
+
const height = useTransform(() => `${Number(y.get()) * 100}%`);
|
|
32
32
|
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.changelogVersions || {} })());
|
|
33
33
|
</script>
|
|
34
34
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VNode } from 'vue';
|
|
2
2
|
import type { AppConfig } from '@nuxt/schema';
|
|
3
|
-
import type { UIMessage } from 'ai';
|
|
3
|
+
import type { UIMessage, FileUIPart } from 'ai';
|
|
4
4
|
import theme from '#build/ui/chat-message';
|
|
5
5
|
import type { AvatarProps, ButtonProps, IconProps } from '../types';
|
|
6
6
|
import type { ComponentConfig } from '../types/tv';
|
|
@@ -53,6 +53,9 @@ export interface ChatMessageSlots {
|
|
|
53
53
|
avatar: ChatMessageProps['avatar'];
|
|
54
54
|
ui: ChatMessage['ui'];
|
|
55
55
|
}): VNode[];
|
|
56
|
+
files?(props: {
|
|
57
|
+
parts: FileUIPart[];
|
|
58
|
+
}): VNode[];
|
|
56
59
|
content?(props: ChatMessageProps): VNode[];
|
|
57
60
|
actions?(props: {
|
|
58
61
|
actions: ChatMessageProps['actions'];
|
|
@@ -32,6 +32,7 @@ const props = defineProps({
|
|
|
32
32
|
const slots = defineSlots();
|
|
33
33
|
const appConfig = useAppConfig();
|
|
34
34
|
const uiProp = useComponentUI("chatMessage", props);
|
|
35
|
+
const fileParts = computed(() => props.parts?.filter((part) => part.type === "file") ?? []);
|
|
35
36
|
const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.chatMessage || {} })({
|
|
36
37
|
variant: props.variant,
|
|
37
38
|
side: props.side,
|
|
@@ -43,6 +44,10 @@ const ui = computed(() => tv({ extend: tv(theme), ...appConfig.ui?.chatMessage |
|
|
|
43
44
|
|
|
44
45
|
<template>
|
|
45
46
|
<Primitive :as="as" :data-role="role" data-slot="root" :class="ui.root({ class: [uiProp?.root, props.class] })">
|
|
47
|
+
<div v-if="!!slots.files && fileParts.length" data-slot="files" :class="ui.files({ class: uiProp?.files })">
|
|
48
|
+
<slot name="files" :parts="fileParts" />
|
|
49
|
+
</div>
|
|
50
|
+
|
|
46
51
|
<div data-slot="container" :class="ui.container({ class: uiProp?.container })">
|
|
47
52
|
<div v-if="icon || avatar || !!slots.leading" data-slot="leading" :class="ui.leading({ class: uiProp?.leading })">
|
|
48
53
|
<slot name="leading" :avatar="avatar" :ui="ui">
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { VNode } from 'vue';
|
|
2
2
|
import type { AppConfig } from '@nuxt/schema';
|
|
3
|
-
import type { UIMessage } from 'ai';
|
|
3
|
+
import type { UIMessage, FileUIPart } from 'ai';
|
|
4
4
|
import theme from '#build/ui/chat-message';
|
|
5
5
|
import type { AvatarProps, ButtonProps, IconProps } from '../types';
|
|
6
6
|
import type { ComponentConfig } from '../types/tv';
|
|
@@ -53,6 +53,9 @@ export interface ChatMessageSlots {
|
|
|
53
53
|
avatar: ChatMessageProps['avatar'];
|
|
54
54
|
ui: ChatMessage['ui'];
|
|
55
55
|
}): VNode[];
|
|
56
|
+
files?(props: {
|
|
57
|
+
parts: FileUIPart[];
|
|
58
|
+
}): VNode[];
|
|
56
59
|
content?(props: ChatMessageProps): VNode[];
|
|
57
60
|
actions?(props: {
|
|
58
61
|
actions: ChatMessageProps['actions'];
|
|
@@ -29,6 +29,12 @@ const props = defineProps({
|
|
|
29
29
|
});
|
|
30
30
|
const slots = defineSlots();
|
|
31
31
|
const getProxySlots = () => omit(slots, ["default", "indicator", "viewport"]);
|
|
32
|
+
const showIndicator = computed(() => {
|
|
33
|
+
if (props.status === "submitted") return true;
|
|
34
|
+
if (props.status !== "streaming") return false;
|
|
35
|
+
const lastMessage = props.messages?.[props.messages.length - 1];
|
|
36
|
+
return lastMessage?.role === "assistant" && !lastMessage.parts?.length;
|
|
37
|
+
});
|
|
32
38
|
const appConfig = useAppConfig();
|
|
33
39
|
const uiProp = useComponentUI("chatMessages", props);
|
|
34
40
|
const userProps = toRef(() => defu(props.user, { side: "right", variant: "soft" }));
|
|
@@ -67,6 +73,13 @@ function scrollToBottom(smooth = true) {
|
|
|
67
73
|
}
|
|
68
74
|
}
|
|
69
75
|
watchThrottled([() => props.messages, () => props.status], ([_, status]) => {
|
|
76
|
+
if (!props.messages?.length) {
|
|
77
|
+
showAutoScroll.value = false;
|
|
78
|
+
userScrolledUp.value = false;
|
|
79
|
+
lastScrollTop.value = 0;
|
|
80
|
+
messagesRefs.value.clear();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
70
83
|
if (status !== "streaming") {
|
|
71
84
|
return;
|
|
72
85
|
}
|
|
@@ -197,7 +210,7 @@ onMounted(() => {
|
|
|
197
210
|
</slot>
|
|
198
211
|
|
|
199
212
|
<UChatMessage
|
|
200
|
-
v-if="
|
|
213
|
+
v-if="showIndicator"
|
|
201
214
|
id="indicator"
|
|
202
215
|
role="assistant"
|
|
203
216
|
v-bind="{ ...assistantProps, actions: void 0, parts: [] }"
|
|
@@ -8,6 +8,7 @@ import { Primitive, useForwardProps } from "reka-ui";
|
|
|
8
8
|
import { reactivePick } from "@vueuse/core";
|
|
9
9
|
import { useAppConfig } from "#imports";
|
|
10
10
|
import { useComponentUI } from "../composables/useComponentUI";
|
|
11
|
+
import { useIMEGuard } from "../composables/useIMEGuard";
|
|
11
12
|
import { useLocale } from "../composables/useLocale";
|
|
12
13
|
import { omit, transformUI } from "../utils";
|
|
13
14
|
import { tv } from "../utils/tv";
|
|
@@ -54,6 +55,9 @@ function blur(e) {
|
|
|
54
55
|
textareaRef.value?.textareaRef?.blur();
|
|
55
56
|
emits("close", e);
|
|
56
57
|
}
|
|
58
|
+
const { onKeydown: onEnter, onCompositionEnd } = useIMEGuard((event) => {
|
|
59
|
+
submit(event);
|
|
60
|
+
});
|
|
57
61
|
defineExpose({
|
|
58
62
|
textareaRef: toRef(() => textareaRef.value?.textareaRef)
|
|
59
63
|
});
|
|
@@ -76,7 +80,8 @@ defineExpose({
|
|
|
76
80
|
:ui="transformUI(omit(ui, ['root', 'body', 'header', 'footer']), uiProp)"
|
|
77
81
|
data-slot="body"
|
|
78
82
|
:class="ui.body({ class: uiProp?.body })"
|
|
79
|
-
@keydown.enter.exact
|
|
83
|
+
@keydown.enter.exact="onEnter"
|
|
84
|
+
@compositionend="onCompositionEnd"
|
|
80
85
|
@keydown.esc="blur"
|
|
81
86
|
>
|
|
82
87
|
<template v-for="(_, name) in getProxySlots()" #[name]="slotData">
|
|
@@ -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
|
+
};
|