/** Chip strip / chip density. `compact` shrinks the thumbnail, padding, text * and max-width for narrow surfaces (e.g. the ticket-drawer reply composer); * `default` is the global Ask-AI chat sizing. */ export type ChatAttachmentSize = 'default' | 'compact'; /** 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; /** Density. `compact` renders a smaller 24×24 button for narrow surfaces * (ticket-drawer composer); `default` is the 28×28 global-chat button. */ size?: ChatAttachmentSize; } /** * 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 `` 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, size, }: ChatAttachmentAddButtonProps): import("react").JSX.Element; export interface ChatAttachmentChipStripProps { attachments: StagedAttachment[]; onRemove: (id: string) => void; /** External disable (e.g. while chat is streaming). */ disabled?: boolean; /** Density. `compact` (smaller thumbnail/padding/text, narrower chips) suits * narrow surfaces like the ticket-drawer reply composer; `default` is the * global Ask-AI chat sizing. */ size?: ChatAttachmentSize; } /** * 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, size, }: ChatAttachmentChipStripProps): import("react").JSX.Element | null; export {}; //# sourceMappingURL=chat-attachment-bar.d.ts.map