'use client'; import { PropsWithChildren, useEffect, useState, type FC } from 'react'; import { XIcon, PlusIcon, FileText } from 'lucide-react'; import { AttachmentPrimitive, ComposerPrimitive, MessagePrimitive, useAuiState, useAui } from '@assistant-ui/react'; import { useShallow } from 'zustand/shallow'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; import { Dialog, DialogTitle, DialogContent, DialogTrigger } from '@/components/ui/dialog'; import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'; import { TooltipIconButton } from '@/components/assistant-ui/tooltip-icon-button'; import { cn } from '@/lib/utils'; const useFileSrc = (file: File | undefined) => { const [src, setSrc] = useState(undefined); useEffect(() => { if (!file) { setSrc(undefined); return; } const objectUrl = URL.createObjectURL(file); setSrc(objectUrl); return () => { URL.revokeObjectURL(objectUrl); }; }, [file]); return src; }; const useAttachmentSrc = () => { const { file, src } = useAuiState( useShallow(({ attachment }): { file?: File; src?: string } => { if (attachment.type !== 'image') return {}; if (attachment.file) return { file: attachment.file }; const src = attachment.content?.filter((c) => c.type === 'image')[0]?.image; if (!src) return {}; return { src }; }), ); return useFileSrc(file) ?? src; }; type AttachmentPreviewProps = { src: string; }; const AttachmentPreview: FC = ({ src }) => { const [isLoaded, setIsLoaded] = useState(false); return ( Image Preview setIsLoaded(true)} /> ); }; const AttachmentPreviewDialog: FC = ({ children }) => { const src = useAttachmentSrc(); if (!src) return children; return ( {children} Image Attachment Preview
); }; const AttachmentThumb: FC = () => { const isImage = useAuiState(({ attachment }) => attachment.type === 'image'); const src = useAttachmentSrc(); return ( ); }; const AttachmentUI: FC = () => { const api = useAui(); const isComposer = api.attachment.source === 'composer'; const isImage = useAuiState(({ attachment }) => attachment.type === 'image'); const typeLabel = useAuiState(({ attachment }) => { const type = attachment.type; switch (type) { case 'image': return 'Image'; case 'document': return 'Document'; case 'file': return 'File'; default: return 'File'; } }); return ( #attachment-tile]:size-24')} >
{isComposer && }
); }; const AttachmentRemove: FC = () => { return ( ); }; export const UserMessageAttachments: FC = () => { return (
); }; export const ComposerAttachments: FC = () => { return (
); }; export const ComposerAddAttachment: FC = () => { return ( ); };