@gram-ai/elements 1.25.2 → 1.26.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/dist/components/Chat/stories/Charts.stories.d.ts +37 -0
- package/dist/components/Chat/stories/GenerativeUI.stories.d.ts +17 -0
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/buttonVariants.d.ts +1 -1
- package/dist/components/ui/charts.stories.d.ts +43 -0
- package/dist/components/ui/generative-ui.stories.d.ts +53 -0
- package/dist/components/ui/tool-ui.d.ts +16 -1
- package/dist/elements.cjs +1 -1
- package/dist/elements.css +1 -1
- package/dist/elements.js +6 -6
- package/dist/index-BpJstUh1.cjs +280 -0
- package/dist/index-BpJstUh1.cjs.map +1 -0
- package/dist/index-CUitXazZ.js +30426 -0
- package/dist/index-CUitXazZ.js.map +1 -0
- package/dist/index-DdrZQXwQ.cjs +147 -0
- package/dist/index-DdrZQXwQ.cjs.map +1 -0
- package/dist/index-DfqYP0CD.js +37062 -0
- package/dist/index-DfqYP0CD.js.map +1 -0
- package/dist/plugins/chart/catalog.d.ts +123 -0
- package/dist/plugins/chart/index.d.ts +1 -1
- package/dist/plugins/chart/ui/area-chart.d.ts +16 -0
- package/dist/plugins/chart/ui/bar-chart.d.ts +16 -0
- package/dist/plugins/chart/ui/donut-chart.d.ts +17 -0
- package/dist/plugins/chart/ui/index.d.ts +7 -0
- package/dist/plugins/chart/ui/line-chart.d.ts +17 -0
- package/dist/plugins/chart/ui/pie-chart.d.ts +15 -0
- package/dist/plugins/chart/ui/radar-chart.d.ts +14 -0
- package/dist/plugins/chart/ui/scatter-chart.d.ts +18 -0
- package/dist/plugins/components/MacOSWindowFrame.d.ts +13 -0
- package/dist/plugins/components/PluginLoadingState.d.ts +1 -1
- package/dist/plugins/generative-ui/catalog.d.ts +293 -0
- package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +18 -0
- package/dist/plugins/generative-ui/ui/accordion.d.ts +7 -0
- package/dist/plugins/generative-ui/ui/action-button.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +9 -0
- package/dist/plugins/generative-ui/ui/alert.d.ts +9 -0
- package/dist/plugins/generative-ui/ui/avatar-wrapper.d.ts +9 -0
- package/dist/plugins/generative-ui/ui/avatar.d.ts +11 -0
- package/dist/plugins/generative-ui/ui/badge.d.ts +12 -0
- package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +15 -0
- package/dist/plugins/generative-ui/ui/button.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/card.d.ts +9 -0
- package/dist/plugins/generative-ui/ui/checkbox-wrapper.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/checkbox.d.ts +4 -0
- package/dist/plugins/generative-ui/ui/data-table.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/dialog.d.ts +17 -0
- package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +25 -0
- package/dist/plugins/generative-ui/ui/grid.d.ts +6 -0
- package/dist/plugins/generative-ui/ui/index.d.ts +40 -0
- package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +11 -0
- package/dist/plugins/generative-ui/ui/input.d.ts +3 -0
- package/dist/plugins/generative-ui/ui/label.d.ts +4 -0
- package/dist/plugins/generative-ui/ui/list.d.ts +6 -0
- package/dist/plugins/generative-ui/ui/metric.d.ts +7 -0
- package/dist/plugins/generative-ui/ui/pagination.d.ts +13 -0
- package/dist/plugins/generative-ui/ui/popover.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/progress.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/radio-group.d.ts +5 -0
- package/dist/plugins/generative-ui/ui/select-wrapper.d.ts +13 -0
- package/dist/plugins/generative-ui/ui/select.d.ts +15 -0
- package/dist/plugins/generative-ui/ui/separator.d.ts +4 -0
- package/dist/plugins/generative-ui/ui/skeleton-wrapper.d.ts +9 -0
- package/dist/plugins/generative-ui/ui/skeleton.d.ts +2 -0
- package/dist/plugins/generative-ui/ui/stack.d.ts +8 -0
- package/dist/plugins/generative-ui/ui/switch.d.ts +6 -0
- package/dist/plugins/generative-ui/ui/table.d.ts +10 -0
- package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +21 -0
- package/dist/plugins/generative-ui/ui/tabs.d.ts +11 -0
- package/dist/plugins/generative-ui/ui/text.d.ts +7 -0
- package/dist/plugins/generative-ui/ui/textarea.d.ts +3 -0
- package/dist/plugins/generative-ui/ui/tooltip.d.ts +7 -0
- package/dist/plugins.cjs +1 -1
- package/dist/plugins.js +1 -1
- package/dist/{profiler-BaG0scxd.js → profiler-WoFj2UH8.js} +2 -2
- package/dist/{profiler-BaG0scxd.js.map → profiler-WoFj2UH8.js.map} +1 -1
- package/dist/{profiler-CuqENACf.cjs → profiler-ZLr2-8s7.cjs} +2 -2
- package/dist/{profiler-CuqENACf.cjs.map → profiler-ZLr2-8s7.cjs.map} +1 -1
- package/dist/{startRecording-BiLmoqZa.cjs → startRecording-BGnWDInp.cjs} +2 -2
- package/dist/{startRecording-BiLmoqZa.cjs.map → startRecording-BGnWDInp.cjs.map} +1 -1
- package/dist/{startRecording-86bHmd-l.js → startRecording-DzQo16WK.js} +2 -2
- package/dist/{startRecording-86bHmd-l.js.map → startRecording-DzQo16WK.js.map} +1 -1
- package/package.json +4 -1
- package/src/components/Chat/stories/Charts.stories.tsx +260 -0
- package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +6 -6
- package/src/components/Chat/stories/GenerativeUI.stories.tsx +113 -0
- package/src/components/Replay.stories.tsx +1 -1
- package/src/components/Replay.tsx +18 -13
- package/src/components/ui/charts.stories.tsx +246 -0
- package/src/components/ui/generative-ui.stories.tsx +557 -0
- package/src/components/ui/generative-ui.tsx +60 -360
- package/src/components/ui/tool-ui.stories.tsx +6 -3
- package/src/components/ui/tool-ui.tsx +31 -2
- package/src/hooks/useAuth.ts +17 -1
- package/src/hooks/useFollowOnSuggestions.ts +6 -1
- package/src/plugins/chart/catalog.ts +141 -0
- package/src/plugins/chart/component.tsx +79 -125
- package/src/plugins/chart/index.ts +141 -89
- package/src/plugins/chart/ui/area-chart.tsx +133 -0
- package/src/plugins/chart/ui/bar-chart.tsx +137 -0
- package/src/plugins/chart/ui/donut-chart.tsx +167 -0
- package/src/plugins/chart/ui/index.ts +7 -0
- package/src/plugins/chart/ui/line-chart.tsx +135 -0
- package/src/plugins/chart/ui/pie-chart.tsx +148 -0
- package/src/plugins/chart/ui/radar-chart.tsx +105 -0
- package/src/plugins/chart/ui/scatter-chart.tsx +132 -0
- package/src/plugins/components/MacOSWindowFrame.tsx +55 -0
- package/src/plugins/components/PluginLoadingState.tsx +9 -13
- package/src/plugins/generative-ui/catalog.ts +277 -0
- package/src/plugins/generative-ui/component.tsx +112 -21
- package/src/plugins/generative-ui/index.ts +20 -141
- package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +57 -0
- package/src/plugins/generative-ui/ui/accordion.tsx +66 -0
- package/src/plugins/generative-ui/ui/action-button.tsx +68 -0
- package/src/plugins/generative-ui/ui/alert-wrapper.tsx +26 -0
- package/src/plugins/generative-ui/ui/alert.tsx +66 -0
- package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +22 -0
- package/src/plugins/generative-ui/ui/avatar.tsx +109 -0
- package/src/plugins/generative-ui/ui/badge.tsx +65 -0
- package/src/plugins/generative-ui/ui/button-wrapper.tsx +32 -0
- package/src/plugins/generative-ui/ui/button.tsx +65 -0
- package/src/plugins/generative-ui/ui/card-wrapper.tsx +36 -0
- package/src/plugins/generative-ui/ui/card.tsx +92 -0
- package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +39 -0
- package/src/plugins/generative-ui/ui/checkbox.tsx +32 -0
- package/src/plugins/generative-ui/ui/data-table.tsx +53 -0
- package/src/plugins/generative-ui/ui/dialog.tsx +158 -0
- package/src/plugins/generative-ui/ui/dropdown-menu.tsx +257 -0
- package/src/plugins/generative-ui/ui/grid.tsx +29 -0
- package/src/plugins/generative-ui/ui/index.ts +43 -0
- package/src/plugins/generative-ui/ui/input-wrapper.tsx +38 -0
- package/src/plugins/generative-ui/ui/input.tsx +21 -0
- package/src/plugins/generative-ui/ui/label.tsx +24 -0
- package/src/plugins/generative-ui/ui/list.tsx +34 -0
- package/src/plugins/generative-ui/ui/metric.tsx +53 -0
- package/src/plugins/generative-ui/ui/pagination.tsx +127 -0
- package/src/plugins/generative-ui/ui/popover.tsx +89 -0
- package/src/plugins/generative-ui/ui/progress.tsx +57 -0
- package/src/plugins/generative-ui/ui/radio-group.tsx +45 -0
- package/src/plugins/generative-ui/ui/select-wrapper.tsx +41 -0
- package/src/plugins/generative-ui/ui/select.tsx +190 -0
- package/src/plugins/generative-ui/ui/separator.tsx +28 -0
- package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +30 -0
- package/src/plugins/generative-ui/ui/skeleton.tsx +13 -0
- package/src/plugins/generative-ui/ui/stack.tsx +54 -0
- package/src/plugins/generative-ui/ui/switch.tsx +35 -0
- package/src/plugins/generative-ui/ui/table.tsx +116 -0
- package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +51 -0
- package/src/plugins/generative-ui/ui/tabs.tsx +92 -0
- package/src/plugins/generative-ui/ui/text.tsx +33 -0
- package/src/plugins/generative-ui/ui/textarea.tsx +18 -0
- package/src/plugins/generative-ui/ui/tooltip.tsx +57 -0
- package/dist/components/Chat/stories/Plugins.stories.d.ts +0 -12
- package/dist/index-B8nSCdu4.cjs +0 -251
- package/dist/index-B8nSCdu4.cjs.map +0 -1
- package/dist/index-CAtaLV1E.cjs +0 -187
- package/dist/index-CAtaLV1E.cjs.map +0 -1
- package/dist/index-CJrwma08.js +0 -27232
- package/dist/index-CJrwma08.js.map +0 -1
- package/dist/index-DLWQ91ow.js +0 -40049
- package/dist/index-DLWQ91ow.js.map +0 -1
- package/src/components/Chat/stories/Plugins.stories.tsx +0 -158
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { createCatalog } from '@json-render/core'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Generative UI Catalog
|
|
6
|
+
*
|
|
7
|
+
* Defines all available components for LLM-generated UI.
|
|
8
|
+
* Components map to shadcn/ui primitives in the ui/ directory.
|
|
9
|
+
*/
|
|
10
|
+
export const catalog = createCatalog({
|
|
11
|
+
name: 'generative-ui',
|
|
12
|
+
components: {
|
|
13
|
+
// Layout
|
|
14
|
+
Stack: {
|
|
15
|
+
props: z.object({
|
|
16
|
+
direction: z.enum(['horizontal', 'vertical']).optional(),
|
|
17
|
+
gap: z.enum(['sm', 'md', 'lg']).optional(),
|
|
18
|
+
align: z.enum(['start', 'center', 'end', 'stretch']).optional(),
|
|
19
|
+
justify: z
|
|
20
|
+
.enum(['start', 'center', 'end', 'between', 'around'])
|
|
21
|
+
.optional(),
|
|
22
|
+
className: z.string().optional(),
|
|
23
|
+
}),
|
|
24
|
+
hasChildren: true,
|
|
25
|
+
description: 'Flex layout container for arranging child elements',
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
Grid: {
|
|
29
|
+
props: z.object({
|
|
30
|
+
columns: z.number().optional(),
|
|
31
|
+
gap: z.enum(['sm', 'md', 'lg']).optional(),
|
|
32
|
+
className: z.string().optional(),
|
|
33
|
+
}),
|
|
34
|
+
hasChildren: true,
|
|
35
|
+
description: 'Grid layout for arranging items in columns',
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
Card: {
|
|
39
|
+
props: z.object({
|
|
40
|
+
title: z.string().optional(),
|
|
41
|
+
className: z.string().optional(),
|
|
42
|
+
}),
|
|
43
|
+
hasChildren: true,
|
|
44
|
+
description: 'Container with optional title, border and padding',
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Typography
|
|
48
|
+
Text: {
|
|
49
|
+
props: z.object({
|
|
50
|
+
content: z.string(),
|
|
51
|
+
variant: z.enum(['heading', 'body', 'caption', 'code']).optional(),
|
|
52
|
+
className: z.string().optional(),
|
|
53
|
+
}),
|
|
54
|
+
description: 'Text content with styling variants',
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Data Display
|
|
58
|
+
Metric: {
|
|
59
|
+
props: z.object({
|
|
60
|
+
label: z.string(),
|
|
61
|
+
value: z.union([z.string(), z.number()]),
|
|
62
|
+
format: z.enum(['number', 'currency', 'percent']).optional(),
|
|
63
|
+
className: z.string().optional(),
|
|
64
|
+
}),
|
|
65
|
+
description:
|
|
66
|
+
'Display a key metric with label and formatted value (e.g., revenue, users)',
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
Badge: {
|
|
70
|
+
props: z.object({
|
|
71
|
+
content: z.string().optional(),
|
|
72
|
+
variant: z
|
|
73
|
+
.enum([
|
|
74
|
+
'default',
|
|
75
|
+
'secondary',
|
|
76
|
+
'destructive',
|
|
77
|
+
'outline',
|
|
78
|
+
'success',
|
|
79
|
+
'warning',
|
|
80
|
+
])
|
|
81
|
+
.optional(),
|
|
82
|
+
className: z.string().optional(),
|
|
83
|
+
}),
|
|
84
|
+
hasChildren: true,
|
|
85
|
+
description: 'Status badge or tag for categorization',
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
Progress: {
|
|
89
|
+
props: z.object({
|
|
90
|
+
value: z.number(),
|
|
91
|
+
max: z.number().optional(),
|
|
92
|
+
className: z.string().optional(),
|
|
93
|
+
}),
|
|
94
|
+
description: 'Progress bar showing completion percentage',
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
Table: {
|
|
98
|
+
props: z.object({
|
|
99
|
+
headers: z.array(z.string()).optional(),
|
|
100
|
+
rows: z.array(z.array(z.union([z.string(), z.number()]))),
|
|
101
|
+
className: z.string().optional(),
|
|
102
|
+
}),
|
|
103
|
+
description: 'Data table with headers and rows',
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
List: {
|
|
107
|
+
props: z.object({
|
|
108
|
+
items: z.array(z.string()),
|
|
109
|
+
ordered: z.boolean().optional(),
|
|
110
|
+
className: z.string().optional(),
|
|
111
|
+
}),
|
|
112
|
+
description: 'Ordered or unordered list of items',
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
// Feedback
|
|
116
|
+
Alert: {
|
|
117
|
+
props: z.object({
|
|
118
|
+
title: z.string(),
|
|
119
|
+
description: z.string().optional(),
|
|
120
|
+
variant: z.enum(['default', 'destructive']).optional(),
|
|
121
|
+
}),
|
|
122
|
+
description: 'Alert message for important information or errors',
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Structure
|
|
126
|
+
Separator: {
|
|
127
|
+
props: z.object({
|
|
128
|
+
orientation: z.enum(['horizontal', 'vertical']).optional(),
|
|
129
|
+
className: z.string().optional(),
|
|
130
|
+
}),
|
|
131
|
+
description: 'Visual divider between content sections',
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
Divider: {
|
|
135
|
+
props: z.object({
|
|
136
|
+
orientation: z.enum(['horizontal', 'vertical']).optional(),
|
|
137
|
+
className: z.string().optional(),
|
|
138
|
+
}),
|
|
139
|
+
description:
|
|
140
|
+
'Visual divider between content sections (alias for Separator)',
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// Interactive
|
|
144
|
+
Accordion: {
|
|
145
|
+
props: z.object({
|
|
146
|
+
type: z.enum(['single', 'multiple']).optional(),
|
|
147
|
+
}),
|
|
148
|
+
hasChildren: true,
|
|
149
|
+
description: 'Collapsible accordion container',
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
AccordionItem: {
|
|
153
|
+
props: z.object({
|
|
154
|
+
value: z.string(),
|
|
155
|
+
title: z.string(),
|
|
156
|
+
}),
|
|
157
|
+
hasChildren: true,
|
|
158
|
+
description: 'Individual accordion item with trigger and content',
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
Tabs: {
|
|
162
|
+
props: z.object({
|
|
163
|
+
defaultValue: z.string().optional(),
|
|
164
|
+
tabs: z.array(
|
|
165
|
+
z.object({
|
|
166
|
+
value: z.string(),
|
|
167
|
+
label: z.string(),
|
|
168
|
+
})
|
|
169
|
+
),
|
|
170
|
+
}),
|
|
171
|
+
hasChildren: true,
|
|
172
|
+
description: 'Tabbed content container',
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
TabContent: {
|
|
176
|
+
props: z.object({
|
|
177
|
+
value: z.string(),
|
|
178
|
+
}),
|
|
179
|
+
hasChildren: true,
|
|
180
|
+
description: 'Content panel for a specific tab',
|
|
181
|
+
},
|
|
182
|
+
|
|
183
|
+
// Actions
|
|
184
|
+
Button: {
|
|
185
|
+
props: z.object({
|
|
186
|
+
label: z.string(),
|
|
187
|
+
variant: z
|
|
188
|
+
.enum(['default', 'secondary', 'destructive', 'outline', 'ghost'])
|
|
189
|
+
.optional(),
|
|
190
|
+
size: z.enum(['default', 'sm', 'lg', 'icon']).optional(),
|
|
191
|
+
disabled: z.boolean().optional(),
|
|
192
|
+
action: z.string().optional(),
|
|
193
|
+
actionParams: z.record(z.string(), z.unknown()).optional(),
|
|
194
|
+
}),
|
|
195
|
+
description:
|
|
196
|
+
'Clickable button that can trigger actions. Use action/actionParams to call backend functions.',
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
ActionButton: {
|
|
200
|
+
props: z.object({
|
|
201
|
+
label: z.string(),
|
|
202
|
+
action: z.string(),
|
|
203
|
+
args: z.record(z.string(), z.unknown()).optional(),
|
|
204
|
+
variant: z
|
|
205
|
+
.enum(['default', 'secondary', 'destructive', 'outline', 'ghost'])
|
|
206
|
+
.optional(),
|
|
207
|
+
size: z.enum(['default', 'sm', 'lg', 'icon']).optional(),
|
|
208
|
+
className: z.string().optional(),
|
|
209
|
+
}),
|
|
210
|
+
description:
|
|
211
|
+
'Button that triggers a frontend tool call directly without LLM roundtrip',
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
// Form Elements
|
|
215
|
+
Input: {
|
|
216
|
+
props: z.object({
|
|
217
|
+
label: z.string().optional(),
|
|
218
|
+
placeholder: z.string().optional(),
|
|
219
|
+
type: z.enum(['text', 'email', 'password', 'number', 'tel']).optional(),
|
|
220
|
+
valuePath: z.string(),
|
|
221
|
+
}),
|
|
222
|
+
description: 'Text input field with optional label',
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
Checkbox: {
|
|
226
|
+
props: z.object({
|
|
227
|
+
label: z.string().optional(),
|
|
228
|
+
valuePath: z.string(),
|
|
229
|
+
defaultChecked: z.boolean().optional(),
|
|
230
|
+
}),
|
|
231
|
+
description: 'Checkbox input with label',
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
Select: {
|
|
235
|
+
props: z.object({
|
|
236
|
+
placeholder: z.string().optional(),
|
|
237
|
+
valuePath: z.string(),
|
|
238
|
+
options: z.array(
|
|
239
|
+
z.object({
|
|
240
|
+
value: z.string(),
|
|
241
|
+
label: z.string(),
|
|
242
|
+
})
|
|
243
|
+
),
|
|
244
|
+
}),
|
|
245
|
+
description: 'Dropdown select input',
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
// Display
|
|
249
|
+
Avatar: {
|
|
250
|
+
props: z.object({
|
|
251
|
+
src: z.string().optional(),
|
|
252
|
+
alt: z.string().optional(),
|
|
253
|
+
fallback: z.string(),
|
|
254
|
+
}),
|
|
255
|
+
description: 'User avatar with image and fallback initials',
|
|
256
|
+
},
|
|
257
|
+
|
|
258
|
+
Skeleton: {
|
|
259
|
+
props: z.object({
|
|
260
|
+
width: z.string().optional(),
|
|
261
|
+
height: z.string().optional(),
|
|
262
|
+
className: z.string().optional(),
|
|
263
|
+
}),
|
|
264
|
+
description: 'Loading placeholder skeleton',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
export type CatalogComponentProps = typeof catalog extends {
|
|
270
|
+
components: infer C
|
|
271
|
+
}
|
|
272
|
+
? {
|
|
273
|
+
[K in keyof C]: C[K] extends { props: infer P }
|
|
274
|
+
? z.infer<P extends z.ZodType ? P : never>
|
|
275
|
+
: never
|
|
276
|
+
}
|
|
277
|
+
: never
|
|
@@ -1,23 +1,109 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import { GenerativeUI } from '@/components/ui/generative-ui'
|
|
4
|
+
import { cn } from '@/lib/utils'
|
|
4
5
|
import { SyntaxHighlighterProps } from '@assistant-ui/react-markdown'
|
|
5
|
-
import { FC, useMemo } from 'react'
|
|
6
|
-
import {
|
|
6
|
+
import { FC, useEffect, useMemo, useState } from 'react'
|
|
7
|
+
import { MacOSWindowFrame } from '../components/MacOSWindowFrame'
|
|
7
8
|
|
|
8
9
|
const loadingMessages = [
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
10
|
+
// Crafting & Creating
|
|
11
|
+
'Arranging pixels with care...',
|
|
12
|
+
'Brewing something beautiful...',
|
|
13
|
+
'Crafting your masterpiece...',
|
|
14
|
+
'Painting with data...',
|
|
15
|
+
'Weaving digital magic...',
|
|
16
|
+
'Assembling the good stuff...',
|
|
17
|
+
'Polishing the details...',
|
|
18
|
+
'Putting the finishing touches...',
|
|
19
|
+
// Cooking & Food
|
|
20
|
+
'Simmering the results...',
|
|
21
|
+
'Letting the data marinate...',
|
|
22
|
+
'Adding a pinch of style...',
|
|
23
|
+
'Fresh out of the oven soon...',
|
|
24
|
+
'Whisking up your view...',
|
|
25
|
+
// Nature & Growth
|
|
26
|
+
'Growing your garden of data...',
|
|
27
|
+
'Watching the seeds sprout...',
|
|
28
|
+
'Letting things bloom...',
|
|
29
|
+
'Nature is taking its course...',
|
|
30
|
+
// Space & Magic
|
|
31
|
+
'Consulting the stars...',
|
|
32
|
+
'Channeling cosmic energy...',
|
|
33
|
+
'Summoning the results...',
|
|
34
|
+
'Waving the magic wand...',
|
|
35
|
+
'Sprinkling some stardust...',
|
|
36
|
+
'Aligning the planets...',
|
|
37
|
+
// Building & Engineering
|
|
38
|
+
'Tightening the bolts...',
|
|
39
|
+
'Connecting the dots...',
|
|
40
|
+
'Stacking the blocks...',
|
|
41
|
+
'Laying the foundation...',
|
|
42
|
+
'Raising the scaffolding...',
|
|
43
|
+
// Playful & Cute
|
|
44
|
+
'Herding the pixels...',
|
|
45
|
+
'Teaching data to dance...',
|
|
46
|
+
'Convincing bits to cooperate...',
|
|
47
|
+
'Giving electrons a pep talk...',
|
|
48
|
+
'Wrangling the numbers...',
|
|
49
|
+
'Coaxing the results out...',
|
|
50
|
+
'Almost there, pinky promise...',
|
|
51
|
+
'Good things take a moment...',
|
|
52
|
+
'Worth the wait...',
|
|
53
|
+
'Patience, grasshopper...',
|
|
54
|
+
'Hold tight...',
|
|
55
|
+
'Doing the thing...',
|
|
56
|
+
// Abstract & Poetic
|
|
57
|
+
'Folding space and time...',
|
|
58
|
+
'Untangling the threads...',
|
|
59
|
+
'Finding the signal...',
|
|
60
|
+
'Distilling the essence...',
|
|
61
|
+
'Turning chaos into order...',
|
|
62
|
+
'Making sense of it all...',
|
|
63
|
+
// Confident & Reassuring
|
|
64
|
+
'This is going to be good...',
|
|
65
|
+
"You're gonna love this...",
|
|
66
|
+
'Something nice is coming...',
|
|
67
|
+
'Just a heartbeat away...',
|
|
17
68
|
]
|
|
18
69
|
|
|
19
|
-
function
|
|
20
|
-
return
|
|
70
|
+
function getRandomStartIndex() {
|
|
71
|
+
return Math.floor(Math.random() * loadingMessages.length)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const CyclingLoadingMessage: FC = () => {
|
|
75
|
+
const [index, setIndex] = useState(getRandomStartIndex)
|
|
76
|
+
const [isVisible, setIsVisible] = useState(true)
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined
|
|
80
|
+
const interval = setInterval(() => {
|
|
81
|
+
// Fade out
|
|
82
|
+
setIsVisible(false)
|
|
83
|
+
|
|
84
|
+
// After fade out, change message and fade in
|
|
85
|
+
timeoutId = setTimeout(() => {
|
|
86
|
+
setIndex((prev) => (prev + 1) % loadingMessages.length)
|
|
87
|
+
setIsVisible(true)
|
|
88
|
+
}, 200)
|
|
89
|
+
}, 2000)
|
|
90
|
+
|
|
91
|
+
return () => {
|
|
92
|
+
clearInterval(interval)
|
|
93
|
+
if (timeoutId) clearTimeout(timeoutId)
|
|
94
|
+
}
|
|
95
|
+
}, [])
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<span
|
|
99
|
+
className={cn(
|
|
100
|
+
'shimmer text-muted-foreground text-sm transition-opacity duration-200',
|
|
101
|
+
isVisible ? 'opacity-100' : 'opacity-0'
|
|
102
|
+
)}
|
|
103
|
+
>
|
|
104
|
+
{loadingMessages[index]}
|
|
105
|
+
</span>
|
|
106
|
+
)
|
|
21
107
|
}
|
|
22
108
|
|
|
23
109
|
export const GenerativeUIRenderer: FC<SyntaxHighlighterProps> = ({ code }) => {
|
|
@@ -39,18 +125,23 @@ export const GenerativeUIRenderer: FC<SyntaxHighlighterProps> = ({ code }) => {
|
|
|
39
125
|
}
|
|
40
126
|
}, [code])
|
|
41
127
|
|
|
42
|
-
//
|
|
43
|
-
const loadingMessage = useMemo(() => getRandomLoadingMessage(), [])
|
|
44
|
-
|
|
45
|
-
// Show loading shimmer while JSON is incomplete/streaming
|
|
128
|
+
// Show loading state while JSON is incomplete/streaming
|
|
46
129
|
if (!content) {
|
|
47
|
-
return
|
|
130
|
+
return (
|
|
131
|
+
<MacOSWindowFrame>
|
|
132
|
+
<div className="bg-background flex min-h-[400px] items-center justify-center">
|
|
133
|
+
<CyclingLoadingMessage />
|
|
134
|
+
</div>
|
|
135
|
+
</MacOSWindowFrame>
|
|
136
|
+
)
|
|
48
137
|
}
|
|
49
138
|
|
|
50
|
-
// Render
|
|
139
|
+
// Render with macOS-style window frame
|
|
51
140
|
return (
|
|
52
|
-
<
|
|
53
|
-
<
|
|
54
|
-
|
|
141
|
+
<MacOSWindowFrame>
|
|
142
|
+
<div className="p-4">
|
|
143
|
+
<GenerativeUI content={content} />
|
|
144
|
+
</div>
|
|
145
|
+
</MacOSWindowFrame>
|
|
55
146
|
)
|
|
56
147
|
}
|
|
@@ -7,147 +7,26 @@ import { GenerativeUIRenderer } from './component'
|
|
|
7
7
|
*/
|
|
8
8
|
export const generativeUI: Plugin = {
|
|
9
9
|
language: 'ui',
|
|
10
|
-
prompt: `
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
Card - Container with optional title
|
|
32
|
-
props: { title?: string }
|
|
33
|
-
children: any components
|
|
34
|
-
|
|
35
|
-
Grid - Multi-column layout
|
|
36
|
-
props: { columns?: number } (default: 2)
|
|
37
|
-
children: any components
|
|
38
|
-
|
|
39
|
-
Stack - Vertical or horizontal flex layout
|
|
40
|
-
props: { direction?: "vertical" | "horizontal" } (default: "vertical")
|
|
41
|
-
children: any components
|
|
42
|
-
|
|
43
|
-
Metric - Displays a label and formatted value
|
|
44
|
-
props: { label: string, value: number, format?: "currency" | "percent" | "number" }
|
|
45
|
-
|
|
46
|
-
Table - Data table
|
|
47
|
-
props: { headers: string[], rows: any[][] }
|
|
48
|
-
|
|
49
|
-
Text - Text with variants
|
|
50
|
-
props: { content: string, variant?: "heading" | "body" | "caption" | "code" }
|
|
51
|
-
|
|
52
|
-
Badge - Status badge
|
|
53
|
-
props: { content: string, variant?: "default" | "success" | "warning" | "error" }
|
|
54
|
-
|
|
55
|
-
Progress - Progress bar
|
|
56
|
-
props: { value: number, max?: number, label?: string }
|
|
57
|
-
|
|
58
|
-
List - Bullet or numbered list
|
|
59
|
-
props: { items: string[], ordered?: boolean }
|
|
60
|
-
|
|
61
|
-
Divider - Horizontal line separator
|
|
62
|
-
|
|
63
|
-
ActionButton - Interactive button that triggers a tool call
|
|
64
|
-
props: {
|
|
65
|
-
label: string, // Button text
|
|
66
|
-
action: string, // Tool name to invoke when clicked
|
|
67
|
-
args?: object, // Arguments to pass to the tool
|
|
68
|
-
variant?: "default" | "secondary" | "outline" | "destructive"
|
|
69
|
-
}
|
|
70
|
-
NOTE: Only use ActionButton with tools you know are available
|
|
71
|
-
|
|
72
|
-
STRUCTURE:
|
|
73
|
-
Every UI spec is a tree with:
|
|
74
|
-
- "type": component name (required)
|
|
75
|
-
- "props": component properties (optional)
|
|
76
|
-
- "children": array of child components (optional)
|
|
77
|
-
|
|
78
|
-
EXAMPLE - DASHBOARD:
|
|
79
|
-
{
|
|
80
|
-
"type": "Card",
|
|
81
|
-
"props": { "title": "Sales Overview" },
|
|
82
|
-
"children": [
|
|
83
|
-
{
|
|
84
|
-
"type": "Grid",
|
|
85
|
-
"props": { "columns": 3 },
|
|
86
|
-
"children": [
|
|
87
|
-
{ "type": "Metric", "props": { "label": "Revenue", "value": 125000, "format": "currency" } },
|
|
88
|
-
{ "type": "Metric", "props": { "label": "Growth", "value": 0.15, "format": "percent" } },
|
|
89
|
-
{ "type": "Metric", "props": { "label": "Orders", "value": 1420, "format": "number" } }
|
|
90
|
-
]
|
|
91
|
-
},
|
|
92
|
-
{ "type": "Divider" },
|
|
93
|
-
{ "type": "Progress", "props": { "label": "Q1 Target", "value": 75, "max": 100 } }
|
|
94
|
-
]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
EXAMPLE - TABLE:
|
|
98
|
-
{
|
|
99
|
-
"type": "Card",
|
|
100
|
-
"props": { "title": "Users" },
|
|
101
|
-
"children": [
|
|
102
|
-
{
|
|
103
|
-
"type": "Table",
|
|
104
|
-
"props": {
|
|
105
|
-
"headers": ["Name", "Email", "Status"],
|
|
106
|
-
"rows": [
|
|
107
|
-
["Alice", "alice@example.com", "Active"],
|
|
108
|
-
["Bob", "bob@example.com", "Pending"]
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
EXAMPLE - WITH ACTIONS:
|
|
116
|
-
{
|
|
117
|
-
"type": "Card",
|
|
118
|
-
"props": { "title": "Pending Request #123" },
|
|
119
|
-
"children": [
|
|
120
|
-
{ "type": "Text", "props": { "variant": "body" }, "children": [{ "type": "Text", "props": {}, "children": [] }] },
|
|
121
|
-
{
|
|
122
|
-
"type": "Stack",
|
|
123
|
-
"props": { "direction": "horizontal" },
|
|
124
|
-
"children": [
|
|
125
|
-
{ "type": "ActionButton", "props": { "label": "Approve", "action": "approve_request", "args": { "id": 123 } } },
|
|
126
|
-
{ "type": "ActionButton", "props": { "label": "Reject", "action": "reject_request", "args": { "id": 123 }, "variant": "destructive" } }
|
|
127
|
-
]
|
|
128
|
-
}
|
|
129
|
-
]
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
STYLE GUIDELINES:
|
|
133
|
-
- Prefer spacious, breathable layouts with adequate visual hierarchy
|
|
134
|
-
- Use Grid with 2-3 columns max for metrics; avoid cramming too many items
|
|
135
|
-
- Group related content in Cards with clear titles
|
|
136
|
-
- Use Dividers to separate logical sections
|
|
137
|
-
- Balance information density: show what matters, hide the noise
|
|
138
|
-
- For dashboards, lead with the most important metrics at the top
|
|
139
|
-
|
|
140
|
-
CONTENT GUIDELINES:
|
|
141
|
-
- Outside the code block, provide context and insights about the data
|
|
142
|
-
- Do not describe technical implementation details
|
|
143
|
-
- Focus on what the data means, not how it's displayed
|
|
144
|
-
|
|
145
|
-
ACTION RESULT HANDLING:
|
|
146
|
-
When you receive a message starting with "[Action completed]" or "[Action failed]", the user clicked an action button and the tool has already been executed. Provide a brief, friendly acknowledgment of what happened. Keep your response concise - one sentence is usually enough. Do not re-execute the action or ask if they want to do something they just did.
|
|
147
|
-
|
|
148
|
-
Examples:
|
|
149
|
-
- "[Action completed] approve_request: Request #123 approved" → "Done! Request #123 has been approved."
|
|
150
|
-
- "[Action failed] delete_task: Permission denied" → "I couldn't delete that task - looks like you don't have permission."`,
|
|
10
|
+
prompt: `Render structured data as visual UI using \`\`\`ui code blocks with valid JSON.
|
|
11
|
+
|
|
12
|
+
Components:
|
|
13
|
+
- Card{title?} - container with border
|
|
14
|
+
- Grid{columns?} - multi-column layout
|
|
15
|
+
- Stack{direction?} - vertical/horizontal flex
|
|
16
|
+
- Metric{label,value,format?} - formatted number display (currency/percent/number)
|
|
17
|
+
- Table{headers[],rows[][]} - data table
|
|
18
|
+
- Text{content,variant?} - heading/body/caption/code
|
|
19
|
+
- Badge{content,variant?} - default/success/warning/error
|
|
20
|
+
- Progress{value,max?,label?} - progress bar
|
|
21
|
+
- List{items[],ordered?} - bullet/numbered list
|
|
22
|
+
- Divider - horizontal separator
|
|
23
|
+
- ActionButton{label,action,args?} - triggers tool call
|
|
24
|
+
|
|
25
|
+
Format: {"type":"Name","props":{...},"children":[...]}
|
|
26
|
+
|
|
27
|
+
Example: {"type":"Card","props":{"title":"Stats"},"children":[{"type":"Metric","props":{"label":"Revenue","value":50000,"format":"currency"}}]}
|
|
28
|
+
|
|
29
|
+
Use for dashboards, tables, metrics from tool results. Skip for simple text or errors.`,
|
|
151
30
|
Component: GenerativeUIRenderer,
|
|
152
31
|
Header: undefined,
|
|
153
32
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import {
|
|
5
|
+
Accordion as AccordionPrimitive,
|
|
6
|
+
AccordionItem as AccordionItemPrimitive,
|
|
7
|
+
AccordionTrigger,
|
|
8
|
+
AccordionContent,
|
|
9
|
+
} from './accordion'
|
|
10
|
+
|
|
11
|
+
export interface AccordionWrapperProps {
|
|
12
|
+
type?: 'single' | 'multiple'
|
|
13
|
+
children?: React.ReactNode
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Accordion wrapper that adapts the compound Accordion to the catalog's props-based API.
|
|
18
|
+
*/
|
|
19
|
+
export function AccordionWrapper({
|
|
20
|
+
type = 'single',
|
|
21
|
+
children,
|
|
22
|
+
}: AccordionWrapperProps) {
|
|
23
|
+
// Type assertion needed because Radix types are complex
|
|
24
|
+
const AccordionRoot = AccordionPrimitive as React.FC<{
|
|
25
|
+
type: 'single' | 'multiple'
|
|
26
|
+
collapsible?: boolean
|
|
27
|
+
children?: React.ReactNode
|
|
28
|
+
}>
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<AccordionRoot type={type} collapsible={type === 'single'}>
|
|
32
|
+
{children}
|
|
33
|
+
</AccordionRoot>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AccordionItemWrapperProps {
|
|
38
|
+
value: string
|
|
39
|
+
title: string
|
|
40
|
+
children?: React.ReactNode
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* AccordionItem wrapper that takes title as a prop and renders trigger + content.
|
|
45
|
+
*/
|
|
46
|
+
export function AccordionItemWrapper({
|
|
47
|
+
value,
|
|
48
|
+
title,
|
|
49
|
+
children,
|
|
50
|
+
}: AccordionItemWrapperProps) {
|
|
51
|
+
return (
|
|
52
|
+
<AccordionItemPrimitive value={value}>
|
|
53
|
+
<AccordionTrigger>{title}</AccordionTrigger>
|
|
54
|
+
<AccordionContent>{children}</AccordionContent>
|
|
55
|
+
</AccordionItemPrimitive>
|
|
56
|
+
)
|
|
57
|
+
}
|