Skip to content

Commit a17cbb5

Browse files
committed
Bumps node modules
1 parent 97909d0 commit a17cbb5

9 files changed

Lines changed: 674 additions & 319 deletions

File tree

agents/agent-langchain-nextjs/components/ai-elements/message.tsx

Lines changed: 153 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,38 @@
1-
"use client";
1+
'use client';
22

3-
import { Button } from "@/components/ui/button";
3+
import { Button } from '@/components/ui/button';
44
import {
55
ButtonGroup,
66
ButtonGroupText,
7-
} from "@/components/ui/button-group";
7+
} from '@/components/ui/button-group';
88
import {
99
Tooltip,
1010
TooltipContent,
1111
TooltipProvider,
1212
TooltipTrigger,
13-
} from "@/components/ui/tooltip";
14-
import { cn } from "@/lib/utils";
15-
import { cjk } from "@streamdown/cjk";
16-
import { code } from "@streamdown/code";
17-
import { math } from "@streamdown/math";
18-
import { mermaid } from "@streamdown/mermaid";
19-
import type { UIMessage } from "ai";
20-
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
21-
import type { ComponentProps, HTMLAttributes, ReactElement } from "react";
22-
import { createContext, memo, useContext, useEffect, useState } from "react";
23-
import { Streamdown } from "streamdown";
13+
} from '@/components/ui/tooltip';
14+
import { cn } from '@/lib/utils';
15+
import type { FileUIPart, UIMessage } from 'ai';
16+
import {
17+
ChevronLeftIcon,
18+
ChevronRightIcon,
19+
PaperclipIcon,
20+
XIcon,
21+
} from 'lucide-react';
22+
import type { ComponentProps, HTMLAttributes, ReactElement } from 'react';
23+
import { createContext, memo, useContext, useEffect, useState } from 'react';
24+
import { Streamdown } from 'streamdown';
2425

2526
export type MessageProps = HTMLAttributes<HTMLDivElement> & {
26-
from: UIMessage["role"];
27+
from: UIMessage['role'];
2728
};
2829

