export interface AttachmentItem { id: string; file?: File; status: 'uploading' | 'ready' | 'error'; url?: string; /** * URL de la miniatura, presente solo si se pidió `generateThumbnail` y el * archivo es una imagen. Es la que deben usar las LISTAS: `url` apunta al * archivo de hasta 1920px, y pedirlo para pintar un recuadro de 84px es la * diferencia entre 240KB y 15KB por fila. Ver `generateThumbnail`. */ thumbnailUrl?: string; error?: string; isExternal?: boolean; } export interface AttachmentUploaderMetadata { /** Título del campo (se renderiza arriba, estilo label de val-form). */ title?: string; /** Texto de ayuda (se renderiza bajo las acciones, alineado al inicio). */ hint?: string; maxFiles?: number; accept?: string; disabled?: boolean; /** Compress images before upload (default: true). PDFs are never compressed. */ compressImages?: boolean; /** * Genera y sube además una miniatura cuadrada por cada imagen, y la expone en * `AttachmentItem.thumbnailUrl` (default: false). * * Por qué es opt-in y no el default: sube DOS archivos por imagen en vez de * uno, y no todo consumer quiere pagar ese costo (ni tener el archivo extra * en su bucket). Actívalo cuando las fotos se muestren en una lista o grilla, * que es donde el ahorro es real. * * La miniatura se genera a partir del archivo YA comprimido, no del original: * `compressorjs` normaliza la orientación EXIF al comprimir, así que a esa * altura la imagen ya está derecha. Generarla del original la sacaría rotada * en las fotos verticales de teléfono (ImageService usa canvas y no lee EXIF). */ generateThumbnail?: boolean; /** Lado de la miniatura en píxeles (default: 320). Cuadrada, recorte centrado. */ thumbnailSize?: number; /** * Función de subida de la miniatura. Si se omite, se usa `uploadFn` con un * File renombrado a `-thumb.jpg` — así el consumer que deriva la ruta * del nombre del archivo no necesita hacer nada. */ thumbnailUploadFn?: (file: File) => Promise; /** Upload function. If omitted, falls back to FeedbackService.uploadAttachment. */ uploadFn?: (file: File) => Promise; /** URLs de items ya subidos — se pre-seedean como items 'ready' al montar. */ existingUrls?: string[]; /** * Lazy mode: los archivos seleccionados se bufferean (status 'ready', file conservado) * sin subir. El consumer recibe AttachmentItem[] con file set y sube manualmente. * Útil cuando el destino (ej. animal ID) no existe aún al momento de seleccionar. */ lazy?: boolean; }