@cloudbase/agent-react-ui 1.0.1-alpha.32
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 +123 -0
- package/components.json +21 -0
- package/dist/index.css +4241 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +59 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.js +2169 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2182 -0
- package/dist/index.mjs.map +1 -0
- package/example/.env.sample +2 -0
- package/example/App.tsx +368 -0
- package/example/app.css +1 -0
- package/example/index.html +12 -0
- package/example/main.tsx +9 -0
- package/example/vite.config.ts +34 -0
- package/package.json +75 -0
- package/postcss.config.cjs +3 -0
- package/src/components/ai-elements/agent.tsx +140 -0
- package/src/components/ai-elements/artifact.tsx +147 -0
- package/src/components/ai-elements/attachments.tsx +421 -0
- package/src/components/ai-elements/audio-player.tsx +228 -0
- package/src/components/ai-elements/canvas.tsx +22 -0
- package/src/components/ai-elements/chain-of-thought.tsx +228 -0
- package/src/components/ai-elements/checkpoint.tsx +71 -0
- package/src/components/ai-elements/code-block.tsx +532 -0
- package/src/components/ai-elements/commit.tsx +448 -0
- package/src/components/ai-elements/confirmation.tsx +176 -0
- package/src/components/ai-elements/connection.tsx +28 -0
- package/src/components/ai-elements/context.tsx +408 -0
- package/src/components/ai-elements/controls.tsx +18 -0
- package/src/components/ai-elements/conversation.tsx +100 -0
- package/src/components/ai-elements/edge.tsx +140 -0
- package/src/components/ai-elements/environment-variables.tsx +295 -0
- package/src/components/ai-elements/file-tree.tsx +258 -0
- package/src/components/ai-elements/image.tsx +24 -0
- package/src/components/ai-elements/inline-citation.tsx +287 -0
- package/src/components/ai-elements/message.tsx +336 -0
- package/src/components/ai-elements/mic-selector.tsx +370 -0
- package/src/components/ai-elements/model-selector.tsx +211 -0
- package/src/components/ai-elements/node.tsx +71 -0
- package/src/components/ai-elements/open-in-chat.tsx +365 -0
- package/src/components/ai-elements/package-info.tsx +233 -0
- package/src/components/ai-elements/panel.tsx +15 -0
- package/src/components/ai-elements/persona.tsx +270 -0
- package/src/components/ai-elements/plan.tsx +142 -0
- package/src/components/ai-elements/prompt-input.tsx +1263 -0
- package/src/components/ai-elements/queue.tsx +274 -0
- package/src/components/ai-elements/reasoning.tsx +193 -0
- package/src/components/ai-elements/sandbox.tsx +126 -0
- package/src/components/ai-elements/schema-display.tsx +458 -0
- package/src/components/ai-elements/shimmer.tsx +64 -0
- package/src/components/ai-elements/snippet.tsx +139 -0
- package/src/components/ai-elements/sources.tsx +77 -0
- package/src/components/ai-elements/speech-input.tsx +301 -0
- package/src/components/ai-elements/stack-trace.tsx +482 -0
- package/src/components/ai-elements/suggestion.tsx +53 -0
- package/src/components/ai-elements/task.tsx +87 -0
- package/src/components/ai-elements/terminal.tsx +261 -0
- package/src/components/ai-elements/test-results.tsx +485 -0
- package/src/components/ai-elements/tool.tsx +174 -0
- package/src/components/ai-elements/toolbar.tsx +16 -0
- package/src/components/ai-elements/transcription.tsx +124 -0
- package/src/components/ai-elements/voice-selector.tsx +479 -0
- package/src/components/ai-elements/web-preview.tsx +263 -0
- package/src/components/chat/Chat.tsx +178 -0
- package/src/components/chat/Input.tsx +98 -0
- package/src/components/chat/Message.tsx +276 -0
- package/src/components/chat/index.ts +2 -0
- package/src/components/index.ts +1 -0
- package/src/components/ui/accordion.tsx +64 -0
- package/src/components/ui/alert.tsx +66 -0
- package/src/components/ui/avatar.tsx +107 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/button-group.tsx +83 -0
- package/src/components/ui/button.tsx +64 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/carousel.tsx +239 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/command.tsx +184 -0
- package/src/components/ui/dialog.tsx +158 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/hover-card.tsx +42 -0
- package/src/components/ui/input-group.tsx +168 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/popover.tsx +87 -0
- package/src/components/ui/progress.tsx +31 -0
- package/src/components/ui/scroll-area.tsx +56 -0
- package/src/components/ui/select.tsx +190 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/switch.tsx +33 -0
- package/src/components/ui/tabs.tsx +91 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/css/global.css +123 -0
- package/src/css/index.css +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-copy-to-clipboard.ts +31 -0
- package/src/index.ts +4 -0
- package/src/lib/utils.ts +6 -0
- package/src/locales/context.ts +8 -0
- package/src/locales/hooks.ts +20 -0
- package/src/locales/index.ts +3 -0
- package/src/locales/langs/en.ts +17 -0
- package/src/locales/langs/index.ts +12 -0
- package/src/locales/langs/zh-cn.ts +18 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +21 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import {
|
|
6
|
+
Collapsible,
|
|
7
|
+
CollapsibleContent,
|
|
8
|
+
CollapsibleTrigger,
|
|
9
|
+
} from "@/components/ui/collapsible";
|
|
10
|
+
import { cn } from "@/lib/utils";
|
|
11
|
+
import {
|
|
12
|
+
CheckIcon,
|
|
13
|
+
CopyIcon,
|
|
14
|
+
FileIcon,
|
|
15
|
+
GitCommitIcon,
|
|
16
|
+
MinusIcon,
|
|
17
|
+
PlusIcon,
|
|
18
|
+
} from "lucide-react";
|
|
19
|
+
import {
|
|
20
|
+
type ComponentProps,
|
|
21
|
+
type HTMLAttributes,
|
|
22
|
+
useEffect,
|
|
23
|
+
useRef,
|
|
24
|
+
useState,
|
|
25
|
+
} from "react";
|
|
26
|
+
|
|
27
|
+
export type CommitProps = ComponentProps<typeof Collapsible>;
|
|
28
|
+
|
|
29
|
+
export const Commit = ({ className, children, ...props }: CommitProps) => (
|
|
30
|
+
<Collapsible
|
|
31
|
+
className={cn("rounded-lg border bg-background", className)}
|
|
32
|
+
{...props}
|
|
33
|
+
>
|
|
34
|
+
{children}
|
|
35
|
+
</Collapsible>
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export type CommitHeaderProps = ComponentProps<typeof CollapsibleTrigger>;
|
|
39
|
+
|
|
40
|
+
export const CommitHeader = ({
|
|
41
|
+
className,
|
|
42
|
+
children,
|
|
43
|
+
...props
|
|
44
|
+
}: CommitHeaderProps) => (
|
|
45
|
+
<CollapsibleTrigger asChild {...props}>
|
|
46
|
+
<div
|
|
47
|
+
className={cn(
|
|
48
|
+
"group flex cursor-pointer items-center justify-between gap-4 p-3 text-left transition-colors hover:opacity-80",
|
|
49
|
+
className
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
</div>
|
|
54
|
+
</CollapsibleTrigger>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
export type CommitHashProps = HTMLAttributes<HTMLSpanElement>;
|
|
58
|
+
|
|
59
|
+
export const CommitHash = ({
|
|
60
|
+
className,
|
|
61
|
+
children,
|
|
62
|
+
...props
|
|
63
|
+
}: CommitHashProps) => (
|
|
64
|
+
<span className={cn("font-mono text-xs", className)} {...props}>
|
|
65
|
+
<GitCommitIcon className="mr-1 inline-block size-3" />
|
|
66
|
+
{children}
|
|
67
|
+
</span>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
export type CommitMessageProps = HTMLAttributes<HTMLSpanElement>;
|
|
71
|
+
|
|
72
|
+
export const CommitMessage = ({
|
|
73
|
+
className,
|
|
74
|
+
children,
|
|
75
|
+
...props
|
|
76
|
+
}: CommitMessageProps) => (
|
|
77
|
+
<span className={cn("font-medium text-sm", className)} {...props}>
|
|
78
|
+
{children}
|
|
79
|
+
</span>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
export type CommitMetadataProps = HTMLAttributes<HTMLDivElement>;
|
|
83
|
+
|
|
84
|
+
export const CommitMetadata = ({
|
|
85
|
+
className,
|
|
86
|
+
children,
|
|
87
|
+
...props
|
|
88
|
+
}: CommitMetadataProps) => (
|
|
89
|
+
<div
|
|
90
|
+
className={cn(
|
|
91
|
+
"flex items-center gap-2 text-muted-foreground text-xs",
|
|
92
|
+
className
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
>
|
|
96
|
+
{children}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
export type CommitSeparatorProps = HTMLAttributes<HTMLSpanElement>;
|
|
101
|
+
|
|
102
|
+
export const CommitSeparator = ({
|
|
103
|
+
className,
|
|
104
|
+
children,
|
|
105
|
+
...props
|
|
106
|
+
}: CommitSeparatorProps) => (
|
|
107
|
+
<span className={className} {...props}>
|
|
108
|
+
{children ?? "•"}
|
|
109
|
+
</span>
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
export type CommitInfoProps = HTMLAttributes<HTMLDivElement>;
|
|
113
|
+
|
|
114
|
+
export const CommitInfo = ({
|
|
115
|
+
className,
|
|
116
|
+
children,
|
|
117
|
+
...props
|
|
118
|
+
}: CommitInfoProps) => (
|
|
119
|
+
<div className={cn("flex flex-1 flex-col", className)} {...props}>
|
|
120
|
+
{children}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
export type CommitAuthorProps = HTMLAttributes<HTMLDivElement>;
|
|
125
|
+
|
|
126
|
+
export const CommitAuthor = ({
|
|
127
|
+
className,
|
|
128
|
+
children,
|
|
129
|
+
...props
|
|
130
|
+
}: CommitAuthorProps) => (
|
|
131
|
+
<div className={cn("flex items-center", className)} {...props}>
|
|
132
|
+
{children}
|
|
133
|
+
</div>
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
export type CommitAuthorAvatarProps = ComponentProps<typeof Avatar> & {
|
|
137
|
+
initials: string;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
export const CommitAuthorAvatar = ({
|
|
141
|
+
initials,
|
|
142
|
+
className,
|
|
143
|
+
...props
|
|
144
|
+
}: CommitAuthorAvatarProps) => (
|
|
145
|
+
<Avatar className={cn("size-8", className)} {...props}>
|
|
146
|
+
<AvatarFallback className="text-xs">{initials}</AvatarFallback>
|
|
147
|
+
</Avatar>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
export type CommitTimestampProps = HTMLAttributes<HTMLTimeElement> & {
|
|
151
|
+
date: Date;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export const CommitTimestamp = ({
|
|
155
|
+
date,
|
|
156
|
+
className,
|
|
157
|
+
children,
|
|
158
|
+
...props
|
|
159
|
+
}: CommitTimestampProps) => {
|
|
160
|
+
const formatted = new Intl.RelativeTimeFormat("en", {
|
|
161
|
+
numeric: "auto",
|
|
162
|
+
}).format(
|
|
163
|
+
Math.round((date.getTime() - Date.now()) / (1000 * 60 * 60 * 24)),
|
|
164
|
+
"day"
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return (
|
|
168
|
+
<time
|
|
169
|
+
className={cn("text-xs", className)}
|
|
170
|
+
dateTime={date.toISOString()}
|
|
171
|
+
{...props}
|
|
172
|
+
>
|
|
173
|
+
{children ?? formatted}
|
|
174
|
+
</time>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export type CommitActionsProps = HTMLAttributes<HTMLDivElement>;
|
|
179
|
+
|
|
180
|
+
export const CommitActions = ({
|
|
181
|
+
className,
|
|
182
|
+
children,
|
|
183
|
+
...props
|
|
184
|
+
}: CommitActionsProps) => (
|
|
185
|
+
// biome-ignore lint/a11y/noNoninteractiveElementInteractions: stopPropagation required for nested interactions
|
|
186
|
+
// biome-ignore lint/a11y/useSemanticElements: fieldset doesn't fit this UI pattern
|
|
187
|
+
<div
|
|
188
|
+
className={cn("flex items-center gap-1", className)}
|
|
189
|
+
onClick={(e) => e.stopPropagation()}
|
|
190
|
+
onKeyDown={(e) => e.stopPropagation()}
|
|
191
|
+
role="group"
|
|
192
|
+
{...props}
|
|
193
|
+
>
|
|
194
|
+
{children}
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
export type CommitCopyButtonProps = ComponentProps<typeof Button> & {
|
|
199
|
+
hash: string;
|
|
200
|
+
onCopy?: () => void;
|
|
201
|
+
onError?: (error: Error) => void;
|
|
202
|
+
timeout?: number;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const CommitCopyButton = ({
|
|
206
|
+
hash,
|
|
207
|
+
onCopy,
|
|
208
|
+
onError,
|
|
209
|
+
timeout = 2000,
|
|
210
|
+
children,
|
|
211
|
+
className,
|
|
212
|
+
...props
|
|
213
|
+
}: CommitCopyButtonProps) => {
|
|
214
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
215
|
+
const timeoutRef = useRef<number>(0);
|
|
216
|
+
|
|
217
|
+
const copyToClipboard = async () => {
|
|
218
|
+
if (typeof window === "undefined" || !navigator?.clipboard?.writeText) {
|
|
219
|
+
onError?.(new Error("Clipboard API not available"));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
try {
|
|
224
|
+
if (!isCopied) {
|
|
225
|
+
await navigator.clipboard.writeText(hash);
|
|
226
|
+
setIsCopied(true);
|
|
227
|
+
onCopy?.();
|
|
228
|
+
timeoutRef.current = window.setTimeout(
|
|
229
|
+
() => setIsCopied(false),
|
|
230
|
+
timeout
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
} catch (error) {
|
|
234
|
+
onError?.(error as Error);
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
useEffect(
|
|
239
|
+
() => () => {
|
|
240
|
+
window.clearTimeout(timeoutRef.current);
|
|
241
|
+
},
|
|
242
|
+
[]
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const Icon = isCopied ? CheckIcon : CopyIcon;
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<Button
|
|
249
|
+
className={cn("size-7 shrink-0", className)}
|
|
250
|
+
onClick={copyToClipboard}
|
|
251
|
+
size="icon"
|
|
252
|
+
variant="ghost"
|
|
253
|
+
{...props}
|
|
254
|
+
>
|
|
255
|
+
{children ?? <Icon size={14} />}
|
|
256
|
+
</Button>
|
|
257
|
+
);
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
export type CommitContentProps = ComponentProps<typeof CollapsibleContent>;
|
|
261
|
+
|
|
262
|
+
export const CommitContent = ({
|
|
263
|
+
className,
|
|
264
|
+
children,
|
|
265
|
+
...props
|
|
266
|
+
}: CommitContentProps) => (
|
|
267
|
+
<CollapsibleContent className={cn("border-t p-3", className)} {...props}>
|
|
268
|
+
{children}
|
|
269
|
+
</CollapsibleContent>
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
export type CommitFilesProps = HTMLAttributes<HTMLDivElement>;
|
|
273
|
+
|
|
274
|
+
export const CommitFiles = ({
|
|
275
|
+
className,
|
|
276
|
+
children,
|
|
277
|
+
...props
|
|
278
|
+
}: CommitFilesProps) => (
|
|
279
|
+
<div className={cn("space-y-1", className)} {...props}>
|
|
280
|
+
{children}
|
|
281
|
+
</div>
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
export type CommitFileProps = HTMLAttributes<HTMLDivElement>;
|
|
285
|
+
|
|
286
|
+
export const CommitFile = ({
|
|
287
|
+
className,
|
|
288
|
+
children,
|
|
289
|
+
...props
|
|
290
|
+
}: CommitFileProps) => (
|
|
291
|
+
<div
|
|
292
|
+
className={cn(
|
|
293
|
+
"flex items-center justify-between gap-2 rounded px-2 py-1 text-sm hover:bg-muted/50",
|
|
294
|
+
className
|
|
295
|
+
)}
|
|
296
|
+
{...props}
|
|
297
|
+
>
|
|
298
|
+
{children}
|
|
299
|
+
</div>
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
export type CommitFileInfoProps = HTMLAttributes<HTMLDivElement>;
|
|
303
|
+
|
|
304
|
+
export const CommitFileInfo = ({
|
|
305
|
+
className,
|
|
306
|
+
children,
|
|
307
|
+
...props
|
|
308
|
+
}: CommitFileInfoProps) => (
|
|
309
|
+
<div className={cn("flex min-w-0 items-center gap-2", className)} {...props}>
|
|
310
|
+
{children}
|
|
311
|
+
</div>
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
const fileStatusStyles = {
|
|
315
|
+
added: "text-green-600 dark:text-green-400",
|
|
316
|
+
modified: "text-yellow-600 dark:text-yellow-400",
|
|
317
|
+
deleted: "text-red-600 dark:text-red-400",
|
|
318
|
+
renamed: "text-blue-600 dark:text-blue-400",
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const fileStatusLabels = {
|
|
322
|
+
added: "A",
|
|
323
|
+
modified: "M",
|
|
324
|
+
deleted: "D",
|
|
325
|
+
renamed: "R",
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
export type CommitFileStatusProps = HTMLAttributes<HTMLSpanElement> & {
|
|
329
|
+
status: "added" | "modified" | "deleted" | "renamed";
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
export const CommitFileStatus = ({
|
|
333
|
+
status,
|
|
334
|
+
className,
|
|
335
|
+
children,
|
|
336
|
+
...props
|
|
337
|
+
}: CommitFileStatusProps) => (
|
|
338
|
+
<span
|
|
339
|
+
className={cn(
|
|
340
|
+
"font-medium font-mono text-xs",
|
|
341
|
+
fileStatusStyles[status],
|
|
342
|
+
className
|
|
343
|
+
)}
|
|
344
|
+
{...props}
|
|
345
|
+
>
|
|
346
|
+
{children ?? fileStatusLabels[status]}
|
|
347
|
+
</span>
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
export type CommitFileIconProps = ComponentProps<typeof FileIcon>;
|
|
351
|
+
|
|
352
|
+
export const CommitFileIcon = ({
|
|
353
|
+
className,
|
|
354
|
+
...props
|
|
355
|
+
}: CommitFileIconProps) => (
|
|
356
|
+
<FileIcon
|
|
357
|
+
className={cn("size-3.5 shrink-0 text-muted-foreground", className)}
|
|
358
|
+
{...props}
|
|
359
|
+
/>
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
export type CommitFilePathProps = HTMLAttributes<HTMLSpanElement>;
|
|
363
|
+
|
|
364
|
+
export const CommitFilePath = ({
|
|
365
|
+
className,
|
|
366
|
+
children,
|
|
367
|
+
...props
|
|
368
|
+
}: CommitFilePathProps) => (
|
|
369
|
+
<span className={cn("truncate font-mono text-xs", className)} {...props}>
|
|
370
|
+
{children}
|
|
371
|
+
</span>
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
export type CommitFileChangesProps = HTMLAttributes<HTMLDivElement>;
|
|
375
|
+
|
|
376
|
+
export const CommitFileChanges = ({
|
|
377
|
+
className,
|
|
378
|
+
children,
|
|
379
|
+
...props
|
|
380
|
+
}: CommitFileChangesProps) => (
|
|
381
|
+
<div
|
|
382
|
+
className={cn(
|
|
383
|
+
"flex shrink-0 items-center gap-1 font-mono text-xs",
|
|
384
|
+
className
|
|
385
|
+
)}
|
|
386
|
+
{...props}
|
|
387
|
+
>
|
|
388
|
+
{children}
|
|
389
|
+
</div>
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
export type CommitFileAdditionsProps = HTMLAttributes<HTMLSpanElement> & {
|
|
393
|
+
count: number;
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
export const CommitFileAdditions = ({
|
|
397
|
+
count,
|
|
398
|
+
className,
|
|
399
|
+
children,
|
|
400
|
+
...props
|
|
401
|
+
}: CommitFileAdditionsProps) => {
|
|
402
|
+
if (count <= 0) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
return (
|
|
407
|
+
<span
|
|
408
|
+
className={cn("text-green-600 dark:text-green-400", className)}
|
|
409
|
+
{...props}
|
|
410
|
+
>
|
|
411
|
+
{children ?? (
|
|
412
|
+
<>
|
|
413
|
+
<PlusIcon className="inline-block size-3" />
|
|
414
|
+
{count}
|
|
415
|
+
</>
|
|
416
|
+
)}
|
|
417
|
+
</span>
|
|
418
|
+
);
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
export type CommitFileDeletionsProps = HTMLAttributes<HTMLSpanElement> & {
|
|
422
|
+
count: number;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
export const CommitFileDeletions = ({
|
|
426
|
+
count,
|
|
427
|
+
className,
|
|
428
|
+
children,
|
|
429
|
+
...props
|
|
430
|
+
}: CommitFileDeletionsProps) => {
|
|
431
|
+
if (count <= 0) {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return (
|
|
436
|
+
<span
|
|
437
|
+
className={cn("text-red-600 dark:text-red-400", className)}
|
|
438
|
+
{...props}
|
|
439
|
+
>
|
|
440
|
+
{children ?? (
|
|
441
|
+
<>
|
|
442
|
+
<MinusIcon className="inline-block size-3" />
|
|
443
|
+
{count}
|
|
444
|
+
</>
|
|
445
|
+
)}
|
|
446
|
+
</span>
|
|
447
|
+
);
|
|
448
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Alert, AlertDescription } from "@/components/ui/alert";
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import { cn } from "@/lib/utils";
|
|
6
|
+
import type { ToolUIPart } from "ai";
|
|
7
|
+
import {
|
|
8
|
+
type ComponentProps,
|
|
9
|
+
createContext,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
useContext,
|
|
12
|
+
} from "react";
|
|
13
|
+
|
|
14
|
+
type ToolUIPartApproval =
|
|
15
|
+
| {
|
|
16
|
+
id: string;
|
|
17
|
+
approved?: never;
|
|
18
|
+
reason?: never;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
id: string;
|
|
22
|
+
approved: boolean;
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
25
|
+
| {
|
|
26
|
+
id: string;
|
|
27
|
+
approved: true;
|
|
28
|
+
reason?: string;
|
|
29
|
+
}
|
|
30
|
+
| {
|
|
31
|
+
id: string;
|
|
32
|
+
approved: true;
|
|
33
|
+
reason?: string;
|
|
34
|
+
}
|
|
35
|
+
| {
|
|
36
|
+
id: string;
|
|
37
|
+
approved: false;
|
|
38
|
+
reason?: string;
|
|
39
|
+
}
|
|
40
|
+
| undefined;
|
|
41
|
+
|
|
42
|
+
interface ConfirmationContextValue {
|
|
43
|
+
approval: ToolUIPartApproval;
|
|
44
|
+
state: ToolUIPart["state"];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const ConfirmationContext = createContext<ConfirmationContextValue | null>(
|
|
48
|
+
null
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const useConfirmation = () => {
|
|
52
|
+
const context = useContext(ConfirmationContext);
|
|
53
|
+
|
|
54
|
+
if (!context) {
|
|
55
|
+
throw new Error("Confirmation components must be used within Confirmation");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return context;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type ConfirmationProps = ComponentProps<typeof Alert> & {
|
|
62
|
+
approval?: ToolUIPartApproval;
|
|
63
|
+
state: ToolUIPart["state"];
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const Confirmation = ({
|
|
67
|
+
className,
|
|
68
|
+
approval,
|
|
69
|
+
state,
|
|
70
|
+
...props
|
|
71
|
+
}: ConfirmationProps) => {
|
|
72
|
+
if (!approval || state === "input-streaming" || state === "input-available") {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<ConfirmationContext.Provider value={{ approval, state }}>
|
|
78
|
+
<Alert className={cn("flex flex-col gap-2", className)} {...props} />
|
|
79
|
+
</ConfirmationContext.Provider>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type ConfirmationTitleProps = ComponentProps<typeof AlertDescription>;
|
|
84
|
+
|
|
85
|
+
export const ConfirmationTitle = ({
|
|
86
|
+
className,
|
|
87
|
+
...props
|
|
88
|
+
}: ConfirmationTitleProps) => (
|
|
89
|
+
<AlertDescription className={cn("inline", className)} {...props} />
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
export interface ConfirmationRequestProps {
|
|
93
|
+
children?: ReactNode;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => {
|
|
97
|
+
const { state } = useConfirmation();
|
|
98
|
+
|
|
99
|
+
// Only show when approval is requested
|
|
100
|
+
if (state !== "approval-requested") {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return children;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export interface ConfirmationAcceptedProps {
|
|
108
|
+
children?: ReactNode;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const ConfirmationAccepted = ({
|
|
112
|
+
children,
|
|
113
|
+
}: ConfirmationAcceptedProps) => {
|
|
114
|
+
const { approval, state } = useConfirmation();
|
|
115
|
+
|
|
116
|
+
// Only show when approved and in response states
|
|
117
|
+
if (
|
|
118
|
+
!approval?.approved ||
|
|
119
|
+
(state !== "approval-responded" &&
|
|
120
|
+
state !== "output-denied" &&
|
|
121
|
+
state !== "output-available")
|
|
122
|
+
) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return children;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export interface ConfirmationRejectedProps {
|
|
130
|
+
children?: ReactNode;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export const ConfirmationRejected = ({
|
|
134
|
+
children,
|
|
135
|
+
}: ConfirmationRejectedProps) => {
|
|
136
|
+
const { approval, state } = useConfirmation();
|
|
137
|
+
|
|
138
|
+
// Only show when rejected and in response states
|
|
139
|
+
if (
|
|
140
|
+
approval?.approved !== false ||
|
|
141
|
+
(state !== "approval-responded" &&
|
|
142
|
+
state !== "output-denied" &&
|
|
143
|
+
state !== "output-available")
|
|
144
|
+
) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return children;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export type ConfirmationActionsProps = ComponentProps<"div">;
|
|
152
|
+
|
|
153
|
+
export const ConfirmationActions = ({
|
|
154
|
+
className,
|
|
155
|
+
...props
|
|
156
|
+
}: ConfirmationActionsProps) => {
|
|
157
|
+
const { state } = useConfirmation();
|
|
158
|
+
|
|
159
|
+
// Only show when approval is requested
|
|
160
|
+
if (state !== "approval-requested") {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<div
|
|
166
|
+
className={cn("flex items-center justify-end gap-2 self-end", className)}
|
|
167
|
+
{...props}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
export type ConfirmationActionProps = ComponentProps<typeof Button>;
|
|
173
|
+
|
|
174
|
+
export const ConfirmationAction = (props: ConfirmationActionProps) => (
|
|
175
|
+
<Button className="h-8 px-3 text-sm" type="button" {...props} />
|
|
176
|
+
);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ConnectionLineComponent } from "@xyflow/react";
|
|
2
|
+
|
|
3
|
+
const HALF = 0.5;
|
|
4
|
+
|
|
5
|
+
export const Connection: ConnectionLineComponent = ({
|
|
6
|
+
fromX,
|
|
7
|
+
fromY,
|
|
8
|
+
toX,
|
|
9
|
+
toY,
|
|
10
|
+
}) => (
|
|
11
|
+
<g>
|
|
12
|
+
<path
|
|
13
|
+
className="animated"
|
|
14
|
+
d={`M${fromX},${fromY} C ${fromX + (toX - fromX) * HALF},${fromY} ${fromX + (toX - fromX) * HALF},${toY} ${toX},${toY}`}
|
|
15
|
+
fill="none"
|
|
16
|
+
stroke="var(--color-ring)"
|
|
17
|
+
strokeWidth={1}
|
|
18
|
+
/>
|
|
19
|
+
<circle
|
|
20
|
+
cx={toX}
|
|
21
|
+
cy={toY}
|
|
22
|
+
fill="#fff"
|
|
23
|
+
r={3}
|
|
24
|
+
stroke="var(--color-ring)"
|
|
25
|
+
strokeWidth={1}
|
|
26
|
+
/>
|
|
27
|
+
</g>
|
|
28
|
+
);
|