import { History, ImagePlus, Loader2, Sparkles, Trash2, X, } from 'lucide-react'; import { type ReactNode, useEffect, useState } from 'react'; import { ResolvedAssetImage } from '../ResolvedAssetImage'; export type CreativeImageInputReferenceImage = { id: string; label: string; imageSrc: string; }; export type CreativeImageInputPanelLabels = { imageField: string; uploadImage: string; replaceImage: string; emptyImageHint: string; removeImage: string; removeImageConfirmTitle: string; removeImageConfirmBody: string; promptReferenceUpload: string; promptReferencePreviewAlt: string; closePromptReferencePreview: string; history?: string; }; export type CreativeImageInputPanelProps = { className?: string; disabled?: boolean; isSubmitting?: boolean; mainImageMode?: 'edit' | 'preview'; canRemoveMainImage?: boolean; canToggleAiRedraw?: boolean; uploadedImageSrc: string; uploadedImageAlt: string; uploadedImageRefreshKey?: string | number | null; mainImageMeta?: ReactNode; mainImageInputId: string; mainImageAccept?: string; promptTextareaId: string; prompt: string; promptLabel: string; promptAriaLabel?: string; promptRows?: number; aiRedraw: boolean; promptReferenceImages: CreativeImageInputReferenceImage[]; promptReferenceLimit?: number; imageModelPicker?: ReactNode; error?: string | null; inputError?: string | null; submitLabel: string; submitCostLabel?: string | null; submitDisabled: boolean; labels: CreativeImageInputPanelLabels; onMainImageFileSelect: (file: File) => void; onMainImageRemove: () => void; onAiRedrawChange: (enabled: boolean) => void; onPromptChange: (value: string) => void; onPromptReferenceFilesSelect?: (files: File[]) => void; onPromptReferenceRemove?: (referenceId: string) => void; onHistoryClick?: () => void; onSubmit: () => void; }; const DEFAULT_IMAGE_ACCEPT = 'image/png,image/jpeg,image/webp'; const DEFAULT_PROMPT_REFERENCE_LIMIT = 5; export function CreativeImageInputPanel({ className = '', disabled = false, isSubmitting = false, mainImageMode = 'edit', canRemoveMainImage = true, canToggleAiRedraw = true, uploadedImageSrc, uploadedImageAlt, uploadedImageRefreshKey = null, mainImageMeta = null, mainImageInputId, mainImageAccept = DEFAULT_IMAGE_ACCEPT, promptTextareaId, prompt, promptLabel, promptAriaLabel, promptRows = 2, aiRedraw, promptReferenceImages, promptReferenceLimit = DEFAULT_PROMPT_REFERENCE_LIMIT, imageModelPicker = null, error = null, inputError = null, submitLabel, submitCostLabel = null, submitDisabled, labels, onMainImageFileSelect, onMainImageRemove, onAiRedrawChange, onPromptChange, onPromptReferenceFilesSelect, onPromptReferenceRemove, onHistoryClick, onSubmit, }: CreativeImageInputPanelProps) { const [previewReferenceImage, setPreviewReferenceImage] = useState(null); const [isRemoveImageConfirmOpen, setIsRemoveImageConfirmOpen] = useState(false); const showPrompt = mainImageMode === 'preview' || !uploadedImageSrc || aiRedraw; const promptReferenceUploadDisabled = disabled || promptReferenceImages.length >= promptReferenceLimit; const canEditMainImage = mainImageMode === 'edit'; useEffect(() => { if (uploadedImageSrc) { setPreviewReferenceImage(null); } }, [uploadedImageSrc]); useEffect(() => { if ( previewReferenceImage && !promptReferenceImages.some( (reference) => reference.id === previewReferenceImage.id, ) ) { setPreviewReferenceImage(null); } }, [previewReferenceImage, promptReferenceImages]); return (
{labels.imageField}
{canEditMainImage ? ( <> { const file = event.currentTarget.files?.[0] ?? null; event.currentTarget.value = ''; if (file) { onMainImageFileSelect(file); } }} className="sr-only" /> ) : null} {uploadedImageSrc ? ( ) : ( )}
{canEditMainImage && onHistoryClick ? ( ) : null} {canEditMainImage && uploadedImageSrc && canToggleAiRedraw ? ( ) : null} {canEditMainImage && uploadedImageSrc && canRemoveMainImage ? ( ) : canEditMainImage && !uploadedImageSrc ? ( ) : null}
{mainImageMeta ?
{mainImageMeta}
: null}
{showPrompt ? (