/** * @oxpulse/chat-widget — AttachmentPicker (staged attachment tray slice 3). * * Renders a hidden file input + staging tray (horizontal thumbnail strip in * slice 4). Stages files on pick/paste/drop, eagerly uploads each in the * background, and exposes the staged list to Composer for send-time batching. * * Uses theme tokens exclusively — no inline hex. * Dispatches `oxpulse-chat:error` events on validation/upload failures. */ import { type EnvelopeAttachment } from '../utils/attachment-envelope.js'; /** Minimal SDK surface required by AttachmentPicker. */ export interface AttachmentPickerClient { uploadAttachment(roomId: string, blob: Blob, args: { mimeType?: string; filename?: string; width?: number; height?: number; signal?: AbortSignal; }): Promise<{ attachmentId: string; attachment: EnvelopeAttachment; }>; } export interface AttachmentPickerOptions { client: AttachmentPickerClient; roomId: string; container: HTMLElement; signal?: AbortSignal; /** BCP-47 tag or an already-resolved Locale. Optional — defaults via resolveLocale(). */ lang?: string; /** Optional callback fired whenever the staged list changes. */ onChange?: () => void; } /** Per-file staged attachment state. */ export interface StagedAttachment { /** F5: stable UUID assigned at enqueue time. */ id: string; file: File; /** Object URL for a local thumbnail preview; revoked on remove/clear/destroy. */ objectURL: string; status: 'uploading' | 'done' | 'error'; progress: number; error?: string; /** Populated once uploadAttachment resolves. */ attachmentId?: string; mime: string; sizeBytes: number; width?: number; height?: number; abortController: AbortController; /** Resolves when this item's upload completes (status='done'). Rejects * with the upload error if status='error'. Set by #enqueue() — present * on every item returned by getStaged() / detachAndAwaitUploads(). */ donePromise?: Promise; } export declare class AttachmentPicker { #private; constructor(opts: AttachmentPickerOptions); mount(): void; destroy(): void; openFileDialog(): void; /** Returns a snapshot of the current staged attachment list. */ getStaged(): StagedAttachment[]; /** Whether there is at least one staged attachment. */ hasStaged(): boolean; /** * Review fix (HIGH, PR #88): disable/enable every cancel + retry button * while Composer#send is in flight. Purely a UI-level defense — Composer * itself re-checks the staged list after awaitAllUploaded() resolves, since * this alone doesn't cover every way the list could still empty out. */ setSendLocked(locked: boolean): void; /** Revoke every objectURL and clear the staged list. */ clearStaged(): void; /** * Resolves once every staged item is done. Rejects immediately if any item is * in the 'error' state, or if a later upload fails while this is pending. * Pending awaiters are cleared when the staged list is cleared/destroyed. */ awaitAllUploaded(): Promise; /** * Detach the currently-staged items from the tray and return a promise that * resolves when all their uploads complete. The tray UI is cleared immediately * (items removed from #items + re-rendered) but the uploads continue in the * background — each item's donePromise is independent of the #items array. * * Used by the non-blocking attachment send path: the composer calls this to * "hand off" the staged items, clears the textarea, and returns control to * the user while the uploads + send proceed in the background. * * Rejects if any upload fails (the rejection carries the failed file's name). */ detachAndAwaitUploads(): Promise; /** Validate files and stage them for upload (append to existing staged list). */ handleFiles(files: FileList | File[]): void; } //# sourceMappingURL=attachment-picker.d.ts.map