@gram-ai/elements 1.25.1 → 1.26.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/components/Chat/stories/Charts.stories.d.ts +37 -0
- package/dist/components/Chat/stories/GenerativeUI.stories.d.ts +17 -0
- package/dist/components/Chat/stories/MessageFeedback.stories.d.ts +1 -1
- 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/contexts/ChatIdContext.d.ts +11 -0
- package/dist/contexts/contexts.d.ts +1 -0
- package/dist/elements.cjs +1 -1
- package/dist/elements.css +1 -1
- package/dist/elements.js +7 -6
- package/dist/index-BJnv49-A.js +37057 -0
- package/dist/index-BJnv49-A.js.map +1 -0
- 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-ChW-CSuu.cjs +147 -0
- package/dist/index-ChW-CSuu.cjs.map +1 -0
- package/dist/index.d.ts +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-CijCgLrw.js → profiler-D4Tw5ecI.js} +2 -2
- package/dist/{profiler-CijCgLrw.js.map → profiler-D4Tw5ecI.js.map} +1 -1
- package/dist/{profiler-DAT0DL1W.cjs → profiler-DCWYDZ1F.cjs} +2 -2
- package/dist/{profiler-DAT0DL1W.cjs.map → profiler-DCWYDZ1F.cjs.map} +1 -1
- package/dist/{startRecording-DotsE8QT.cjs → startRecording-3sTskM3H.cjs} +2 -2
- package/dist/{startRecording-DotsE8QT.cjs.map → startRecording-3sTskM3H.cjs.map} +1 -1
- package/dist/{startRecording-gmhENmf0.js → startRecording-BHhcCWQE.js} +2 -2
- package/dist/{startRecording-gmhENmf0.js.map → startRecording-BHhcCWQE.js.map} +1 -1
- package/dist/types/index.d.ts +4 -4
- 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/Chat/stories/MessageFeedback.stories.tsx +6 -6
- package/src/components/Chat/stories/ToolApproval.stories.tsx +10 -10
- package/src/components/Chat/stories/Tools.stories.tsx +122 -104
- package/src/components/Chat/stories/Variants.stories.tsx +1 -1
- package/src/components/Replay.stories.tsx +1 -1
- package/src/components/Replay.tsx +18 -13
- package/src/components/ShadowRoot.tsx +5 -1
- package/src/components/assistant-ui/message-feedback.tsx +6 -7
- package/src/components/assistant-ui/thread.tsx +76 -11
- 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/contexts/ChatIdContext.tsx +21 -0
- package/src/contexts/ElementsProvider.tsx +77 -37
- package/src/contexts/contexts.ts +2 -0
- package/src/hooks/useAuth.ts +18 -3
- package/src/hooks/useFollowOnSuggestions.ts +6 -1
- package/src/index.ts +1 -0
- 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/src/types/index.ts +4 -4
- package/dist/components/Chat/stories/Plugins.stories.d.ts +0 -12
- package/dist/index-C3UbmFRR.cjs +0 -178
- package/dist/index-C3UbmFRR.cjs.map +0 -1
- package/dist/index-CtyV0c-T.js +0 -27225
- package/dist/index-CtyV0c-T.js.map +0 -1
- package/dist/index-DxJwZ5Kc.js +0 -39975
- package/dist/index-DxJwZ5Kc.js.map +0 -1
- package/dist/index-iUSSoKFz.cjs +0 -251
- package/dist/index-iUSSoKFz.cjs.map +0 -1
- package/src/components/Chat/stories/Plugins.stories.tsx +0 -158
|
@@ -1,18 +1,36 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { useToolExecution } from '@/contexts/ToolExecutionContext'
|
|
4
3
|
import { useDensity } from '@/hooks/useDensity'
|
|
5
|
-
import { useRadius } from '@/hooks/useRadius'
|
|
6
4
|
import { cn } from '@/lib/utils'
|
|
7
5
|
import { isJsonRenderTree, type JsonRenderNode } from '@/lib/generative-ui'
|
|
8
|
-
import {
|
|
6
|
+
import { AlertCircleIcon } from 'lucide-react'
|
|
7
|
+
import { FC, useMemo } from 'react'
|
|
8
|
+
|
|
9
|
+
// Import all components from the generative-ui plugin ui directory
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
AccordionWrapper,
|
|
12
|
+
AccordionItemWrapper,
|
|
13
|
+
ActionButton,
|
|
14
|
+
AlertWrapper,
|
|
15
|
+
AvatarWrapper,
|
|
16
|
+
Badge,
|
|
17
|
+
ButtonWrapper,
|
|
18
|
+
CardWrapper,
|
|
19
|
+
CheckboxWrapper,
|
|
20
|
+
DataTable,
|
|
21
|
+
Grid,
|
|
22
|
+
InputWrapper,
|
|
23
|
+
List,
|
|
24
|
+
Metric,
|
|
25
|
+
Progress,
|
|
26
|
+
SelectWrapper,
|
|
27
|
+
Separator,
|
|
28
|
+
SkeletonWrapper,
|
|
29
|
+
Stack,
|
|
30
|
+
TabsWrapper,
|
|
31
|
+
TabContentWrapper,
|
|
32
|
+
Text,
|
|
33
|
+
} from '@/plugins/generative-ui/ui'
|
|
16
34
|
|
|
17
35
|
interface GenerativeUIProps {
|
|
18
36
|
/** The JSON content to render - can be a json-render tree or raw object */
|
|
@@ -25,357 +43,39 @@ interface GenerativeUIProps {
|
|
|
25
43
|
* Built-in components for rendering json-render trees.
|
|
26
44
|
* These provide a default set of UI primitives for tool results.
|
|
27
45
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
style: 'percent',
|
|
62
|
-
minimumFractionDigits: 1,
|
|
63
|
-
}).format(numValue)
|
|
64
|
-
case 'number':
|
|
65
|
-
default:
|
|
66
|
-
return new Intl.NumberFormat('en-US').format(numValue)
|
|
67
|
-
}
|
|
68
|
-
}, [value, format])
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<div className={cn('flex flex-col gap-2', className as string)}>
|
|
72
|
-
<span className="text-muted-foreground text-sm">{String(label)}</span>
|
|
73
|
-
<span className="text-3xl font-bold">{formattedValue}</span>
|
|
74
|
-
</div>
|
|
75
|
-
)
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
Grid: ({ columns = 2, children, className }) => {
|
|
79
|
-
const d = useDensity()
|
|
80
|
-
return (
|
|
81
|
-
<div
|
|
82
|
-
className={cn('grid', d('gap-lg'), className as string)}
|
|
83
|
-
style={{
|
|
84
|
-
gridTemplateColumns: `repeat(${columns as number}, minmax(0, 1fr))`,
|
|
85
|
-
}}
|
|
86
|
-
>
|
|
87
|
-
{children as React.ReactNode}
|
|
88
|
-
</div>
|
|
89
|
-
)
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
Stack: ({ direction = 'vertical', children, className }) => {
|
|
93
|
-
const d = useDensity()
|
|
94
|
-
return (
|
|
95
|
-
<div
|
|
96
|
-
className={cn(
|
|
97
|
-
'flex',
|
|
98
|
-
direction === 'horizontal' ? 'flex-row' : 'flex-col',
|
|
99
|
-
d('gap-md'),
|
|
100
|
-
className as string
|
|
101
|
-
)}
|
|
102
|
-
>
|
|
103
|
-
{children as React.ReactNode}
|
|
104
|
-
</div>
|
|
105
|
-
)
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
Text: ({ children, content, variant = 'body', className }) => {
|
|
109
|
-
const variantClasses: Record<string, string> = {
|
|
110
|
-
heading: 'text-lg font-semibold',
|
|
111
|
-
body: 'text-sm',
|
|
112
|
-
caption: 'text-xs text-muted-foreground',
|
|
113
|
-
code: 'font-mono text-sm bg-muted px-1 rounded',
|
|
114
|
-
}
|
|
115
|
-
// Support both content prop (for direct text) and children (for nested components)
|
|
116
|
-
const textContent = content != null ? String(content) : null
|
|
117
|
-
return (
|
|
118
|
-
<span
|
|
119
|
-
className={cn(variantClasses[variant as string], className as string)}
|
|
120
|
-
>
|
|
121
|
-
{textContent ?? (children as React.ReactNode)}
|
|
122
|
-
</span>
|
|
123
|
-
)
|
|
124
|
-
},
|
|
125
|
-
|
|
126
|
-
Badge: ({ children, content, variant = 'default', className }) => {
|
|
127
|
-
const r = useRadius()
|
|
128
|
-
const variantClasses: Record<string, string> = {
|
|
129
|
-
default: 'bg-primary text-primary-foreground',
|
|
130
|
-
secondary: 'bg-secondary text-secondary-foreground',
|
|
131
|
-
success:
|
|
132
|
-
'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100',
|
|
133
|
-
warning:
|
|
134
|
-
'bg-amber-100 text-amber-800 dark:bg-amber-900 dark:text-amber-100',
|
|
135
|
-
error: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100',
|
|
136
|
-
}
|
|
137
|
-
// Support both content prop (for direct text) and children (for nested components)
|
|
138
|
-
const textContent = content != null ? String(content) : null
|
|
139
|
-
return (
|
|
140
|
-
<span
|
|
141
|
-
className={cn(
|
|
142
|
-
'inline-flex items-center px-2 py-0.5 text-xs font-medium',
|
|
143
|
-
r('sm'),
|
|
144
|
-
variantClasses[variant as string] ?? variantClasses.default,
|
|
145
|
-
className as string
|
|
146
|
-
)}
|
|
147
|
-
>
|
|
148
|
-
{textContent ?? (children as React.ReactNode)}
|
|
149
|
-
</span>
|
|
150
|
-
)
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
Table: ({ headers, rows, className }) => {
|
|
154
|
-
const r = useRadius()
|
|
155
|
-
const headerArray = Array.isArray(headers) ? (headers as string[]) : []
|
|
156
|
-
const rowsArray = Array.isArray(rows) ? (rows as unknown[][]) : []
|
|
157
|
-
return (
|
|
158
|
-
<div className={cn('overflow-auto', className as string)}>
|
|
159
|
-
<table className={cn('w-full border-collapse text-sm', r('lg'))}>
|
|
160
|
-
{headerArray.length > 0 && (
|
|
161
|
-
<thead>
|
|
162
|
-
<tr className="border-border border-b">
|
|
163
|
-
{headerArray.map((header, i) => (
|
|
164
|
-
<th
|
|
165
|
-
key={i}
|
|
166
|
-
className="text-muted-foreground px-4 py-3 text-left font-medium"
|
|
167
|
-
>
|
|
168
|
-
{header}
|
|
169
|
-
</th>
|
|
170
|
-
))}
|
|
171
|
-
</tr>
|
|
172
|
-
</thead>
|
|
173
|
-
)}
|
|
174
|
-
<tbody>
|
|
175
|
-
{rowsArray.map((row, i) => (
|
|
176
|
-
<tr key={i} className="border-border border-b last:border-0">
|
|
177
|
-
{row.map((cell, j) => (
|
|
178
|
-
<td key={j} className="px-4 py-3">
|
|
179
|
-
{String(cell)}
|
|
180
|
-
</td>
|
|
181
|
-
))}
|
|
182
|
-
</tr>
|
|
183
|
-
))}
|
|
184
|
-
</tbody>
|
|
185
|
-
</table>
|
|
186
|
-
</div>
|
|
187
|
-
)
|
|
188
|
-
},
|
|
189
|
-
|
|
190
|
-
List: ({ items, ordered = false, className }) => {
|
|
191
|
-
const Tag = ordered ? 'ol' : 'ul'
|
|
192
|
-
const itemsArray = Array.isArray(items) ? (items as string[]) : []
|
|
193
|
-
return (
|
|
194
|
-
<Tag
|
|
195
|
-
className={cn(
|
|
196
|
-
'list-inside space-y-2 text-sm',
|
|
197
|
-
ordered ? 'list-decimal' : 'list-disc',
|
|
198
|
-
className as string
|
|
199
|
-
)}
|
|
200
|
-
>
|
|
201
|
-
{itemsArray.map((item, i) => (
|
|
202
|
-
<li key={i}>{item}</li>
|
|
203
|
-
))}
|
|
204
|
-
</Tag>
|
|
205
|
-
)
|
|
206
|
-
},
|
|
207
|
-
|
|
208
|
-
Divider: ({ className }) => (
|
|
209
|
-
<hr className={cn('border-border my-4', className as string)} />
|
|
210
|
-
),
|
|
211
|
-
|
|
212
|
-
Progress: ({ value, max = 100, label, className }) => {
|
|
213
|
-
const r = useRadius()
|
|
214
|
-
const numValue = Number(value)
|
|
215
|
-
const numMax = Number(max)
|
|
216
|
-
const percentage =
|
|
217
|
-
isNaN(numValue) || isNaN(numMax) || numMax === 0
|
|
218
|
-
? 0
|
|
219
|
-
: Math.min(100, Math.max(0, (numValue / numMax) * 100))
|
|
220
|
-
const labelStr = label != null ? String(label) : null
|
|
221
|
-
return (
|
|
222
|
-
<div className={cn('w-full space-y-2', className as string)}>
|
|
223
|
-
{labelStr && (
|
|
224
|
-
<div className="flex justify-between text-sm">
|
|
225
|
-
<span>{labelStr}</span>
|
|
226
|
-
<span className="text-muted-foreground">
|
|
227
|
-
{percentage.toFixed(0)}%
|
|
228
|
-
</span>
|
|
229
|
-
</div>
|
|
230
|
-
)}
|
|
231
|
-
<div className={cn('bg-muted h-3 overflow-hidden', r('sm'))}>
|
|
232
|
-
<div
|
|
233
|
-
className={cn('bg-primary h-full transition-all', r('sm'))}
|
|
234
|
-
style={{ width: `${percentage}%` }}
|
|
235
|
-
/>
|
|
236
|
-
</div>
|
|
237
|
-
</div>
|
|
238
|
-
)
|
|
239
|
-
},
|
|
240
|
-
|
|
241
|
-
ActionButton: ({ label, action, args, variant = 'default', className }) => {
|
|
242
|
-
const r = useRadius()
|
|
243
|
-
const { executeTool, isToolAvailable } = useToolExecution()
|
|
244
|
-
const runtime = useThreadRuntime({ optional: true })
|
|
245
|
-
const [isLoading, setIsLoading] = useState(false)
|
|
246
|
-
const [result, setResult] = useState<{
|
|
247
|
-
success: boolean
|
|
248
|
-
message?: string
|
|
249
|
-
} | null>(null)
|
|
250
|
-
|
|
251
|
-
const toolAvailable = action ? isToolAvailable(action as string) : false
|
|
252
|
-
|
|
253
|
-
const handleClick = useCallback(async () => {
|
|
254
|
-
if (!action) return
|
|
255
|
-
|
|
256
|
-
setIsLoading(true)
|
|
257
|
-
setResult(null)
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
const toolResult = await executeTool(
|
|
261
|
-
action as string,
|
|
262
|
-
(args as Record<string, unknown>) ?? {}
|
|
263
|
-
)
|
|
264
|
-
|
|
265
|
-
if (toolResult.success) {
|
|
266
|
-
// Format the result message
|
|
267
|
-
let message = 'Done'
|
|
268
|
-
if (toolResult.result) {
|
|
269
|
-
if (typeof toolResult.result === 'string') {
|
|
270
|
-
message = toolResult.result
|
|
271
|
-
} else if (
|
|
272
|
-
typeof toolResult.result === 'object' &&
|
|
273
|
-
toolResult.result !== null &&
|
|
274
|
-
'content' in toolResult.result
|
|
275
|
-
) {
|
|
276
|
-
// Handle MCP tool result format
|
|
277
|
-
const content = (
|
|
278
|
-
toolResult.result as { content: Array<{ text?: string }> }
|
|
279
|
-
).content
|
|
280
|
-
if (Array.isArray(content) && content[0]?.text) {
|
|
281
|
-
message = content[0].text
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
setResult({ success: true, message })
|
|
286
|
-
|
|
287
|
-
// Notify the LLM of the action result so it can respond
|
|
288
|
-
if (runtime) {
|
|
289
|
-
await runtime.append({
|
|
290
|
-
role: 'user',
|
|
291
|
-
content: [
|
|
292
|
-
{
|
|
293
|
-
type: 'text',
|
|
294
|
-
text: `[Action completed] ${action}: ${message}`,
|
|
295
|
-
},
|
|
296
|
-
],
|
|
297
|
-
})
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
setResult({ success: false, message: toolResult.error })
|
|
301
|
-
|
|
302
|
-
// Also notify on failure so LLM can help
|
|
303
|
-
if (runtime) {
|
|
304
|
-
await runtime.append({
|
|
305
|
-
role: 'user',
|
|
306
|
-
content: [
|
|
307
|
-
{
|
|
308
|
-
type: 'text',
|
|
309
|
-
text: `[Action failed] ${action}: ${toolResult.error}`,
|
|
310
|
-
},
|
|
311
|
-
],
|
|
312
|
-
})
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
} catch (err) {
|
|
316
|
-
const errorMessage =
|
|
317
|
-
err instanceof Error ? err.message : 'Unknown error'
|
|
318
|
-
setResult({
|
|
319
|
-
success: false,
|
|
320
|
-
message: errorMessage,
|
|
321
|
-
})
|
|
322
|
-
} finally {
|
|
323
|
-
setIsLoading(false)
|
|
324
|
-
}
|
|
325
|
-
}, [action, args, executeTool, runtime])
|
|
326
|
-
|
|
327
|
-
const variantClasses: Record<string, string> = {
|
|
328
|
-
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
|
|
329
|
-
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
330
|
-
outline:
|
|
331
|
-
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
|
|
332
|
-
destructive:
|
|
333
|
-
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// Show result state if we have one
|
|
337
|
-
if (result) {
|
|
338
|
-
return (
|
|
339
|
-
<div
|
|
340
|
-
className={cn(
|
|
341
|
-
'inline-flex items-center gap-2 px-4 py-2 text-sm',
|
|
342
|
-
r('md'),
|
|
343
|
-
result.success
|
|
344
|
-
? 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100'
|
|
345
|
-
: 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100',
|
|
346
|
-
className as string
|
|
347
|
-
)}
|
|
348
|
-
>
|
|
349
|
-
{result.success ? (
|
|
350
|
-
<CheckCircleIcon className="size-4" />
|
|
351
|
-
) : (
|
|
352
|
-
<XCircleIcon className="size-4" />
|
|
353
|
-
)}
|
|
354
|
-
<span className="max-w-[200px] truncate">
|
|
355
|
-
{result.message ?? (result.success ? 'Success' : 'Failed')}
|
|
356
|
-
</span>
|
|
357
|
-
</div>
|
|
358
|
-
)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return (
|
|
362
|
-
<button
|
|
363
|
-
onClick={handleClick}
|
|
364
|
-
disabled={isLoading || !toolAvailable}
|
|
365
|
-
title={!toolAvailable ? `Tool "${action}" not available` : undefined}
|
|
366
|
-
className={cn(
|
|
367
|
-
'inline-flex items-center justify-center gap-2 px-4 py-2 text-sm font-medium transition-colors',
|
|
368
|
-
'disabled:pointer-events-none disabled:opacity-50',
|
|
369
|
-
r('md'),
|
|
370
|
-
variantClasses[variant as string] ?? variantClasses.default,
|
|
371
|
-
className as string
|
|
372
|
-
)}
|
|
373
|
-
>
|
|
374
|
-
{isLoading && <Loader2Icon className="size-4 animate-spin" />}
|
|
375
|
-
{String(label)}
|
|
376
|
-
</button>
|
|
377
|
-
)
|
|
378
|
-
},
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
47
|
+
const components: Record<string, FC<any>> = {
|
|
48
|
+
// Layout
|
|
49
|
+
Card: CardWrapper,
|
|
50
|
+
Grid,
|
|
51
|
+
Stack,
|
|
52
|
+
// Typography
|
|
53
|
+
Text,
|
|
54
|
+
// Data Display
|
|
55
|
+
Metric,
|
|
56
|
+
Badge,
|
|
57
|
+
Table: DataTable,
|
|
58
|
+
List,
|
|
59
|
+
Progress,
|
|
60
|
+
Avatar: AvatarWrapper,
|
|
61
|
+
Skeleton: SkeletonWrapper,
|
|
62
|
+
// Feedback
|
|
63
|
+
Alert: AlertWrapper,
|
|
64
|
+
// Structure
|
|
65
|
+
Divider: Separator,
|
|
66
|
+
Separator,
|
|
67
|
+
// Interactive
|
|
68
|
+
Accordion: AccordionWrapper,
|
|
69
|
+
AccordionItem: AccordionItemWrapper,
|
|
70
|
+
Tabs: TabsWrapper,
|
|
71
|
+
TabContent: TabContentWrapper,
|
|
72
|
+
// Actions
|
|
73
|
+
Button: ButtonWrapper,
|
|
74
|
+
ActionButton,
|
|
75
|
+
// Form Elements
|
|
76
|
+
Input: InputWrapper,
|
|
77
|
+
Checkbox: CheckboxWrapper,
|
|
78
|
+
Select: SelectWrapper,
|
|
379
79
|
}
|
|
380
80
|
|
|
381
81
|
/**
|
|
@@ -7,14 +7,17 @@ import { ToolUI } from './tool-ui'
|
|
|
7
7
|
// However, to use this design variant, we'd have to add lots of metadata to the tool parts
|
|
8
8
|
|
|
9
9
|
const meta: Meta<typeof ToolUI> = {
|
|
10
|
+
title: 'Components/Tool UI',
|
|
10
11
|
component: ToolUI,
|
|
11
12
|
parameters: {
|
|
12
|
-
layout: '
|
|
13
|
+
layout: 'fullscreen',
|
|
13
14
|
},
|
|
14
15
|
decorators: [
|
|
15
16
|
(Story) => (
|
|
16
|
-
<div className="
|
|
17
|
-
<
|
|
17
|
+
<div className="bg-background text-foreground flex min-h-screen items-start justify-center p-6">
|
|
18
|
+
<div className="w-[400px]">
|
|
19
|
+
<Story />
|
|
20
|
+
</div>
|
|
18
21
|
</div>
|
|
19
22
|
),
|
|
20
23
|
],
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react'
|
|
2
|
+
|
|
3
|
+
export interface ChatIdContextValue {
|
|
4
|
+
chatId: string | null
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const ChatIdContext = createContext<ChatIdContextValue | null>(null)
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Hook to access the current chat ID from the Elements context.
|
|
11
|
+
* Works in both history-enabled and history-disabled modes.
|
|
12
|
+
*
|
|
13
|
+
* @returns The current chat ID, or null if not yet initialized
|
|
14
|
+
*/
|
|
15
|
+
export const useChatId = () => {
|
|
16
|
+
const context = useContext(ChatIdContext)
|
|
17
|
+
if (!context) {
|
|
18
|
+
throw new Error('useChatId must be used within ElementsProvider')
|
|
19
|
+
}
|
|
20
|
+
return context.chatId
|
|
21
|
+
}
|