@gntik-ai/chat 0.0.0-stage → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,829 @@
1
+
2
+ import { ComponentDoc } from "@gntik-ai/ui";
3
+ import { ComponentType, ReactNode, Ref } from "react";
4
+ //#region src/Attachment/AttachmentChip.d.ts
5
+ /** A file attached to a message or waiting in the composer. */
6
+ interface ChatAttachment {
7
+ id: string;
8
+ name: string;
9
+ /** Size in bytes. */
10
+ size?: number;
11
+ /** MIME type; picks the icon (falls back to the extension). */
12
+ type?: string;
13
+ /** Image preview URL (e.g. from URL.createObjectURL); shown as a thumbnail for images. */
14
+ previewUrl?: string;
15
+ /** Upload progress 0–100 (`null` = indeterminate). Omit when not uploading. */
16
+ progress?: number | null;
17
+ /** Upload failed; a string replaces the default message. */
18
+ error?: boolean | string;
19
+ }
20
+ type AttachmentStatus = 'idle' | 'uploading' | 'error';
21
+ interface AttachmentChipProps {
22
+ attachment: ChatAttachment;
23
+ /** `chip` (composer, compact row) or `tile` (message, larger image preview). */
24
+ variant?: 'chip' | 'tile';
25
+ /** Shows the remove button. */
26
+ onRemove?: (id: string) => void;
27
+ /** Shows a retry button in the error state. */
28
+ onRetry?: (id: string) => void;
29
+ disabled?: boolean;
30
+ className?: string;
31
+ ref?: Ref<HTMLDivElement>;
32
+ }
33
+ /** Status of an attachment from its progress and error fields. */
34
+ export declare function attachmentStatus(a: ChatAttachment): AttachmentStatus;
35
+ /**
36
+ * One attached file: image thumbnail or file-type icon, name, size, upload progress
37
+ * (a progressbar), error with retry, and a remove button.
38
+ */
39
+ export declare function AttachmentChip({ attachment: a, variant, onRemove, onRetry, disabled, className, ref }: AttachmentChipProps): import("react").JSX.Element;
40
+ //#endregion
41
+ //#region src/Attachment/AttachmentList.d.ts
42
+ interface AttachmentListProps {
43
+ attachments: ChatAttachment[];
44
+ /** `chip` for the composer, `tile` for larger image previews in a message. */
45
+ variant?: 'chip' | 'tile';
46
+ onRemove?: (id: string) => void;
47
+ onRetry?: (id: string) => void;
48
+ disabled?: boolean;
49
+ /** Accessible name of the list. Default "Attachments". */
50
+ label?: string;
51
+ className?: string;
52
+ ref?: Ref<HTMLUListElement>;
53
+ }
54
+ /** A labelled list of AttachmentChips. Renders nothing when empty. */
55
+ export declare function AttachmentList({ attachments, variant, onRemove, onRetry, disabled, label, className, ref }: AttachmentListProps): import("react").JSX.Element | null;
56
+ //#endregion
57
+ //#region src/Attachment/validateFiles.d.ts
58
+ type AttachmentRejectionReason = 'type' | 'size' | 'count';
59
+ interface AttachmentRejection {
60
+ file: File;
61
+ reason: AttachmentRejectionReason;
62
+ /** Human-readable message (set by ChatComposer from the i18n catalog). */
63
+ message: string;
64
+ }
65
+ interface ValidateFilesOptions {
66
+ /** Same syntax as `<input accept>`: ".pdf,.csv,image/*,application/json". */
67
+ accept?: string;
68
+ /** Largest allowed file, in bytes. */
69
+ maxSize?: number;
70
+ /** Most files allowed in total, counting `current`. */
71
+ maxFiles?: number;
72
+ /** Files already attached. */
73
+ current?: number;
74
+ }
75
+ /** Whether a file matches an `accept` list (extensions, exact MIME types and `type/*`). */
76
+ export declare function matchesAccept(file: Pick<File, 'name' | 'type'>, accept?: string): boolean;
77
+ /** Splits files into accepted ones and rejections (without messages) by type, size and count. */
78
+ export declare function validateFiles(files: File[], { accept, maxSize, maxFiles, current }: ValidateFilesOptions): {
79
+ accepted: File[];
80
+ rejected: {
81
+ file: File;
82
+ reason: AttachmentRejectionReason;
83
+ }[];
84
+ };
85
+ //#endregion
86
+ //#region src/Attachment/attachment.variants.d.ts
87
+ /** Slot classes for AttachmentChip / AttachmentList. */
88
+ export declare const attachmentStyles: {
89
+ readonly list: "flex flex-wrap gap-1.5";
90
+ readonly item: "min-w-0";
91
+ readonly chip: string;
92
+ readonly tile: string;
93
+ readonly media: "grid size-7 shrink-0 place-items-center overflow-hidden rounded bg-background text-muted-foreground";
94
+ readonly mediaError: "text-destructive-text";
95
+ readonly tileMedia: "grid aspect-square w-full place-items-center overflow-hidden bg-secondary/50 text-muted-foreground";
96
+ readonly img: "size-full object-cover";
97
+ readonly text: "flex min-w-0 flex-1 flex-col leading-4";
98
+ readonly tileText: "flex min-w-0 flex-col gap-0.5 px-2 py-1.5 leading-4";
99
+ readonly name: "truncate font-medium";
100
+ readonly meta: "truncate font-mono text-[10.5px] text-muted-foreground";
101
+ readonly metaError: "truncate text-[11px] text-destructive-chip-text";
102
+ readonly button: "grid size-6 shrink-0 place-items-center rounded text-muted-foreground hover:bg-foreground/10 hover:text-foreground disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
103
+ readonly tileActions: "absolute end-1 top-1 flex gap-0.5 rounded-md bg-card/90";
104
+ readonly track: "absolute inset-x-0 bottom-0 h-0.5 bg-border";
105
+ readonly bar: "h-full bg-primary transition-[width] duration-200 motion-reduce:transition-none";
106
+ readonly barIndeterminate: "h-full w-1/3 bg-primary animate-pulse motion-reduce:animate-none";
107
+ };
108
+ //#endregion
109
+ //#region src/Attachment/Attachment.doc.d.ts
110
+ declare const doc: ComponentDoc;
111
+ //#endregion
112
+ //#region src/ChatComposer/ChatComposer.d.ts
113
+ /** A file in the composer: name and size, plus optional type, preview, progress and error. */
114
+ type ComposerAttachment = ChatAttachment;
115
+ interface ChatComposerProps {
116
+ /** Controlled text. Pair with `onValueChange`. */
117
+ value?: string;
118
+ defaultValue?: string;
119
+ onValueChange?: (value: string) => void;
120
+ /** Called with the trimmed text when the user sends. Uncontrolled composers clear themselves. */
121
+ onSubmit: (text: string, attachments: ComposerAttachment[]) => void;
122
+ /** A reply is streaming: Send turns into Stop, Enter no longer sends, Escape stops. */
123
+ streaming?: boolean;
124
+ onStop?: () => void;
125
+ disabled?: boolean;
126
+ placeholder?: string;
127
+ /** Accessible name of the text box. */
128
+ label?: string;
129
+ /** Soft limit: shows a counter near the limit and blocks sending above it. */
130
+ maxLength?: number;
131
+ /** Attached files shown as removable chips (thumbnail, progress, error + retry). */
132
+ attachments?: ComposerAttachment[];
133
+ /**
134
+ * Shows the attach button and enables paste and drag-and-drop of files; called with the
135
+ * files that pass `accept`, `maxSize` and `maxFiles`.
136
+ */
137
+ onAttach?: (files: File[]) => void;
138
+ onRemoveAttachment?: (id: string) => void;
139
+ /** Shows Retry on attachments in the error state. */
140
+ onRetryAttachment?: (id: string) => void;
141
+ /** Allowed types, `<input accept>` syntax (e.g. ".pdf,.csv,image/*"). Also checked on paste and drop. */
142
+ accept?: string;
143
+ /** Largest allowed file, in bytes. */
144
+ maxSize?: number;
145
+ /** Most files attached at once. */
146
+ maxFiles?: number;
147
+ /** Called with the files that failed validation (their messages are also shown under the box). */
148
+ onReject?: (rejections: AttachmentRejection[]) => void;
149
+ /** Slot left of the send button, e.g. a model Select. */
150
+ modelPicker?: ReactNode;
151
+ /** Extra tools after the attach button. */
152
+ tools?: ReactNode;
153
+ /** Small line under the box. Defaults to the keyboard hint; pass null to hide it. */
154
+ hint?: ReactNode;
155
+ className?: string;
156
+ ref?: Ref<HTMLTextAreaElement>;
157
+ }
158
+ /**
159
+ * Message box for a chat: grows with its content, Enter sends and Shift+Enter adds a line,
160
+ * files (picked, pasted or dropped, validated against accept / maxSize / maxFiles) show as
161
+ * removable chips with previews and upload progress, a model picker can sit in the toolbar, and while a reply
162
+ * streams the send button becomes Stop (Escape also stops).
163
+ */
164
+ export declare function ChatComposer({ value, defaultValue, onValueChange, onSubmit, streaming, onStop, disabled, placeholder: placeholderProp, label: labelProp, maxLength, attachments, onAttach, onRemoveAttachment, onRetryAttachment, accept, maxSize, maxFiles, onReject, modelPicker, tools, hint, className, ref }: ChatComposerProps): import("react").JSX.Element;
165
+ //#endregion
166
+ //#region src/ChatComposer/chatComposer.variants.d.ts
167
+ /** Slot classes for ChatComposer (focus ring on the frame, like the legacy composer). */
168
+ export declare const chatComposerStyles: {
169
+ readonly root: string;
170
+ readonly dropOverlay: "pointer-events-none absolute inset-0 z-10 flex items-center justify-center gap-2 rounded-xl border-2 border-dashed border-primary/60 bg-card/95 text-[13px] font-medium text-primary-text";
171
+ readonly errors: "mx-3 mt-3 flex items-start gap-2 rounded-md border border-destructive/40 bg-destructive/8 px-2.5 py-1.5 text-[12px] text-destructive-chip-text";
172
+ readonly errorList: "flex min-w-0 flex-1 flex-col gap-0.5";
173
+ readonly errorDismiss: "-me-1 grid size-5 shrink-0 place-items-center rounded text-destructive-chip-text hover:bg-foreground/10 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
174
+ readonly attachments: "flex flex-wrap gap-1.5 px-3 pt-3";
175
+ /** @deprecated Chips render AttachmentChip (see attachmentStyles). */
176
+ readonly chip: "inline-flex h-7 max-w-60 items-center gap-1.5 rounded-md border border-border bg-secondary/50 ps-2 pe-1 text-[12px] text-foreground";
177
+ readonly chipName: "truncate font-medium";
178
+ readonly chipSize: "shrink-0 font-mono text-[10.5px] text-muted-foreground";
179
+ readonly chipRemove: "grid size-5 shrink-0 place-items-center rounded text-muted-foreground hover:bg-foreground/10 hover:text-foreground focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
180
+ readonly textarea: string;
181
+ readonly toolbar: "flex items-center justify-between gap-2 px-2 pb-2";
182
+ readonly tools: "flex min-w-0 items-center gap-1";
183
+ readonly end: "flex shrink-0 items-center gap-2";
184
+ readonly count: "font-mono text-[11px] text-muted-foreground tabular-nums";
185
+ readonly countOver: "text-destructive-text";
186
+ readonly hint: "mt-1.5 px-1 text-center text-[11.5px] text-muted-foreground";
187
+ };
188
+ //#endregion
189
+ //#region src/ChatComposer/ChatComposer.doc.d.ts
190
+ declare const doc$1: ComponentDoc;
191
+ //#endregion
192
+ //#region src/ChatDemo/ChatDemo.d.ts
193
+ interface ChatDemoProps {
194
+ /** Show the resizable details panel. */
195
+ withPanel?: boolean;
196
+ /** Milliseconds between streamed chunks. */
197
+ tickMs?: number;
198
+ className?: string;
199
+ }
200
+ /**
201
+ * End-to-end example: suggestions, a user turn with attachments, a tool call, a streamed
202
+ * markdown reply with sources, Stop, Regenerate and feedback, and a compact model picker. Streaming is mocked with timers that are cleared on
203
+ * Stop and on unmount.
204
+ */
205
+ export declare function ChatDemo({ withPanel, tickMs, className }: ChatDemoProps): import("react").JSX.Element;
206
+ //#endregion
207
+ //#region src/ChatDemo/ChatDemo.doc.d.ts
208
+ declare const doc$2: ComponentDoc;
209
+ //#endregion
210
+ //#region src/ChatLayout/ChatLayout.d.ts
211
+ interface ChatLayoutProps {
212
+ /** The messages (ChatMessage list, suggestions, …). */
213
+ children?: ReactNode;
214
+ /** Pinned at the bottom of the thread column, outside the scroll area (usually ChatComposer). */
215
+ composer?: ReactNode;
216
+ /** Optional header above the thread (title, model, actions). */
217
+ header?: ReactNode;
218
+ /** Optional side panel (artifact preview, details). Omit to hide it and its resize handle. */
219
+ panel?: ReactNode;
220
+ /** Accessible name of the side panel landmark. */
221
+ panelLabel?: string;
222
+ /** Initial panel width in px. */
223
+ defaultPanelWidth?: number;
224
+ minPanelWidth?: number;
225
+ maxPanelWidth?: number;
226
+ onPanelWidthChange?: (width: number) => void;
227
+ /** Accessible name of the thread region. */
228
+ label?: string;
229
+ /** Label of the "jump to latest" button. */
230
+ scrollButtonLabel?: string;
231
+ /** Extra classes on the root. */
232
+ className?: string;
233
+ /** Extra classes on the centred content column. */
234
+ contentClassName?: string;
235
+ ref?: Ref<HTMLDivElement>;
236
+ }
237
+ /**
238
+ * Full-height chat frame: a scrollable thread with auto-scroll that respects scrolling up,
239
+ * a "jump to latest" button, the composer pinned below, and an optional side panel that the
240
+ * user can resize by dragging or with the arrow keys on its separator.
241
+ */
242
+ export declare function ChatLayout({ children, composer, header, panel, panelLabel: panelLabelProp, defaultPanelWidth, minPanelWidth, maxPanelWidth, onPanelWidthChange, label: labelProp, scrollButtonLabel: scrollButtonLabelProp, className, contentClassName, ref }: ChatLayoutProps): import("react").JSX.Element;
243
+ //#endregion
244
+ //#region src/ChatLayout/chatLayout.variants.d.ts
245
+ /** Slot classes for ChatLayout (plain strings: this package does not ship tailwind-variants). */
246
+ export declare const chatLayoutStyles: {
247
+ readonly root: "flex h-full min-h-0 w-full bg-background text-foreground";
248
+ readonly thread: "flex min-w-0 flex-1 flex-col";
249
+ readonly header: "shrink-0 border-b border-border";
250
+ readonly viewport: "relative min-h-0 flex-1";
251
+ readonly scroller: "h-full overflow-y-auto overscroll-contain focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring focus-visible:-outline-offset-2";
252
+ readonly content: "mx-auto flex w-full max-w-3xl flex-col gap-6 px-4 py-6 sm:px-6";
253
+ readonly jump: "pointer-events-none absolute inset-x-0 bottom-3 flex justify-center";
254
+ readonly jumpButton: "pointer-events-auto rounded-full shadow-md";
255
+ readonly composer: "shrink-0 bg-background px-4 pb-4 pt-2 sm:px-6";
256
+ readonly composerInner: "mx-auto w-full max-w-3xl";
257
+ readonly handle: string;
258
+ readonly panel: "flex min-h-0 shrink-0 flex-col overflow-hidden border-s border-border bg-card";
259
+ };
260
+ //#endregion
261
+ //#region src/ChatLayout/ChatLayout.doc.d.ts
262
+ declare const doc$3: ComponentDoc;
263
+ //#endregion
264
+ //#region src/ChatMessage/ChatMessage.d.ts
265
+ /**
266
+ * Who wrote a turn. `participant` is another person in the conversation (a teammate, an agent
267
+ * handing over): not the current user and not the assistant.
268
+ */
269
+ type ChatRole = 'user' | 'assistant' | 'participant' | 'system' | 'tool';
270
+ type ChatFeedback = 'up' | 'down' | null;
271
+ interface ChatMessageProps {
272
+ role: ChatRole;
273
+ /** Display name; defaults per role ("You", "Assistant", "Participant", "System", "Tool"). Pass it for `participant`. */
274
+ author?: string;
275
+ /** Replaces the default avatar. Pass `null` to hide it. */
276
+ avatar?: ReactNode;
277
+ /** Image URL for the default avatar of `user` and `participant` turns (initials show while it loads or if it fails). */
278
+ avatarSrc?: string;
279
+ /** When the message was sent. A Date renders as a local short time. */
280
+ timestamp?: Date | string;
281
+ /** The body: a string, a <Markdown>, a ToolCallCard… */
282
+ children?: ReactNode;
283
+ /**
284
+ * Text is still arriving: marks the message aria-busy, hides the actions, shows a
285
+ * TypingIndicator while empty and a caret after plain-text children (a streaming
286
+ * <Markdown> draws its own caret).
287
+ */
288
+ streaming?: boolean;
289
+ /** Draw the caret after streamed plain-text children. Default true. */
290
+ showCaret?: boolean;
291
+ /** Plain text to copy; shows the Copy action. */
292
+ copyText?: string;
293
+ /** Shows the Retry action (assistant replies). */
294
+ onRetry?: () => void;
295
+ /** Current feedback (controlled). */
296
+ feedback?: ChatFeedback;
297
+ /** Shows the thumbs; called with the new value (clicking the active thumb clears it). */
298
+ onFeedback?: (value: ChatFeedback) => void;
299
+ /** Extra actions appended to the action group. */
300
+ actions?: ReactNode;
301
+ /** Keep the actions visible instead of revealing them on hover/focus. */
302
+ alwaysShowActions?: boolean;
303
+ className?: string;
304
+ ref?: Ref<HTMLElement>;
305
+ }
306
+ /**
307
+ * One turn in a conversation. User turns are right-aligned bubbles, participant turns (another
308
+ * person) are start-aligned outlined bubbles, assistant turns are full-width prose, system notes are centred pills and tool turns hold a ToolCallCard. Copy,
309
+ * retry and feedback actions appear on hover or keyboard focus and are reachable with Tab.
310
+ */
311
+ export declare function ChatMessage({ role, author, avatar, avatarSrc, timestamp, children, streaming, showCaret, copyText, onRetry, feedback, onFeedback, actions, alwaysShowActions, className, ref }: ChatMessageProps): import("react").JSX.Element;
312
+ //#endregion
313
+ //#region src/ChatMessage/ChatAnnouncer.d.ts
314
+ interface ChatAnnouncerProps {
315
+ /** A reply is being generated. */
316
+ streaming: boolean;
317
+ /** Plain text of the latest completed reply (announced once, when streaming ends). */
318
+ lastReply?: string;
319
+ /** Who is replying, used in the "is responding" status. */
320
+ author?: string;
321
+ /** Max characters of the completed reply to announce. */
322
+ maxLength?: number;
323
+ }
324
+ /**
325
+ * Screen-reader strategy for streaming: the thread itself is not a live region (it would
326
+ * re-announce every token). This single polite, atomic status says "Assistant is responding…"
327
+ * when a stream starts and reads the finished reply once when it ends.
328
+ */
329
+ export declare function ChatAnnouncer({ streaming, lastReply, author, maxLength }: ChatAnnouncerProps): import("react").JSX.Element;
330
+ //#endregion
331
+ //#region src/ChatMessage/chatMessage.variants.d.ts
332
+ /** Slot classes for ChatMessage, per role. */
333
+ export declare const chatMessageStyles: {
334
+ readonly root: "group/message relative flex gap-3 outline-none";
335
+ readonly avatar: "mt-0.5 shrink-0";
336
+ readonly body: "flex min-w-0 flex-1 flex-col gap-1";
337
+ readonly meta: "flex items-baseline gap-2 text-[12px] leading-5";
338
+ readonly author: "font-semibold text-foreground";
339
+ readonly time: "font-mono text-[11px] text-muted-foreground";
340
+ readonly content: "min-w-0 text-[14px] leading-[1.7] text-foreground";
341
+ readonly actions: string;
342
+ readonly actionsVisible: "opacity-100";
343
+ /** @deprecated The empty streaming state renders TypingIndicator (see typingIndicatorStyles). */
344
+ readonly typing: "inline-flex h-6 items-center gap-1";
345
+ /** @deprecated See typingIndicatorStyles.dot. */
346
+ readonly typingDot: "size-1.5 rounded-full bg-muted-foreground animate-pulse motion-reduce:animate-none";
347
+ readonly role: {
348
+ readonly user: {
349
+ readonly root: "flex-row-reverse";
350
+ readonly body: "items-end";
351
+ readonly meta: "flex-row-reverse";
352
+ readonly content: "max-w-[85%] rounded-2xl rounded-se-md bg-secondary px-4 py-2.5 whitespace-pre-wrap [overflow-wrap:anywhere]";
353
+ };
354
+ readonly assistant: {
355
+ readonly root: "";
356
+ readonly body: "";
357
+ readonly meta: "";
358
+ readonly content: "";
359
+ };
360
+ readonly participant: {
361
+ readonly root: "";
362
+ readonly body: "items-start";
363
+ readonly meta: "";
364
+ readonly content: "max-w-[85%] rounded-2xl rounded-ss-md border border-border bg-card px-4 py-2.5 whitespace-pre-wrap [overflow-wrap:anywhere]";
365
+ };
366
+ readonly system: {
367
+ readonly root: "justify-center";
368
+ readonly body: "items-center";
369
+ readonly meta: "sr-only";
370
+ readonly content: "rounded-full border border-border bg-card px-3 py-1 text-center text-[12px] leading-5 text-muted-foreground";
371
+ };
372
+ readonly tool: {
373
+ readonly root: "";
374
+ readonly body: "";
375
+ readonly meta: "";
376
+ readonly content: "text-[13px]";
377
+ };
378
+ };
379
+ };
380
+ //#endregion
381
+ //#region src/ChatMessage/ChatMessage.doc.d.ts
382
+ declare const doc$4: ComponentDoc;
383
+ //#endregion
384
+ //#region src/Citation/Citation.d.ts
385
+ interface CitationSource {
386
+ /** Source title. */
387
+ title: string;
388
+ /** Where it lives; shown as its host name and linked. */
389
+ url?: string;
390
+ /** Short excerpt that supports the claim. */
391
+ snippet?: string;
392
+ /** Publisher or site name; defaults to the URL host. */
393
+ publisher?: string;
394
+ }
395
+ /** Host name of a URL ("docs.example.com"), or undefined if it cannot be parsed. */
396
+ export declare function sourceHost(url?: string): string | undefined;
397
+ /** Only http(s) sources become links. */
398
+ export declare function safeSourceUrl(url?: string): string | undefined;
399
+ interface CitationProps {
400
+ /** 1-based number shown in the marker. */
401
+ index: number;
402
+ source: CitationSource;
403
+ /** Hover delay before the preview opens (keyboard and click open it immediately). */
404
+ delay?: number;
405
+ className?: string;
406
+ }
407
+ /**
408
+ * Inline numbered reference ([1]). Hovering, focusing + Enter or clicking opens a preview
409
+ * card with the title, host, snippet and a link to the source.
410
+ */
411
+ export declare function Citation({ index, source, delay, className }: CitationProps): import("react").JSX.Element;
412
+ interface CitationListProps {
413
+ sources: CitationSource[];
414
+ /** Visible heading; also the list's accessible name. */
415
+ heading?: ReactNode;
416
+ className?: string;
417
+ }
418
+ /** Numbered list of the sources cited in a reply, matching the inline markers. */
419
+ export declare function CitationList({ sources, heading: headingProp, className }: CitationListProps): import("react").JSX.Element | null;
420
+ //#endregion
421
+ //#region src/Citation/citation.variants.d.ts
422
+ /** Slot classes for Citation and CitationList. */
423
+ export declare const citationStyles: {
424
+ readonly trigger: string;
425
+ readonly popup: "w-80";
426
+ readonly head: "flex items-center gap-2 text-[11.5px] text-muted-foreground";
427
+ readonly index: "grid h-[18px] min-w-[18px] place-items-center rounded-md bg-secondary px-1 font-mono text-[10.5px] font-semibold text-foreground";
428
+ readonly title: "mt-1.5 text-[13px] font-semibold leading-snug text-foreground";
429
+ readonly snippet: "mt-1 line-clamp-4 text-[12.5px] leading-relaxed text-muted-foreground";
430
+ readonly open: "mt-2.5 inline-flex items-center gap-1 rounded-sm text-[12.5px] font-medium text-primary-text hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
431
+ readonly list: "flex flex-col gap-1.5";
432
+ readonly heading: "mb-1 text-[11.5px] font-semibold tracking-wide text-muted-foreground uppercase";
433
+ readonly item: "flex gap-2.5 rounded-lg border border-border bg-card px-3 py-2.5";
434
+ readonly itemBody: "min-w-0 flex-1";
435
+ readonly itemTitle: "rounded-sm text-[13px] font-medium text-foreground hover:text-primary-text hover:underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
436
+ readonly itemHost: "mt-0.5 truncate font-mono text-[11px] text-muted-foreground";
437
+ };
438
+ //#endregion
439
+ //#region src/Citation/Citation.doc.d.ts
440
+ declare const doc$5: ComponentDoc;
441
+ //#endregion
442
+ //#region src/Markdown/Markdown.d.ts
443
+ interface MarkdownProps {
444
+ /** Markdown source (GitHub-flavoured: tables, task lists, strikethrough, autolinks). */
445
+ children: string;
446
+ /** Text is still arriving: closes a dangling code fence and draws the caret. */
447
+ streaming?: boolean;
448
+ className?: string;
449
+ }
450
+ /**
451
+ * URL policy: relative URLs, anchors and http(s)/mailto/tel only. Everything else
452
+ * (javascript:, data:, vbscript:, …) is dropped, on top of react-markdown's own transform.
453
+ */
454
+ export declare function safeUrl(url: string): string;
455
+ /**
456
+ * Makes partial streamed markdown render sanely: a fence that has opened but not closed is
457
+ * closed at the end, so the tail renders as code instead of flashing as paragraphs.
458
+ */
459
+ export declare function repairStreamingMarkdown(text: string): string;
460
+ /**
461
+ * Safe markdown for model output: raw HTML is never rendered (skipped, not parsed), links are
462
+ * restricted to http(s)/mailto/tel/relative, external links open in a new tab with a marker,
463
+ * and fenced code gets a copy button. Partial input from a stream is tolerated.
464
+ */
465
+ export declare const Markdown: import("react").MemoExoticComponent<({ children, streaming, className }: MarkdownProps) => import("react").JSX.Element>;
466
+ //#endregion
467
+ //#region src/Markdown/CodeBlock.d.ts
468
+ interface CodeBlockProps {
469
+ /** Source text. */
470
+ code: string;
471
+ /** Language tag from the fence (```ts). */
472
+ language?: string;
473
+ className?: string;
474
+ }
475
+ /** Fenced code with a language label and a copy button. */
476
+ export declare function CodeBlock({ code, language, className }: CodeBlockProps): import("react").JSX.Element;
477
+ //#endregion
478
+ //#region src/Markdown/markdown.variants.d.ts
479
+ /**
480
+ * Blinking caret drawn after the last block while text streams in. Pure CSS (an ::after on the
481
+ * last child), so it follows paragraphs, list items and code without extra DOM.
482
+ */
483
+ export declare const streamingCaretClass: string;
484
+ /** Element classes for Markdown (token colours only). */
485
+ export declare const markdownStyles: {
486
+ readonly root: "min-w-0 text-[14px] leading-[1.7] text-foreground [overflow-wrap:anywhere] [&>:first-child]:mt-0 [&>:last-child]:mb-0";
487
+ readonly h1: "mt-5 mb-2 text-[18px] font-semibold tracking-tight";
488
+ readonly h2: "mt-5 mb-2 text-[16px] font-semibold tracking-tight";
489
+ readonly h3: "mt-4 mb-1.5 text-[14.5px] font-semibold";
490
+ readonly h4: "mt-4 mb-1.5 text-[13.5px] font-semibold text-muted-foreground";
491
+ readonly p: "my-2.5";
492
+ readonly ul: "my-2.5 list-disc space-y-1 ps-5 marker:text-muted-foreground";
493
+ readonly ol: "my-2.5 list-decimal space-y-1 ps-5 marker:text-muted-foreground";
494
+ readonly li: "ps-1 [&>ul]:my-1 [&>ol]:my-1 [&.task-list-item]:list-none [&.task-list-item]:-ms-5";
495
+ readonly blockquote: "my-3 border-s-2 border-primary/50 ps-3.5 text-muted-foreground";
496
+ readonly hr: "my-5 border-border";
497
+ readonly link: "rounded-sm font-medium text-primary-text underline decoration-primary/40 underline-offset-2 hover:decoration-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring";
498
+ readonly linkIcon: "ms-0.5 inline-block align-[-1px]";
499
+ readonly inlineCode: "rounded-md border border-border bg-secondary/60 px-1.5 py-px font-mono text-[12.5px]";
500
+ readonly tableWrap: "my-3 overflow-x-auto rounded-lg border border-border";
501
+ readonly table: "w-full border-collapse text-start text-[13px]";
502
+ readonly th: "border-b border-border bg-secondary/50 px-3 py-2 font-semibold";
503
+ readonly td: "border-b border-border px-3 py-2 align-top [tr:last-child_&]:border-b-0";
504
+ readonly checkbox: "me-1.5 align-[-2px] accent-primary";
505
+ readonly image: "text-muted-foreground italic";
506
+ readonly code: {
507
+ readonly root: "my-3 overflow-hidden rounded-lg border border-border bg-secondary/40";
508
+ readonly header: "flex h-9 items-center justify-between border-b border-border bg-secondary/50 ps-3 pe-1.5";
509
+ readonly lang: "font-mono text-[11px] tracking-wide text-muted-foreground uppercase";
510
+ readonly pre: "overflow-x-auto p-3 font-mono text-[12.5px] leading-6";
511
+ };
512
+ };
513
+ //#endregion
514
+ //#region src/Markdown/Markdown.doc.d.ts
515
+ declare const doc$6: ComponentDoc;
516
+ //#endregion
517
+ //#region src/MessageFeedback/MessageFeedback.d.ts
518
+ type FeedbackRating = 'up' | 'down';
519
+ interface FeedbackValue {
520
+ /** `null` = no rating. */
521
+ rating: FeedbackRating | null;
522
+ /** Reason picked after a thumbs down (a `FeedbackReason.value`). */
523
+ reason?: string;
524
+ /** Free-text comment after a thumbs down. */
525
+ comment?: string;
526
+ }
527
+ interface FeedbackReason {
528
+ value: string;
529
+ label: string;
530
+ }
531
+ interface MessageFeedbackProps {
532
+ /** Current feedback (controlled). Uncontrolled when omitted. */
533
+ value?: FeedbackValue;
534
+ /**
535
+ * Called on every change: `{ rating: 'up' }`, `{ rating: 'down' }` right away on thumbs down,
536
+ * then `{ rating: 'down', reason, comment }` when the details form is sent, and
537
+ * `{ rating: null }` when the active thumb is pressed again.
538
+ */
539
+ onFeedback?: (value: FeedbackValue) => void;
540
+ /** Reasons offered after a thumbs down. Defaults to a generic list; `[]` hides the picker. */
541
+ reasons?: FeedbackReason[];
542
+ /** Open the reason/comment popover on thumbs down. Default true. */
543
+ askDetails?: boolean;
544
+ /** Plain text to copy; shows the Copy action. */
545
+ copyText?: string;
546
+ /** Shows the Regenerate action. */
547
+ onRegenerate?: () => void;
548
+ /** Accessible name of the group. Default "Response feedback". */
549
+ label?: string;
550
+ disabled?: boolean;
551
+ className?: string;
552
+ ref?: Ref<HTMLDivElement>;
553
+ }
554
+ /**
555
+ * Feedback for an assistant reply: thumbs up / down toggles (aria-pressed), and on thumbs down
556
+ * a popover asking for a reason and an optional comment. Copy and Regenerate sit alongside.
557
+ */
558
+ export declare function MessageFeedback({ value: valueProp, onFeedback, reasons: reasonsProp, askDetails, copyText, onRegenerate, label, disabled, className, ref }: MessageFeedbackProps): import("react").JSX.Element;
559
+ //#endregion
560
+ //#region src/MessageFeedback/messageFeedback.variants.d.ts
561
+ /** Slot classes for MessageFeedback. */
562
+ export declare const messageFeedbackStyles: {
563
+ readonly root: "inline-flex items-center gap-0.5";
564
+ readonly up: "text-primary-text";
565
+ readonly down: "text-destructive-text";
566
+ readonly popup: "w-80 max-w-[calc(100vw-2rem)]";
567
+ readonly form: "flex flex-col gap-3";
568
+ readonly title: "text-[13px] font-semibold text-foreground";
569
+ readonly label: "mb-1.5 block text-[12.5px] font-medium text-foreground";
570
+ readonly footer: "flex justify-end gap-2";
571
+ };
572
+ //#endregion
573
+ //#region src/MessageFeedback/MessageFeedback.doc.d.ts
574
+ declare const doc$7: ComponentDoc;
575
+ //#endregion
576
+ //#region src/ModelPicker/ModelPicker.d.ts
577
+ type ModelCapability = 'vision' | 'tools' | 'reasoning' | 'files' | 'web' | 'audio';
578
+ interface ChatModel {
579
+ /** Value reported by `onValueChange`. */
580
+ id: string;
581
+ name: string;
582
+ /** Group heading, e.g. the provider or the deployment. Models are grouped in first-seen order. */
583
+ provider: string;
584
+ description?: string;
585
+ capabilities?: ModelCapability[];
586
+ /** Context window in tokens; shown as "128K context". */
587
+ contextWindow?: number;
588
+ disabled?: boolean;
589
+ /** Why it is disabled ("Needs an upgraded plan"); shown under the name. */
590
+ disabledReason?: string;
591
+ }
592
+ interface ModelPickerProps {
593
+ models: ChatModel[];
594
+ /** Selected model id (controlled). */
595
+ value: string | null;
596
+ onValueChange: (id: string) => void;
597
+ /** Small borderless trigger with only the model name, for the composer toolbar. */
598
+ compact?: boolean;
599
+ /** Accessible name of the trigger. Default "Model". */
600
+ label?: string;
601
+ placeholder?: string;
602
+ disabled?: boolean;
603
+ /** Hide the provider next to the name in the full trigger. */
604
+ hideProvider?: boolean;
605
+ className?: string;
606
+ ref?: Ref<HTMLButtonElement>;
607
+ }
608
+ /** Models grouped by provider, keeping first-seen order. */
609
+ export declare function groupModels(models: ChatModel[]): {
610
+ provider: string;
611
+ items: ChatModel[];
612
+ }[];
613
+ /**
614
+ * Model / provider select for a chat: options grouped by provider with capability badges
615
+ * (vision, tools, context size…) and disabled models that say why. `compact` renders a small
616
+ * borderless trigger for the composer toolbar. Built on Select (Base UI).
617
+ */
618
+ export declare function ModelPicker({ models, value, onValueChange, compact, label, placeholder, disabled, hideProvider, className, ref }: ModelPickerProps): import("react").JSX.Element;
619
+ //#endregion
620
+ //#region src/ModelPicker/modelPicker.variants.d.ts
621
+ /** Slot classes for ModelPicker. */
622
+ export declare const modelPickerStyles: {
623
+ readonly trigger: "w-auto max-w-full min-w-0";
624
+ readonly compactTrigger: "h-7 w-auto max-w-56 min-w-0 gap-1 border-transparent bg-transparent ps-2 pe-1.5 shadow-none hover:bg-secondary/70 hover:border-transparent";
625
+ readonly triggerValue: "flex min-w-0 items-center gap-1.5";
626
+ readonly triggerIcon: "shrink-0 text-muted-foreground";
627
+ readonly triggerName: "truncate font-medium";
628
+ readonly triggerProvider: "truncate text-muted-foreground";
629
+ readonly popup: "w-80 max-w-[calc(100vw-2rem)]";
630
+ readonly item: "items-start";
631
+ readonly itemBody: "flex min-w-0 flex-col gap-1 py-0.5 whitespace-normal";
632
+ readonly itemName: "font-medium text-foreground";
633
+ readonly itemDescription: "text-[11.5px] leading-4 text-muted-foreground";
634
+ readonly badges: "flex flex-wrap gap-1";
635
+ readonly reason: "text-[11.5px] leading-4 text-muted-foreground italic";
636
+ };
637
+ //#endregion
638
+ //#region src/ModelPicker/fixtures.d.ts
639
+ /** Generic, product-agnostic models for examples and the demo. */
640
+ export declare const DEMO_MODELS: ChatModel[];
641
+ //#endregion
642
+ //#region src/ModelPicker/ModelPicker.doc.d.ts
643
+ declare const doc$8: ComponentDoc;
644
+ //#endregion
645
+ //#region src/SuggestionChips/SuggestionChips.d.ts
646
+ type IconComponent = ComponentType<{
647
+ size?: number;
648
+ className?: string;
649
+ 'aria-hidden'?: boolean;
650
+ }>;
651
+ interface Suggestion {
652
+ /** Stable key; defaults to the label. */
653
+ id?: string;
654
+ /** Short title shown on the chip. */
655
+ label: string;
656
+ /** Second line (card layout only). */
657
+ description?: string;
658
+ /** Prompt sent when chosen; defaults to the label. */
659
+ prompt?: string;
660
+ icon?: IconComponent;
661
+ }
662
+ interface SuggestionChipsProps {
663
+ suggestions: ReadonlyArray<Suggestion | string>;
664
+ onSelect: (prompt: string, suggestion: Suggestion) => void;
665
+ /** `cards` (two-column grid with descriptions) for an empty thread, `chips` (pills) for follow-ups. */
666
+ layout?: 'cards' | 'chips';
667
+ /** Heading above the group; also its accessible name. */
668
+ heading?: ReactNode;
669
+ /** Accessible name when there is no visible heading. */
670
+ label?: string;
671
+ disabled?: boolean;
672
+ className?: string;
673
+ }
674
+ /** Prompt suggestions for an empty conversation (cards) or as follow-ups after a reply (chips). */
675
+ export declare function SuggestionChips({ suggestions, onSelect, layout, heading, label: labelProp, disabled, className }: SuggestionChipsProps): import("react").JSX.Element;
676
+ //#endregion
677
+ //#region src/SuggestionChips/suggestionChips.variants.d.ts
678
+ /** Slot classes for SuggestionChips. */
679
+ export declare const suggestionChipsStyles: {
680
+ readonly root: "w-full";
681
+ readonly heading: "mb-2.5 text-[12px] font-semibold tracking-wide text-muted-foreground uppercase";
682
+ readonly grid: "grid gap-2 sm:grid-cols-2";
683
+ readonly row: "flex flex-wrap gap-2";
684
+ readonly card: string;
685
+ readonly chip: string;
686
+ readonly icon: "mt-0.5 shrink-0 text-muted-foreground group-hover:text-primary-text";
687
+ readonly label: "block text-[13px] font-medium text-foreground";
688
+ readonly description: "mt-0.5 block text-[12px] leading-5 text-muted-foreground";
689
+ };
690
+ //#endregion
691
+ //#region src/SuggestionChips/SuggestionChips.doc.d.ts
692
+ declare const doc$9: ComponentDoc;
693
+ //#endregion
694
+ //#region src/ToolCallCard/ToolCallCard.d.ts
695
+ type ToolCallStatus = 'running' | 'succeeded' | 'failed';
696
+ interface ToolCallCardProps {
697
+ /** Tool / function name, e.g. "search_invoices". */
698
+ name: string;
699
+ status: ToolCallStatus;
700
+ /** Elapsed time in ms. */
701
+ durationMs?: number;
702
+ /** Arguments the model passed. */
703
+ args?: unknown;
704
+ /** What the tool returned. */
705
+ result?: unknown;
706
+ /** Error message for a failed call. */
707
+ error?: string;
708
+ /** Start expanded. Failed calls open by default. */
709
+ defaultOpen?: boolean;
710
+ /** Controlled open state. */
711
+ open?: boolean;
712
+ onOpenChange?: (open: boolean) => void;
713
+ className?: string;
714
+ ref?: Ref<HTMLDivElement>;
715
+ }
716
+ /**
717
+ * A tool invocation inside an assistant turn: name, status, duration, and a collapsible body
718
+ * with the arguments and the result (or error) as small JSON views.
719
+ */
720
+ export declare function ToolCallCard({ name, status, durationMs, args, result, error, defaultOpen, open, onOpenChange, className, ref }: ToolCallCardProps): import("react").JSX.Element;
721
+ //#endregion
722
+ //#region src/ToolCallCard/JsonView.d.ts
723
+ interface JsonViewProps {
724
+ /** Section title ("Arguments", "Result"). */
725
+ label: string;
726
+ /** Any value: objects are pretty-printed, strings shown as-is. */
727
+ value: unknown;
728
+ defaultOpen?: boolean;
729
+ }
730
+ /** A small collapsible, scrollable JSON block. */
731
+ export declare function JsonView({ label, value, defaultOpen }: JsonViewProps): import("react").JSX.Element;
732
+ //#endregion
733
+ //#region src/ToolCallCard/toolCallCard.variants.d.ts
734
+ /** Slot classes for ToolCallCard and JsonView. */
735
+ export declare const toolCallCardStyles: {
736
+ readonly root: "w-full overflow-hidden rounded-lg border border-border bg-card text-[13px]";
737
+ readonly trigger: string;
738
+ readonly icon: "grid size-6 shrink-0 place-items-center rounded-md bg-secondary text-muted-foreground";
739
+ readonly iconFailed: "bg-destructive/15 text-destructive-chip-text";
740
+ readonly label: "flex min-w-0 flex-1 items-baseline gap-1.5";
741
+ readonly verb: "shrink-0 text-muted-foreground";
742
+ readonly name: "truncate font-mono text-[12.5px] font-semibold text-foreground";
743
+ readonly meta: "flex shrink-0 items-center gap-2";
744
+ readonly duration: "font-mono text-[11px] text-muted-foreground tabular-nums";
745
+ readonly body: "flex flex-col gap-2 border-t border-border px-3 pb-3 pt-1";
746
+ readonly error: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-[12.5px] text-destructive-chip-text";
747
+ readonly json: {
748
+ readonly trigger: "mx-0 h-7 px-1 text-[11.5px] font-semibold tracking-wide text-muted-foreground uppercase";
749
+ readonly content: "pt-1";
750
+ readonly pre: "max-h-64 overflow-auto rounded-md border border-border bg-secondary/40 p-2.5 font-mono text-[12px] leading-5 text-foreground";
751
+ };
752
+ };
753
+ //#endregion
754
+ //#region src/ToolCallCard/ToolCallCard.doc.d.ts
755
+ declare const doc$10: ComponentDoc;
756
+ //#endregion
757
+ //#region src/TypingIndicator/TypingIndicator.d.ts
758
+ interface TypingIndicatorProps {
759
+ /** Who is typing; used in the accessible text ("Assistant is typing"). */
760
+ author?: string;
761
+ /** Show the text next to the dots instead of keeping it screen-reader only. */
762
+ showLabel?: boolean;
763
+ /** Overrides the text entirely. */
764
+ label?: string;
765
+ size?: 'sm' | 'md';
766
+ /**
767
+ * Announce the text through its own polite status region. Off by default: in a thread,
768
+ * ChatAnnouncer already announces "is responding" once.
769
+ */
770
+ announce?: boolean;
771
+ className?: string;
772
+ ref?: Ref<HTMLSpanElement>;
773
+ }
774
+ /**
775
+ * Three dots that pulse while a reply is being written. The dots are decorative; the text
776
+ * ("Assistant is typing") is always in the accessibility tree. Under reduced motion the dots
777
+ * hold still.
778
+ */
779
+ export declare function TypingIndicator({ author, showLabel, label, size, announce, className, ref }: TypingIndicatorProps): import("react").JSX.Element;
780
+ //#endregion
781
+ //#region src/TypingIndicator/typingIndicator.variants.d.ts
782
+ /** Slot classes for TypingIndicator. Dots pulse in sequence; static under reduced motion. */
783
+ export declare const typingIndicatorStyles: {
784
+ readonly root: "inline-flex items-center gap-2 text-muted-foreground";
785
+ readonly dots: "inline-flex h-6 items-center gap-1";
786
+ readonly dot: "size-1.5 rounded-full bg-muted-foreground animate-pulse motion-reduce:animate-none";
787
+ readonly label: "text-[12.5px]";
788
+ readonly size: {
789
+ readonly sm: {
790
+ readonly dots: "h-4 gap-0.5";
791
+ readonly dot: "size-1";
792
+ };
793
+ readonly md: {
794
+ readonly dots: "";
795
+ readonly dot: "";
796
+ };
797
+ };
798
+ };
799
+ /** Thin blinking caret after streamed plain text (static under reduced motion). */
800
+ export declare const streamingCaret = "ms-0.5 inline-block h-[1.05em] w-[2px] translate-y-[2px] bg-primary animate-pulse motion-reduce:animate-none";
801
+ //#endregion
802
+ //#region src/TypingIndicator/TypingIndicator.doc.d.ts
803
+ declare const doc$11: ComponentDoc;
804
+ //#endregion
805
+ //#region src/useChatScroll/useChatScroll.d.ts
806
+ interface UseChatScrollOptions {
807
+ /** Distance from the bottom (px) still treated as "at the bottom". */
808
+ threshold?: number;
809
+ }
810
+ interface UseChatScrollResult {
811
+ /** Callback ref for the scrolling element. */
812
+ scrollRef: (el: HTMLElement | null) => void;
813
+ /** Callback ref for the content inside it (watched for growth, e.g. streamed tokens). */
814
+ contentRef: (el: HTMLElement | null) => void;
815
+ /** True while the viewport is pinned to the latest message. */
816
+ isAtBottom: boolean;
817
+ /** Scrolls to the latest message and re-pins auto-scroll. */
818
+ scrollToBottom: (behavior?: ScrollBehavior) => void;
819
+ }
820
+ /**
821
+ * Auto-scroll for a chat thread that respects the reader: new content keeps the view pinned
822
+ * to the bottom only while the user is already there. Scrolling up unpins it (and
823
+ * `isAtBottom` turns false, so a "scroll to latest" button can show); `scrollToBottom()`
824
+ * pins it again.
825
+ */
826
+ export declare function useChatScroll({ threshold }?: UseChatScrollOptions): UseChatScrollResult;
827
+ //#endregion
828
+ export { type AttachmentChipProps, type AttachmentListProps, type AttachmentRejection, type AttachmentRejectionReason, type AttachmentStatus, type ChatAnnouncerProps, type ChatAttachment, type ChatComposerProps, type ChatDemoProps, type ChatFeedback, type ChatLayoutProps, type ChatMessageProps, type ChatModel, type ChatRole, type CitationListProps, type CitationProps, type CitationSource, type CodeBlockProps, type ComposerAttachment, type FeedbackRating, type FeedbackReason, type FeedbackValue, type JsonViewProps, type MarkdownProps, type MessageFeedbackProps, type ModelCapability, type ModelPickerProps, type Suggestion, type SuggestionChipsProps, type ToolCallCardProps, type ToolCallStatus, type TypingIndicatorProps, type UseChatScrollOptions, type UseChatScrollResult, type ValidateFilesOptions, doc as attachmentListDoc, doc$1 as chatComposerDoc, doc$2 as chatDemoDoc, doc$3 as chatLayoutDoc, doc$4 as chatMessageDoc, doc$5 as citationDoc, doc$6 as markdownDoc, doc$7 as messageFeedbackDoc, doc$8 as modelPickerDoc, doc$9 as suggestionChipsDoc, doc$10 as toolCallCardDoc, doc$11 as typingIndicatorDoc };
829
+ //# sourceMappingURL=index.d.ts.map