@uipath/apollo-wind 2.69.0 → 2.70.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.
Files changed (53) hide show
  1. package/dist/components/custom/chat-first-experience.cjs +3 -3
  2. package/dist/components/custom/chat-first-experience.js +3 -3
  3. package/dist/components/custom/demo-composer.cjs +80 -0
  4. package/dist/components/custom/demo-composer.d.ts +11 -0
  5. package/dist/components/custom/demo-composer.js +46 -0
  6. package/dist/components/custom/panel-flow.cjs +2 -2
  7. package/dist/components/custom/panel-flow.js +2 -2
  8. package/dist/components/ui/chat-composer.cjs +429 -0
  9. package/dist/components/ui/chat-composer.d.ts +157 -0
  10. package/dist/components/ui/chat-composer.js +359 -0
  11. package/dist/components/ui/citation.cjs +188 -0
  12. package/dist/components/ui/citation.d.ts +42 -0
  13. package/dist/components/ui/citation.js +148 -0
  14. package/dist/components/ui/dropzone-overlay.cjs +142 -0
  15. package/dist/components/ui/dropzone-overlay.d.ts +27 -0
  16. package/dist/components/ui/dropzone-overlay.js +105 -0
  17. package/dist/components/ui/file-upload.cjs +5 -29
  18. package/dist/components/ui/file-upload.js +2 -26
  19. package/dist/components/ui/file-validation.cjs +91 -0
  20. package/dist/components/ui/file-validation.d.ts +24 -0
  21. package/dist/components/ui/file-validation.js +51 -0
  22. package/dist/components/ui/hover-card.cjs +15 -8
  23. package/dist/components/ui/hover-card.d.ts +4 -1
  24. package/dist/components/ui/hover-card.js +16 -9
  25. package/dist/components/ui/index.cjs +280 -214
  26. package/dist/components/ui/index.d.ts +6 -0
  27. package/dist/components/ui/index.js +6 -0
  28. package/dist/components/ui/input-group.cjs +1 -1
  29. package/dist/components/ui/input-group.d.ts +2 -1
  30. package/dist/components/ui/input-group.js +1 -1
  31. package/dist/components/ui/message-actions.cjs +302 -0
  32. package/dist/components/ui/message-actions.d.ts +102 -0
  33. package/dist/components/ui/message-actions.js +241 -0
  34. package/dist/components/ui/message.cjs +1 -1
  35. package/dist/components/ui/message.d.ts +2 -0
  36. package/dist/components/ui/message.js +1 -1
  37. package/dist/components/ui/sources.cjs +175 -0
  38. package/dist/components/ui/sources.d.ts +44 -0
  39. package/dist/components/ui/sources.js +132 -0
  40. package/dist/index.cjs +117 -6
  41. package/dist/index.d.ts +12 -0
  42. package/dist/index.js +7 -1
  43. package/dist/lib/index.cjs +8 -1
  44. package/dist/lib/index.d.ts +1 -0
  45. package/dist/lib/index.js +2 -1
  46. package/dist/lib/url.cjs +54 -0
  47. package/dist/lib/url.d.ts +8 -0
  48. package/dist/lib/url.js +17 -0
  49. package/dist/styles.css +157 -35
  50. package/package.json +1 -1
  51. package/dist/components/custom/chat-composer.cjs +0 -134
  52. package/dist/components/custom/chat-composer.d.ts +0 -14
  53. package/dist/components/custom/chat-composer.js +0 -100
