/** Hand-curated chat-attachment allow-list. Intentionally excludes
 *  `image/svg+xml` for XSS safety. */
export declare const CHAT_ATTACHMENT_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/webp", "image/gif", "video/mp4", "video/webm", "video/quicktime"];
/** Client-side cap on `addFiles` (the upload hook rejects 6+ files in a
 *  single selection). Server-side is per-IP-rate-limit; this is a UX
 *  hint more than a security boundary. */
export declare const CHAT_ATTACHMENT_CONCURRENT_UPLOADS_PER_USER = 5;
type Status = 'sniffing' | 'uploading' | 'ready' | 'error';
/** Staged-attachment shape consumed by the chip strip. Mirrors the hub
 *  `StagedAttachment` produced by `useChatAttachments`. */
export interface StagedAttachment {
    /** Stable client-side id; survives across re-renders. */
    id: string;
    file: File;
    status: Status;
    /** Set when `status === 'ready'`. Server-issued. */
    storagePath?: string;
    /** Set when `status === 'ready'`. Server-issued HMAC view token. */
    viewToken?: string;
    /** 0-100 during 'uploading'. */
    progress: number;
    /** Set when `status === 'error'`. */
    errorMessage?: string;
}
export interface ChatAttachmentAddButtonProps {
    /** Auth-gate flag. Hub passes `useChatIdentity().attachmentsEnabled`;
     *  embedders supply their own boolean. Disabled state collapses the
     *  button to a layout-reserving invisible placeholder. */
    attachmentsEnabled: boolean;
    /** Current attachment count — drives the limit-reached disabled state. */
    attachmentsCount: number;
    onAddFiles: (files: FileList | File[]) => void;
    /** External disable (e.g. while chat is streaming). */
    disabled?: boolean;
}
/**
 * Settled `+` icon-only button for the bottom-controls row.
 *
 * LAYOUT STABILITY — first-paint placeholder pattern:
 *   `attachmentsEnabled` typically resolves ASYNCHRONOUSLY on mount
 *   (hub's `useChatIdentity()` round-trip ~100-500ms). When the flag is
 *   false (loading OR anon final state), the component renders an
 *   INVISIBLE placeholder `<span>` with the same `h-7 w-7 shrink-0`
 *   footprint as the real button. The placeholder reserves layout space
 *   from the very first paint; if `attachmentsEnabled` flips to `true`
 *   the button replaces the placeholder at the IDENTICAL 28×28
 *   position — ZERO shift.
 *
 *   Truly-anon users see the invisible 28×28 spacer permanently —
 *   acceptable trade-off vs the universal jump on every panel open.
 */
export declare function ChatAttachmentAddButton({ attachmentsEnabled, attachmentsCount, onAddFiles, disabled, }: ChatAttachmentAddButtonProps): import("react/jsx-runtime").JSX.Element;
export interface ChatAttachmentChipStripProps {
    attachments: StagedAttachment[];
    onRemove: (id: string) => void;
    /** External disable (e.g. while chat is streaming). */
    disabled?: boolean;
}
/**
 * Horizontal strip of file chips that appears ABOVE the input when one
 * or more attachments are staged. Returns `null` when empty — no
 * permanent UI footprint.
 */
export declare function ChatAttachmentChipStrip({ attachments, onRemove, disabled, }: ChatAttachmentChipStripProps): import("react/jsx-runtime").JSX.Element | null;
export {};
//# sourceMappingURL=chat-attachment-bar.d.ts.map