@@ -12,13 +12,12 @@ import {
1212 TooltipTrigger ,
1313} from "@/components/ui/tooltip" ;
1414import { 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" ;
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" ;
2221import type { ComponentProps , HTMLAttributes , ReactElement } from "react" ;
2322import { createContext , memo , useContext , useEffect , useState } from "react" ;
2423import { Streamdown } from "streamdown" ;
@@ -30,7 +29,7 @@ export type MessageProps = HTMLAttributes<HTMLDivElement> & {
3029export const Message = ( { className, from, ...props } : MessageProps ) => (
3130 < div
3231 className = { cn (
33- "group flex flex-col w-full max-w-[80%] gap-2" ,
32+ "group flex w-full max-w-[95%] flex-col gap-2" ,
3433 from === "user" ? "is-user ml-auto justify-end" : "is-assistant" ,
3534 className
3635 ) }
@@ -47,7 +46,7 @@ export const MessageContent = ({
4746} : MessageContentProps ) => (
4847 < div
4948 className = { cn (
50- "is-user:dark flex w-fit flex-col gap-2 overflow-hidden text-sm" ,
49+ "is-user:dark flex w-fit min-w-0 max-w-full flex-col gap-2 overflow-hidden text-sm" ,
5150 "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" ,
5251 "group-[.is-assistant]:text-foreground" ,
5352 className
@@ -106,14 +105,14 @@ export const MessageAction = ({
106105 return button ;
107106} ;
108107
109- type MessageBranchContextType = {
108+ interface MessageBranchContextType {
110109 currentBranch : number ;
111110 totalBranches : number ;
112111 goToPrevious : ( ) => void ;
113112 goToNext : ( ) => void ;
114113 branches : ReactElement [ ] ;
115114 setBranches : ( branches : ReactElement [ ] ) => void ;
116- } ;
115+ }
117116
118117const MessageBranchContext = createContext < MessageBranchContextType | null > (
119118 null
@@ -263,7 +262,6 @@ export type MessageBranchNextProps = ComponentProps<typeof Button>;
263262
264263export const MessageBranchNext = ( {
265264 children,
266- className,
267265 ...props
268266} : MessageBranchNextProps ) => {
269267 const { goToNext, totalBranches } = useMessageBranch ( ) ;
@@ -313,6 +311,7 @@ export const MessageResponse = memo(
313311 "size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0" ,
314312 className
315313 ) }
314+ plugins = { { code, mermaid, math, cjk } }
316315 { ...props }
317316 />
318317 ) ,
@@ -321,114 +320,6 @@ export const MessageResponse = memo(
321320
322321MessageResponse . displayName = "MessageResponse" ;
323322
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- }
431-
432323export type MessageToolbarProps = ComponentProps < "div" > ;
433324
434325export const MessageToolbar = ( {
0 commit comments