@@ -0,0 +1,157 @@
1
+ import { type VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ import { type AttachmentState } from './attachment';
4
+ import { type ButtonProps } from './button';
5
+ import { type FileRejection, type FileValidationOptions } from './file-validation';
6
+ import { type InputGroupProps, type InputGroupTextareaProps } from './input-group';
7
+ /**
8
+ * The prompt input of a chat. `ChatComposer` is the form and owns the draft, the status and the
9
+ * attachments; its parts read them from context:
10
+ *
11
+ * ```tsx
12
+ * <ChatComposer onSubmit={send} status={status} onStop={stop}>
13
+ * <ChatComposerError />
14
+ * <ChatComposerInputGroup>
15
+ * <ChatComposerAttachments />
16
+ * <ChatComposerTextarea />
17
+ * <ChatComposerToolbar>
18
+ * <ChatComposerAttachButton onFiles={add} />
19
+ * <ChatComposerSubmit />
20
+ * </ChatComposerToolbar>
21
+ * </ChatComposerInputGroup>
22
+ * <ChatComposerFooter />
23
+ * </ChatComposer>
24
+ * ```
25
+ *
26
+ * Enter sends and Shift+Enter starts a new line. While `status` is `streaming` the submit button
27
+ * becomes a stop button and Enter does not send.
28
+ */
29
+ export interface ChatComposerStrings {
30
+ /** Accessible name of the textarea. */
31
+ label: string;
32
+ placeholder: string;
33
+ send: string;
34
+ stop: string;
35
+ attach: string;
36
+ removeAttachment: (name: string) => string;
37
+ dismissError: string;
38
+ }
39
+ export declare const DEFAULT_CHAT_COMPOSER_STRINGS: ChatComposerStrings;
40
+ export type ChatComposerStatus = 'idle' | 'streaming';
41
+ export type ChatComposerDensity = 'comfortable' | 'compact';
42
+ /** One chip in `ChatComposerAttachments`. The consumer owns the list and its upload states. */
43
+ export interface ChatComposerAttachmentItem {
44
+ id: string;
45
+ name: string;
46
+ /** Second line, such as the size, or the reason an upload failed. */
47
+ description?: React.ReactNode;
48
+ state?: AttachmentState;
49
+ /** Replaces the default file icon. */
50
+ icon?: React.ReactNode;
51
+ /** An image URL shown as a thumbnail instead of the icon. */
52
+ previewUrl?: string;
53
+ }
54
+ export interface ChatComposerSubmitDetails {
55
+ attachments: ChatComposerAttachmentItem[];
56
+ }
57
+ /** What `useChatComposer` gives a custom part. */
58
+ export interface ChatComposerContextValue {
59
+ value: string;
60
+ /** Replaces the draft, through `onValueChange` when controlled. */
61
+ setValue: (value: string) => void;
62
+ status: ChatComposerStatus;
63
+ density: ChatComposerDensity;
64
+ disabled: boolean;
65
+ strings: ChatComposerStrings;
66
+ attachments: ChatComposerAttachmentItem[];
67
+ onRemoveAttachment?: (attachment: ChatComposerAttachmentItem) => void;
68
+ onStop?: () => void;
69
+ canSubmit: boolean;
70
+ /** Sends the draft, if `canSubmit`. */
71
+ submit: () => void;
72
+ }
73
+ /** The enclosing `ChatComposer`'s state and actions, for custom parts. */
74
+ declare function useChatComposer(): ChatComposerContextValue;
75
+ declare const chatComposerVariants: (props?: ({
76
+ density?: "compact" | "comfortable" | null | undefined;
77
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
78
+ export interface ChatComposerProps extends Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit' | 'defaultValue'>, VariantProps<typeof chatComposerVariants> {
79
+ /** Controls the draft. Clear it yourself in `onSubmit`. */
80
+ value?: string;
81
+ defaultValue?: string;
82
+ /** Called on every edit, and with `''` when an uncontrolled draft clears after sending. */
83
+ onValueChange?: (value: string) => void;
84
+ /** Called with the draft when the user sends. An uncontrolled draft clears itself after. */
85
+ onSubmit?: (value: string, details: ChatComposerSubmitDetails) => void;
86
+ /** `streaming` turns the submit button into a stop button and holds back Enter. */
87
+ status?: ChatComposerStatus;
88
+ /**
89
+ * Called by the stop button while `status` is `streaming`. Without it, there is no stop button.
90
+ */
91
+ onStop?: () => void;
92
+ disabled?: boolean;
93
+ /** Holds back sending, by button and by Enter, while the textarea stays editable. */
94
+ submitDisabled?: boolean;
95
+ /**
96
+ * Files attached to the draft, rendered by `ChatComposerAttachments`. One still uploading or
97
+ * processing holds back sending.
98
+ */
99
+ attachments?: ChatComposerAttachmentItem[];
100
+ /** Adds a remove action to every attachment chip. */
101
+ onRemoveAttachment?: (attachment: ChatComposerAttachmentItem) => void;
102
+ /** Overrides for any subset of the English strings. */
103
+ strings?: Partial<ChatComposerStrings>;
104
+ }
105
+ declare const ChatComposer: React.ForwardRefExoticComponent<ChatComposerProps & React.RefAttributes<HTMLFormElement>>;
106
+ export interface ChatComposerInputGroupProps extends Omit<InputGroupProps, 'layout'> {
107
+ }
108
+ /** The field box: an `InputGroup` in block layout holding attachments, textarea and toolbar. */
109
+ declare const ChatComposerInputGroup: React.ForwardRefExoticComponent<ChatComposerInputGroupProps & React.RefAttributes<HTMLDivElement>>;
110
+ /** The draft lives on `ChatComposer`, so the textarea takes no `value` of its own. */
111
+ export interface ChatComposerTextareaProps extends Omit<InputGroupTextareaProps, 'value' | 'defaultValue'> {
112
+ }
113
+ declare const ChatComposerTextarea: React.ForwardRefExoticComponent<Omit<ChatComposerTextareaProps, "ref"> & React.RefAttributes<HTMLTextAreaElement>>;
114
+ export interface ChatComposerToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
115
+ }
116
+ /**
117
+ * The row of actions below the textarea. `ChatComposerSubmit` pushes itself right with `ml-auto`;
118
+ * to group another action with it, such as a mic button, give that action `ml-auto` and the
119
+ * submit button `ml-0`.
120
+ */
121
+ declare const ChatComposerToolbar: React.ForwardRefExoticComponent<ChatComposerToolbarProps & React.RefAttributes<HTMLDivElement>>;
122
+ export interface ChatComposerAttachButtonProps extends Omit<ButtonProps, 'onChange'>, FileValidationOptions {
123
+ /** Allows picking several files at once. Defaults to true. */
124
+ multiple?: boolean;
125
+ /**
126
+ * Called once per pick, with the files that passed the checks and those that did not. `maxFiles`
127
+ * counts the composer's attachments too, so it caps the draft rather than each pick.
128
+ */
129
+ onFiles?: (accepted: File[], rejected: FileRejection[]) => void;
130
+ }
131
+ declare const ChatComposerAttachButton: React.ForwardRefExoticComponent<ChatComposerAttachButtonProps & React.RefAttributes<HTMLButtonElement>>;
132
+ export interface ChatComposerSubmitProps extends ButtonProps {
133
+ }
134
+ /**
135
+ * Sends while idle and stops while streaming. Idle, it is disabled until there is text or an
136
+ * attachment to send, and while an attachment is busy or `submitDisabled` is set. Streaming
137
+ * without an `onStop`, it stays a disabled send button.
138
+ */
139
+ declare const ChatComposerSubmit: React.ForwardRefExoticComponent<ChatComposerSubmitProps & React.RefAttributes<HTMLButtonElement>>;
140
+ export interface ChatComposerAttachmentsProps extends React.HTMLAttributes<HTMLDivElement> {
141
+ }
142
+ /** The draft's attachments as a scrolling row of chips. Renders nothing when there are none. */
143
+ declare const ChatComposerAttachments: React.ForwardRefExoticComponent<ChatComposerAttachmentsProps & React.RefAttributes<HTMLDivElement>>;
144
+ declare const chatComposerErrorVariants: (props?: ({
145
+ variant?: "error" | "warning" | null | undefined;
146
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
147
+ export interface ChatComposerErrorProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof chatComposerErrorVariants> {
148
+ /** Adds a dismiss button. */
149
+ onDismiss?: () => void;
150
+ }
151
+ /** A message about the last send, such as a failed request or a rate limit. */
152
+ declare const ChatComposerError: React.ForwardRefExoticComponent<ChatComposerErrorProps & React.RefAttributes<HTMLDivElement>>;
153
+ export interface ChatComposerFooterProps extends React.HTMLAttributes<HTMLParagraphElement> {
154
+ }
155
+ /** Small muted text below the field, such as an AI disclaimer. */
156
+ declare const ChatComposerFooter: React.ForwardRefExoticComponent<ChatComposerFooterProps & React.RefAttributes<HTMLParagraphElement>>;
157
+ export { ChatComposer, ChatComposerAttachButton, ChatComposerAttachments, ChatComposerError, ChatComposerFooter, ChatComposerInputGroup, ChatComposerSubmit, ChatComposerTextarea, ChatComposerToolbar, chatComposerErrorVariants, chatComposerVariants, useChatComposer, };
@@ -0,0 +1,359 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { cva } from "class-variance-authority";
4
+ import { ArrowUp, CircleAlert, FileText, Paperclip, Square, TriangleAlert, X } from "lucide-react";
5
+ import { createContext, forwardRef, useCallback, useContext, useMemo, useRef, useState } from "react";
6
+ import { cn } from "../../lib/index.js";
7
+ import { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle } from "./attachment.js";
8
+ import { Button } from "./button.js";
9
+ import { validateFiles } from "./file-validation.js";
10
+ import { InputGroup, InputGroupBody, InputGroupButton, InputGroupRow, InputGroupTextarea } from "./input-group.js";
11
+ const DEFAULT_CHAT_COMPOSER_STRINGS = {
12
+ label: 'Message',
13
+ placeholder: 'Ask anything',
14
+ send: 'Send message',
15
+ stop: 'Stop generating',
16
+ attach: 'Attach files',
17
+ removeAttachment: (name)=>`Remove ${name}`,
18
+ dismissError: 'Dismiss'
19
+ };
20
+ const ChatComposerContext = /*#__PURE__*/ createContext(null);
21
+ function useChatComposerInternal() {
22
+ const context = useContext(ChatComposerContext);
23
+ if (!context) throw new Error('ChatComposer parts must be rendered inside <ChatComposer>.');
24
+ return context;
25
+ }
26
+ function useChatComposer() {
27
+ return useChatComposerInternal();
28
+ }
29
+ const chatComposerVariants = cva('flex w-full min-w-0 flex-col', {
30
+ variants: {
31
+ density: {
32
+ comfortable: 'gap-2',
33
+ compact: 'gap-1.5'
34
+ }
35
+ },
36
+ defaultVariants: {
37
+ density: 'comfortable'
38
+ }
39
+ });
40
+ const NO_ATTACHMENTS = [];
41
+ const ChatComposer = /*#__PURE__*/ forwardRef(({ className, children, value: valueProp, defaultValue, onValueChange, onSubmit, status = 'idle', onStop, disabled = false, submitDisabled = false, density, attachments = NO_ATTACHMENTS, onRemoveAttachment, strings, ...props }, ref)=>{
42
+ const resolvedDensity = density ?? 'comfortable';
43
+ const controlled = void 0 !== valueProp;
44
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue ?? '');
45
+ const value = controlled ? valueProp : uncontrolledValue;
46
+ const fileInputRef = useRef(null);
47
+ const onFilesRef = useRef(void 0);
48
+ const attachmentsBusy = attachments.some(({ state })=>'uploading' === state || 'processing' === state);
49
+ const canSubmit = !disabled && !submitDisabled && !attachmentsBusy && 'idle' === status && ('' !== value.trim() || attachments.length > 0);
50
+ const setValue = useCallback((next)=>{
51
+ if (!controlled) setUncontrolledValue(next);
52
+ onValueChange?.(next);
53
+ }, [
54
+ controlled,
55
+ onValueChange
56
+ ]);
57
+ const submit = useCallback(()=>{
58
+ if (!canSubmit) return;
59
+ onSubmit?.(value, {
60
+ attachments
61
+ });
62
+ if (!controlled) setValue('');
63
+ }, [
64
+ canSubmit,
65
+ onSubmit,
66
+ value,
67
+ attachments,
68
+ controlled,
69
+ setValue
70
+ ]);
71
+ const openFilePicker = useCallback(({ accept, multiple = true, onFiles })=>{
72
+ const input = fileInputRef.current;
73
+ if (!input) return;
74
+ input.accept = accept ?? '';
75
+ input.multiple = multiple;
76
+ onFilesRef.current = onFiles;
77
+ input.click();
78
+ }, []);
79
+ const text = useMemo(()=>({
80
+ ...DEFAULT_CHAT_COMPOSER_STRINGS,
81
+ ...strings
82
+ }), [
83
+ strings
84
+ ]);
85
+ const context = useMemo(()=>({
86
+ value,
87
+ setValue,
88
+ status,
89
+ density: resolvedDensity,
90
+ disabled,
91
+ strings: text,
92
+ attachments,
93
+ onRemoveAttachment,
94
+ onStop,
95
+ canSubmit,
96
+ submit,
97
+ openFilePicker
98
+ }), [
99
+ value,
100
+ setValue,
101
+ status,
102
+ resolvedDensity,
103
+ disabled,
104
+ text,
105
+ attachments,
106
+ onRemoveAttachment,
107
+ onStop,
108
+ canSubmit,
109
+ submit,
110
+ openFilePicker
111
+ ]);
112
+ return /*#__PURE__*/ jsx(ChatComposerContext.Provider, {
113
+ value: context,
114
+ children: /*#__PURE__*/ jsxs("form", {
115
+ ref: ref,
116
+ "data-slot": "chat-composer",
117
+ "data-status": status,
118
+ "data-density": resolvedDensity,
119
+ "data-disabled": disabled ? '' : void 0,
120
+ className: cn(chatComposerVariants({
121
+ density: resolvedDensity
122
+ }), className),
123
+ onSubmit: (event)=>{
124
+ event.preventDefault();
125
+ submit();
126
+ },
127
+ ...props,
128
+ children: [
129
+ children,
130
+ /*#__PURE__*/ jsx("input", {
131
+ ref: fileInputRef,
132
+ type: "file",
133
+ hidden: true,
134
+ tabIndex: -1,
135
+ "data-slot": "chat-composer-file-input",
136
+ disabled: disabled,
137
+ onChange: (event)=>{
138
+ const files = Array.from(event.target.files ?? []);
139
+ event.target.value = '';
140
+ if (files.length > 0) onFilesRef.current?.(files);
141
+ }
142
+ })
143
+ ]
144
+ })
145
+ });
146
+ });
147
+ ChatComposer.displayName = 'ChatComposer';
148
+ const FOCUS_RING_CLASS = 'has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot][aria-invalid=true]]:has-[[data-slot=input-group-control]:focus-visible]:ring-error future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-2 future:has-[[data-slot=input-group-control]:focus-visible]:ring-offset-background';
149
+ const ChatComposerInputGroup = /*#__PURE__*/ forwardRef(({ className, disabled, invalid, error, ...props }, ref)=>{
150
+ const composer = useChatComposer();
151
+ return /*#__PURE__*/ jsx(InputGroup, {
152
+ ref: ref,
153
+ layout: "block",
154
+ disabled: disabled || composer.disabled,
155
+ invalid: invalid,
156
+ error: error,
157
+ className: cn(FOCUS_RING_CLASS, invalid || error ? 'has-[[data-slot=input-group-control]:focus-visible]:ring-error' : 'has-[[data-slot=input-group-control]:focus-visible]:ring-ring future:has-[[data-slot=input-group-control]:focus-visible]:ring-primary', className),
158
+ ...props
159
+ });
160
+ });
161
+ ChatComposerInputGroup.displayName = 'ChatComposerInputGroup';
162
+ const ChatComposerTextarea = /*#__PURE__*/ forwardRef(({ className, minRows, maxRows = 6, placeholder, disabled, onChange, onKeyDown, 'aria-label': ariaLabel, ...props }, ref)=>{
163
+ const composer = useChatComposer();
164
+ const rows = minRows ?? ('compact' === composer.density ? 1 : 2);
165
+ return /*#__PURE__*/ jsx(InputGroupRow, {
166
+ className: cn('has-[[data-slot=input-group-control]:focus-visible]:ring-0 has-[[data-slot=input-group-control]_:focus-visible]:ring-0', 'compact' === composer.density ? 'min-h-0 py-1 future:min-h-0' : 'py-2'),
167
+ children: /*#__PURE__*/ jsx(InputGroupTextarea, {
168
+ ref: ref,
169
+ rows: rows,
170
+ minRows: rows,
171
+ maxRows: maxRows,
172
+ "aria-label": ariaLabel ?? composer.strings.label,
173
+ placeholder: placeholder ?? composer.strings.placeholder,
174
+ disabled: disabled || composer.disabled,
175
+ value: composer.value,
176
+ onChange: (event)=>{
177
+ onChange?.(event);
178
+ composer.setValue(event.target.value);
179
+ },
180
+ onKeyDown: (event)=>{
181
+ onKeyDown?.(event);
182
+ if (event.defaultPrevented || 'Enter' !== event.key || event.shiftKey) return;
183
+ if (event.nativeEvent.isComposing || 229 === event.keyCode) return;
184
+ event.preventDefault();
185
+ composer.submit();
186
+ },
187
+ className: className,
188
+ ...props
189
+ })
190
+ });
191
+ });
192
+ ChatComposerTextarea.displayName = 'ChatComposerTextarea';
193
+ const ChatComposerToolbar = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>{
194
+ const { density } = useChatComposer();
195
+ return /*#__PURE__*/ jsx(InputGroupBody, {
196
+ ref: ref,
197
+ "data-slot": "chat-composer-toolbar",
198
+ className: cn('flex min-w-0 items-center gap-1', 'compact' === density ? 'px-1.5 py-1' : 'px-2 py-1.5', className),
199
+ ...props
200
+ });
201
+ });
202
+ ChatComposerToolbar.displayName = 'ChatComposerToolbar';
203
+ const ChatComposerAttachButton = /*#__PURE__*/ forwardRef(({ accept, maxSize, maxFiles, multiple = true, onFiles, onClick, children, disabled, ...props }, ref)=>{
204
+ const composer = useChatComposerInternal();
205
+ const openPicker = ()=>{
206
+ const remaining = void 0 === maxFiles ? void 0 : Math.max(0, maxFiles - composer.attachments.length);
207
+ composer.openFilePicker({
208
+ accept: Array.isArray(accept) ? accept.join(',') : accept,
209
+ multiple,
210
+ onFiles: (files)=>{
211
+ const { accepted, rejected } = validateFiles(files, {
212
+ accept,
213
+ maxSize,
214
+ maxFiles: remaining
215
+ });
216
+ onFiles?.(accepted, rejected);
217
+ }
218
+ });
219
+ };
220
+ return /*#__PURE__*/ jsx(InputGroupButton, {
221
+ ref: ref,
222
+ "data-slot": "chat-composer-attach",
223
+ icon: true,
224
+ size: 'compact' === composer.density ? '3xs' : '2xs',
225
+ "aria-label": composer.strings.attach,
226
+ disabled: disabled || composer.disabled,
227
+ onClick: (event)=>{
228
+ onClick?.(event);
229
+ if (!event.defaultPrevented) openPicker();
230
+ },
231
+ ...props,
232
+ children: children ?? /*#__PURE__*/ jsx(Paperclip, {})
233
+ });
234
+ });
235
+ ChatComposerAttachButton.displayName = 'ChatComposerAttachButton';
236
+ const ChatComposerSubmit = /*#__PURE__*/ forwardRef(({ className, onClick, children, disabled, ...props }, ref)=>{
237
+ const composer = useChatComposer();
238
+ const stoppable = 'streaming' === composer.status && void 0 !== composer.onStop;
239
+ return /*#__PURE__*/ jsx(InputGroupButton, {
240
+ ref: ref,
241
+ "data-slot": "chat-composer-submit",
242
+ "data-status": composer.status,
243
+ type: stoppable ? 'button' : 'submit',
244
+ variant: stoppable ? 'ghost' : 'default',
245
+ icon: true,
246
+ size: 'compact' === composer.density ? '3xs' : '2xs',
247
+ "aria-label": stoppable ? composer.strings.stop : composer.strings.send,
248
+ disabled: disabled || composer.disabled || !stoppable && !composer.canSubmit,
249
+ onClick: (event)=>{
250
+ onClick?.(event);
251
+ if (stoppable && !event.defaultPrevented) composer.onStop?.();
252
+ },
253
+ className: cn('ml-auto', className),
254
+ ...props,
255
+ children: children ?? (stoppable ? /*#__PURE__*/ jsx(Square, {
256
+ className: "fill-current"
257
+ }) : /*#__PURE__*/ jsx(ArrowUp, {}))
258
+ });
259
+ });
260
+ ChatComposerSubmit.displayName = 'ChatComposerSubmit';
261
+ const ChatComposerAttachments = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>{
262
+ const { attachments, onRemoveAttachment, strings, disabled, density } = useChatComposer();
263
+ if (0 === attachments.length) return null;
264
+ return /*#__PURE__*/ jsx(AttachmentGroup, {
265
+ ref: ref,
266
+ "data-slot": "chat-composer-attachments",
267
+ className: cn('compact' === density ? 'px-2 pt-1.5' : 'px-2.5 pt-2.5', className),
268
+ ...props,
269
+ children: attachments.map((attachment)=>{
270
+ const state = attachment.state ?? 'done';
271
+ return /*#__PURE__*/ jsxs(Attachment, {
272
+ size: 'compact' === density ? 'xs' : 'sm',
273
+ state: state,
274
+ "aria-busy": 'uploading' === state || 'processing' === state || void 0,
275
+ children: [
276
+ /*#__PURE__*/ jsx(AttachmentMedia, {
277
+ variant: attachment.previewUrl ? 'image' : 'icon',
278
+ children: attachment.previewUrl ? /*#__PURE__*/ jsx("img", {
279
+ src: attachment.previewUrl,
280
+ alt: ""
281
+ }) : attachment.icon ?? ('error' === state ? /*#__PURE__*/ jsx(CircleAlert, {}) : /*#__PURE__*/ jsx(FileText, {}))
282
+ }),
283
+ /*#__PURE__*/ jsxs(AttachmentContent, {
284
+ children: [
285
+ /*#__PURE__*/ jsx(AttachmentTitle, {
286
+ children: attachment.name
287
+ }),
288
+ attachment.description && /*#__PURE__*/ jsx(AttachmentDescription, {
289
+ children: attachment.description
290
+ })
291
+ ]
292
+ }),
293
+ onRemoveAttachment && /*#__PURE__*/ jsx(AttachmentActions, {
294
+ children: /*#__PURE__*/ jsx(AttachmentAction, {
295
+ "aria-label": strings.removeAttachment(attachment.name),
296
+ disabled: disabled,
297
+ onClick: ()=>onRemoveAttachment(attachment),
298
+ children: /*#__PURE__*/ jsx(X, {})
299
+ })
300
+ })
301
+ ]
302
+ }, attachment.id);
303
+ })
304
+ });
305
+ });
306
+ ChatComposerAttachments.displayName = 'ChatComposerAttachments';
307
+ const chatComposerErrorVariants = cva("flex items-start gap-2 rounded-lg border px-3 py-2 text-xs leading-4 text-foreground [&>svg:not([class*='size-'])]:mt-px [&>svg:not([class*='size-'])]:size-3.5 [&>svg]:shrink-0", {
308
+ variants: {
309
+ variant: {
310
+ error: 'border-error/50 bg-error-background/25 [&>svg]:text-error',
311
+ warning: 'border-warning/50 bg-warning-background/25 [&>svg]:text-warning'
312
+ }
313
+ },
314
+ defaultVariants: {
315
+ variant: 'error'
316
+ }
317
+ });
318
+ const ChatComposerError = /*#__PURE__*/ forwardRef(({ className, variant, onDismiss, children, ...props }, ref)=>{
319
+ const { strings } = useChatComposer();
320
+ const resolved = variant ?? 'error';
321
+ const Icon = 'warning' === resolved ? TriangleAlert : CircleAlert;
322
+ return /*#__PURE__*/ jsxs("div", {
323
+ ref: ref,
324
+ role: "alert",
325
+ "data-slot": "chat-composer-error",
326
+ "data-variant": resolved,
327
+ className: cn(chatComposerErrorVariants({
328
+ variant: resolved
329
+ }), className),
330
+ ...props,
331
+ children: [
332
+ /*#__PURE__*/ jsx(Icon, {
333
+ "aria-hidden": "true"
334
+ }),
335
+ /*#__PURE__*/ jsx("div", {
336
+ className: "min-w-0 flex-1",
337
+ children: children
338
+ }),
339
+ onDismiss && /*#__PURE__*/ jsx(Button, {
340
+ variant: "ghost",
341
+ size: "4xs",
342
+ icon: true,
343
+ "aria-label": strings.dismissError,
344
+ className: "-my-0.5 shrink-0",
345
+ onClick: onDismiss,
346
+ children: /*#__PURE__*/ jsx(X, {})
347
+ })
348
+ ]
349
+ });
350
+ });
351
+ ChatComposerError.displayName = 'ChatComposerError';
352
+ const ChatComposerFooter = /*#__PURE__*/ forwardRef(({ className, ...props }, ref)=>/*#__PURE__*/ jsx("p", {
353
+ ref: ref,
354
+ "data-slot": "chat-composer-footer",
355
+ className: cn('px-1 text-center text-xs text-muted-foreground', className),
356
+ ...props
357
+ }));
358
+ ChatComposerFooter.displayName = 'ChatComposerFooter';
359
+ export { ChatComposer, ChatComposerAttachButton, ChatComposerAttachments, ChatComposerError, ChatComposerFooter, ChatComposerInputGroup, ChatComposerSubmit, ChatComposerTextarea, ChatComposerToolbar, DEFAULT_CHAT_COMPOSER_STRINGS, chatComposerErrorVariants, chatComposerVariants, useChatComposer };