2930
export const Message = ({ className, from, ...props }: MessageProps) => (
3031
<div
3132
className={cn(
32-
"group flex w-full max-w-[95%] flex-col gap-2",
33-
from === "user" ? "is-user ml-auto justify-end" : "is-assistant",
34-
className
33+
'group flex w-full max-w-[95%] flex-col gap-2',
34+
from === 'user' ? 'is-user ml-auto justify-end' : 'is-assistant',
35+
className,
3536
)}
3637
{...props}
3738
/>
@@ -46,25 +47,25 @@ export const MessageContent = ({
4647
}: MessageContentProps) => (
4748
<div
4849
className={cn(
49-
"is-user:dark flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm",
50-
"group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground",
51-
"group-[.is-assistant]:text-foreground",
52-
className
50+
'is-user:dark flex w-fit max-w-full min-w-0 flex-col gap-2 overflow-hidden text-sm',
51+
'group-[.is-user]:ml-auto group-[.is-user]:rounded-lg group-[.is-user]:bg-secondary group-[.is-user]:px-4 group-[.is-user]:py-3 group-[.is-user]:text-foreground',
52+
'group-[.is-assistant]:text-foreground',
53+
className,
5354
)}
5455
{...props}
5556
>
5657
{children}
5758
</div>
5859
);
5960

60-
export type MessageActionsProps = ComponentProps<"div">;
61+
export type MessageActionsProps = ComponentProps<'div'>;
6162

6263
export const MessageActions = ({
6364
className,
6465
children,
6566
...props
6667
}: MessageActionsProps) => (
67-
<div className={cn("flex items-center gap-1", className)} {...props}>
68+
<div className={cn('flex items-center gap-1', className)} {...props}>
6869
{children}
6970
</div>
7071
);
@@ -78,8 +79,8 @@ export const MessageAction = ({
7879
tooltip,
7980
children,
8081
label,
81-
variant = "ghost",
82-
size = "icon-sm",
82+
variant = 'ghost',
83+
size = 'icon-sm',
8384
...props
8485
}: MessageActionProps) => {
8586
const button = (
@@ -115,15 +116,15 @@ interface MessageBranchContextType {
115116
}
116117

117118
const MessageBranchContext = createContext<MessageBranchContextType | null>(
118-
null
119+
null,
119120
);
120121

121122
const useMessageBranch = () => {
122123
const context = useContext(MessageBranchContext);
123124

124125
if (!context) {
125126
throw new Error(
126-
"MessageBranch components must be used within MessageBranch"
127+
'MessageBranch components must be used within MessageBranch',
127128
);
128129
}
129130

@@ -173,7 +174,7 @@ export const MessageBranch = ({
173174
return (
174175
<MessageBranchContext.Provider value={contextValue}>
175176
<div
176-
className={cn("grid w-full gap-2 [&>div]:pb-0", className)}
177+
className={cn('grid w-full gap-2 [&>div]:pb-0', className)}
177178
{...props}
178179
/>
179180
</MessageBranchContext.Provider>
@@ -199,8 +200,8 @@ export const MessageBranchContent = ({
199200
return childrenArray.map((branch, index) => (
200201
<div
201202
className={cn(
202-
"grid gap-2 overflow-hidden [&>div]:pb-0",
203-
index === currentBranch ? "block" : "hidden"
203+
'grid gap-2 overflow-hidden [&>div]:pb-0',
204+
index === currentBranch ? 'block' : 'hidden',
204205
)}
205206
key={branch.key}
206207
{...props}
@@ -211,10 +212,12 @@ export const MessageBranchContent = ({
211212
};
212213

213214
export type MessageBranchSelectorProps = HTMLAttributes<HTMLDivElement> & {
214-
from: UIMessage["role"];
215+
from: UIMessage['role'];
215216
};
216217

217218
export const MessageBranchSelector = ({
219+
className,
220+
from,
218221
...props
219222
}: MessageBranchSelectorProps) => {
220223
const { totalBranches } = useMessageBranch();
@@ -260,6 +263,7 @@ export type MessageBranchNextProps = ComponentProps<typeof Button>;
260263

261264
export const MessageBranchNext = ({
262265
children,
266+
className,
263267
...props
264268
}: MessageBranchNextProps) => {
265269
const { goToNext, totalBranches } = useMessageBranch();
@@ -290,8 +294,8 @@ export const MessageBranchPage = ({
290294
return (
291295
<ButtonGroupText
292296
className={cn(
293-
"border-none bg-transparent text-muted-foreground shadow-none",
294-
className
297+
'border-none bg-transparent text-muted-foreground shadow-none',
298+
className,
295299
)}
296300
{...props}
297301
>
@@ -306,19 +310,126 @@ export const MessageResponse = memo(
306310
({ className, ...props }: MessageResponseProps) => (
307311
<Streamdown
308312
className={cn(
309-
"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
310-
className
313+
'size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0',
314+
className,
311315
)}
312-
plugins={{ code, mermaid, math, cjk }}
313316
{...props}
314317
/>
315318
),
316-
(prevProps, nextProps) => prevProps.children === nextProps.children
319+
(prevProps, nextProps) => prevProps.children === nextProps.children,
317320
);
318321

319-
MessageResponse.displayName = "MessageResponse";
322+
MessageResponse.displayName = 'MessageResponse';
323+
324+
export type MessageAttachmentProps = HTMLAttributes<HTMLDivElement> & {
325+
data: FileUIPart;
326+
className?: string;
327+
onRemove?: () => void;
328+
};
329+
330+
export function MessageAttachment({
331+
data,
332+
className,
333+
onRemove,
334+
...props
335+
}: MessageAttachmentProps) {
336+
const filename = data.filename || '';
337+
const mediaType =
338+
data.mediaType?.startsWith('image/') && data.url ? 'image' : 'file';
339+
const isImage = mediaType === 'image';
340+
const attachmentLabel = filename || (isImage ? 'Image' : 'Attachment');
341+
342+
return (
343+
<div
344+
className={cn(
345+
'group relative size-24 overflow-hidden rounded-lg',
346+
className,
347+
)}
348+
{...props}
349+
>
350+
{isImage ? (
351+
<>
352+
<img
353+
alt={filename || 'attachment'}
354+
className="size-full object-cover"
355+
height={100}
356+
src={data.url}
357+
width={100}
358+
/>
359+
{onRemove && (
360+
<Button
361+
aria-label="Remove attachment"
362+
className="absolute top-2 right-2 size-6 rounded-full bg-background/80 p-0 opacity-0 backdrop-blur-sm transition-opacity hover:bg-background group-hover:opacity-100 [&>svg]:size-3"
363+
onClick={(e) => {
364+
e.stopPropagation();
365+
onRemove();
366+
}}
367+
type="button"
368+
variant="ghost"
369+
>
370+
<XIcon />
371+
<span className="sr-only">Remove</span>
372+
</Button>
373+
)}
374+
</>
375+
) : (
376+
<>
377+
<Tooltip>
378+
<TooltipTrigger asChild>
379+
<div className="flex size-full shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
380+
<PaperclipIcon className="size-4" />
381+
</div>
382+
</TooltipTrigger>
383+
<TooltipContent>
384+
<p>{attachmentLabel}</p>
385+
</TooltipContent>
386+
</Tooltip>
387+
{onRemove && (
388+
<Button
389+
aria-label="Remove attachment"
390+
className="size-6 shrink-0 rounded-full p-0 opacity-0 transition-opacity hover:bg-accent group-hover:opacity-100 [&>svg]:size-3"
391+
onClick={(e) => {
392+
e.stopPropagation();
393+
onRemove();
394+
}}
395+
type="button"
396+
variant="ghost"
397+
>
398+
<XIcon />
399+
<span className="sr-only">Remove</span>
400+
</Button>
401+
)}
402+
</>
403+
)}
404+
</div>
405+
);
406+
}
407+
408+
export type MessageAttachmentsProps = ComponentProps<'div'>;
409+
410+
export function MessageAttachments({
411+
children,
412+
className,
413+
...props
414+
}: MessageAttachmentsProps) {
415+
if (!children) {
416+
return null;
417+
}
418+
419+
return (
420+
<div
421+
className={cn(
422+
'ml-auto flex w-fit flex-wrap items-start gap-2',
423+
className,
424+
)}
425+
{...props}
426+
>
427+
{children}
428+
</div>
429+
);
430+
}
320431

321-
export type MessageToolbarProps = ComponentProps<"div">;
432+
export type MessageToolbarProps = ComponentProps<'div'>;
322433

323434
export const MessageToolbar = ({
324435
className,
@@ -327,8 +438,8 @@ export const MessageToolbar = ({
327438
}: MessageToolbarProps) => (
328439
<div
329440
className={cn(
330-
"mt-4 flex w-full items-center justify-between gap-4",
331-
className
441+
'mt-4 flex w-full items-center justify-between gap-4',
442+
className,
332443
)}
333444
{...props}
334445
>

0 commit comments

Comments
 (0)