import { forwardRef, useState, useCallback, useEffect } from 'react' import type { HTMLAttributes } from 'react' import { createPortal } from 'react-dom' import { cn } from '@/lib/utils' import type { ReactNode } from 'react' import { CloseLine, CloseLargeLine } from '../basic/icons-inline' import { IconButton } from '../basic/icon-button' const SIZE_CLASS = { sm: 'w-12 h-12', md: 'w-16 h-16', lg: 'w-20 h-20', } as const const PREVIEW_MAX = 'max-w-[90vw] max-h-[90vh] object-contain' const closeClass = 'h-2.5 w-2.5 text-text-secondary' const closeLargeClass = 'h-4 w-4 text-text-secondary' export interface ImageAttachmentProps extends Omit, 'children'> { src: string alt?: string onRemove?: (e: React.MouseEvent) => void previewable?: boolean onClick?: (e: React.MouseEvent) => void size?: keyof typeof SIZE_CLASS closeIcon?: ReactNode closeLargeIcon?: ReactNode } export const ImageAttachment = forwardRef( ( { src, alt = '', onRemove, previewable = true, onClick, size = 'sm', className, closeIcon, closeLargeIcon, ...props }, ref ) => { const [previewOpen, setPreviewOpen] = useState(false) const defaultClose = closeIcon ?? const defaultCloseLarge = closeLargeIcon ?? const showClose = typeof onRemove === 'function' const openPreview = useCallback(() => { if (previewable) setPreviewOpen(true) }, [previewable]) const closePreview = useCallback(() => setPreviewOpen(false), []) const handleThumbClick = useCallback( (e: React.MouseEvent) => { onClick?.(e) if (!e.defaultPrevented && previewable) openPreview() }, [onClick, previewable, openPreview] ) const handleRemove = useCallback( (e: React.MouseEvent) => { e.stopPropagation() onRemove?.(e) }, [onRemove] ) useEffect(() => { if (!previewOpen) return const onKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') closePreview() } window.addEventListener('keydown', onKeyDown) return () => window.removeEventListener('keydown', onKeyDown) }, [previewOpen, closePreview]) const previewPortal = previewOpen && typeof document !== 'undefined' ? createPortal(
{ if (e.target === e.currentTarget) closePreview() }} onKeyDown={(e) => e.key === 'Escape' && closePreview()} > {alt} e.stopPropagation()} draggable={false} />
, document.body ) : null return ( <>
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() openPreview() } } : undefined } {...props} > {alt} {showClose && ( )}
{previewPortal} ) } ) ImageAttachment.displayName = 'ImageAttachment'