@moldable-ai/ui 0.2.7 → 0.2.9

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 (44) hide show
  1. package/dist/components/app-error-boundary.d.ts +26 -0
  2. package/dist/components/app-error-boundary.d.ts.map +1 -0
  3. package/dist/components/app-error-boundary.js +87 -0
  4. package/dist/components/chat/chat-input.d.ts +9 -1
  5. package/dist/components/chat/chat-input.d.ts.map +1 -1
  6. package/dist/components/chat/chat-input.js +13 -4
  7. package/dist/components/chat/chat-message.d.ts +6 -0
  8. package/dist/components/chat/chat-message.d.ts.map +1 -1
  9. package/dist/components/chat/chat-message.js +576 -157
  10. package/dist/components/chat/chat-messages.d.ts +2 -1
  11. package/dist/components/chat/chat-messages.d.ts.map +1 -1
  12. package/dist/components/chat/chat-messages.js +3 -3
  13. package/dist/components/chat/chat-panel.d.ts +25 -3
  14. package/dist/components/chat/chat-panel.d.ts.map +1 -1
  15. package/dist/components/chat/chat-panel.js +173 -49
  16. package/dist/components/chat/index.d.ts +3 -3
  17. package/dist/components/chat/index.d.ts.map +1 -1
  18. package/dist/components/chat/index.js +1 -1
  19. package/dist/components/chat/model-selector.d.ts.map +1 -1
  20. package/dist/components/chat/model-selector.js +1 -1
  21. package/dist/components/chat/tool-handlers.d.ts.map +1 -1
  22. package/dist/components/chat/tool-handlers.js +89 -1
  23. package/dist/components/markdown.d.ts.map +1 -1
  24. package/dist/components/markdown.js +18 -4
  25. package/dist/components/rich-media-player.d.ts +8 -0
  26. package/dist/components/rich-media-player.d.ts.map +1 -0
  27. package/dist/components/rich-media-player.js +99 -0
  28. package/dist/components/ui/command.d.ts +2 -1
  29. package/dist/components/ui/command.d.ts.map +1 -1
  30. package/dist/components/ui/command.js +2 -2
  31. package/dist/components/ui/resizable.d.ts +4 -1
  32. package/dist/components/ui/resizable.d.ts.map +1 -1
  33. package/dist/components/ui/resizable.js +1 -1
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +4 -1
  37. package/dist/lib/commands.d.ts +8 -0
  38. package/dist/lib/commands.d.ts.map +1 -1
  39. package/dist/lib/commands.js +18 -0
  40. package/package.json +17 -14
  41. package/src/styles/index.css +25 -0
  42. package/dist/lib/commands.test.d.ts +0 -2
  43. package/dist/lib/commands.test.d.ts.map +0 -1
  44. package/dist/lib/commands.test.js +0 -111
@@ -0,0 +1,26 @@
1
+ import { Component, type ErrorInfo, type ReactNode } from 'react';
2
+ type ErrorSource = 'react' | 'window' | 'promise';
3
+ interface AppErrorBoundaryProps {
4
+ appName: string;
5
+ children: ReactNode;
6
+ surface?: 'app' | 'widget';
7
+ }
8
+ interface AppErrorBoundaryState {
9
+ error: Error | null;
10
+ source: ErrorSource;
11
+ componentStack: string | null;
12
+ }
13
+ export declare class AppErrorBoundary extends Component<AppErrorBoundaryProps, AppErrorBoundaryState> {
14
+ state: AppErrorBoundaryState;
15
+ static getDerivedStateFromError(error: Error): Partial<AppErrorBoundaryState>;
16
+ componentDidMount(): void;
17
+ componentWillUnmount(): void;
18
+ componentDidCatch(error: Error, info: ErrorInfo): void;
19
+ private handleWindowError;
20
+ private handleUnhandledRejection;
21
+ private reload;
22
+ private askMoldable;
23
+ render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
24
+ }
25
+ export {};
26
+ //# sourceMappingURL=app-error-boundary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error-boundary.d.ts","sourceRoot":"","sources":["../../src/components/app-error-boundary.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAGjE,KAAK,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAA;AAEjD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,SAAS,CAAA;IACnB,OAAO,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;CAC3B;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAiCD,qBAAa,gBAAiB,SAAQ,SAAS,CAC7C,qBAAqB,EACrB,qBAAqB,CACtB;IACC,KAAK,EAAE,qBAAqB,CAI3B;IAED,MAAM,CAAC,wBAAwB,CAC7B,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,qBAAqB,CAAC;IAIjC,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAU5B,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI;IAKtD,OAAO,CAAC,iBAAiB,CAKxB;IAED,OAAO,CAAC,wBAAwB,CAI/B;IAED,OAAO,CAAC,MAAM,CAEb;IAED,OAAO,CAAC,WAAW,CAclB;IAED,MAAM;CA8CP"}
@@ -0,0 +1,87 @@
1
+ 'use client';
2
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
3
+ import { MessageSquareWarning, RefreshCw } from 'lucide-react';
4
+ import { Component } from 'react';
5
+ import { Button } from './ui/button';
6
+ function toError(value) {
7
+ if (value instanceof Error)
8
+ return value;
9
+ if (typeof value === 'string')
10
+ return new Error(value);
11
+ try {
12
+ return new Error(JSON.stringify(value));
13
+ }
14
+ catch {
15
+ return new Error(String(value));
16
+ }
17
+ }
18
+ function formatError(error, source, componentStack) {
19
+ const parts = [`${error.name}: ${error.message}`];
20
+ if (error.stack) {
21
+ parts.push(error.stack);
22
+ }
23
+ if (componentStack) {
24
+ parts.push(`React component stack:${componentStack}`);
25
+ }
26
+ parts.push(`Source: ${source}`);
27
+ return parts.join('\n\n');
28
+ }
29
+ export class AppErrorBoundary extends Component {
30
+ state = {
31
+ error: null,
32
+ source: 'react',
33
+ componentStack: null,
34
+ };
35
+ static getDerivedStateFromError(error) {
36
+ return { error, source: 'react' };
37
+ }
38
+ componentDidMount() {
39
+ if (typeof window === 'undefined')
40
+ return;
41
+ window.addEventListener('error', this.handleWindowError);
42
+ window.addEventListener('unhandledrejection', this.handleUnhandledRejection);
43
+ }
44
+ componentWillUnmount() {
45
+ if (typeof window === 'undefined')
46
+ return;
47
+ window.removeEventListener('error', this.handleWindowError);
48
+ window.removeEventListener('unhandledrejection', this.handleUnhandledRejection);
49
+ }
50
+ componentDidCatch(error, info) {
51
+ console.error(`${this.props.appName} UI crashed:`, error, info);
52
+ this.setState({ componentStack: info.componentStack ?? null });
53
+ }
54
+ handleWindowError = (event) => {
55
+ const error = event.error instanceof Error ? event.error : new Error(event.message);
56
+ console.error(`${this.props.appName} uncaught frontend error:`, error);
57
+ this.setState({ error, source: 'window', componentStack: null });
58
+ };
59
+ handleUnhandledRejection = (event) => {
60
+ const error = toError(event.reason);
61
+ console.error(`${this.props.appName} unhandled promise rejection:`, error);
62
+ this.setState({ error, source: 'promise', componentStack: null });
63
+ };
64
+ reload = () => {
65
+ window.location.reload();
66
+ };
67
+ askMoldable = () => {
68
+ const { error, source, componentStack } = this.state;
69
+ if (!error)
70
+ return;
71
+ const surfaceLabel = this.props.surface === 'widget' ? ' widget' : ' full app';
72
+ const errorReport = formatError(error, source, componentStack);
73
+ const text = [
74
+ `${this.props.appName}${surfaceLabel} hit an uncaught frontend error.`,
75
+ 'Please inspect and fix the client crash.',
76
+ errorReport,
77
+ ].join('\n\n');
78
+ window.parent.postMessage({ type: 'moldable:set-chat-input', text }, '*');
79
+ };
80
+ render() {
81
+ const { error, source, componentStack } = this.state;
82
+ if (!error)
83
+ return this.props.children;
84
+ const errorSummary = formatError(error, source, componentStack);
85
+ return (_jsx("main", { className: "bg-background text-foreground flex min-h-screen items-center justify-center p-4 sm:p-6", children: _jsxs("section", { className: "border-border bg-card w-full max-w-xl rounded-lg border p-5 shadow-lg sm:p-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("h1", { className: "text-xl font-semibold tracking-tight", children: [this.props.appName, " hit a UI error"] }), _jsx("p", { className: "text-muted-foreground text-sm leading-6", children: "Reload to recover, or send the captured client error to Moldable so it can inspect the crash." })] }), _jsx("pre", { className: "bg-muted text-muted-foreground mt-5 max-h-44 overflow-auto whitespace-pre-wrap rounded-md border p-3 font-mono text-xs", children: errorSummary }), _jsxs("div", { className: "mt-5 flex flex-col gap-2 sm:flex-row", children: [_jsxs(Button, { type: "button", className: "cursor-pointer", onClick: this.reload, children: [_jsx(RefreshCw, {}), "Reload"] }), _jsxs(Button, { type: "button", variant: "secondary", className: "cursor-pointer", onClick: this.askMoldable, children: [_jsx(MessageSquareWarning, {}), "Ask Moldable to fix this"] })] })] }) }));
86
+ }
87
+ }
@@ -1,5 +1,10 @@
1
1
  import type { ChangeEvent, FormEvent, ReactNode, RefObject } from 'react';
2
2
  export type ChatSubmitMode = 'send' | 'steer' | 'queue';
3
+ export type ChatSlashCommandOption = {
4
+ id: string;
5
+ name: string;
6
+ description: string;
7
+ };
3
8
  export type ChatImageAttachment = {
4
9
  id: string;
5
10
  name: string;
@@ -20,7 +25,10 @@ type ChatInputProps = {
20
25
  onRemoveImageAttachment?: (id: string) => void;
21
26
  footerStartControls?: ReactNode;
22
27
  footerControls?: ReactNode;
28
+ submitDisabled?: boolean;
29
+ slashCommands?: ChatSlashCommandOption[];
30
+ onSlashCommandSelect?: (command: ChatSlashCommandOption) => void;
23
31
  };
24
- export declare function ChatInput({ input, onInputChange, onSubmit, isResponding, placeholder, inputRef, onStop, compact, imageAttachments, onRemoveImageAttachment, footerStartControls, footerControls, }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
32
+ export declare function ChatInput({ input, onInputChange, onSubmit, isResponding, placeholder, inputRef, onStop, compact, imageAttachments, onRemoveImageAttachment, footerStartControls, footerControls, submitDisabled, slashCommands, onSlashCommandSelect, }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
25
33
  export {};
26
34
  //# sourceMappingURL=chat-input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-input.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGT,SAAS,EACT,SAAS,EACV,MAAM,OAAO,CAAA;AAKd,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAEvD,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAC5D,QAAQ,EAAE,CACR,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,SAAS,EACzC,IAAI,CAAC,EAAE,cAAc,KAClB,IAAI,CAAA;IACT,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACxC,uBAAuB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,mBAAmB,CAAC,EAAE,SAAS,CAAA;IAC/B,cAAc,CAAC,EAAE,SAAS,CAAA;CAC3B,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAA+B,EAC/B,QAAQ,EACR,MAAM,EACN,OAAe,EACf,gBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,GACf,EAAE,cAAc,2CA6IhB"}
1
+ {"version":3,"file":"chat-input.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EAGT,SAAS,EACT,SAAS,EACV,MAAM,OAAO,CAAA;AAKd,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAEvD,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,mBAAmB,CAAC,KAAK,IAAI,CAAA;IAC5D,QAAQ,EAAE,CACR,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,SAAS,EACzC,IAAI,CAAC,EAAE,cAAc,KAClB,IAAI,CAAA;IACT,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAA;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gBAAgB,CAAC,EAAE,mBAAmB,EAAE,CAAA;IACxC,uBAAuB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9C,mBAAmB,CAAC,EAAE,SAAS,CAAA;IAC/B,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,aAAa,CAAC,EAAE,sBAAsB,EAAE,CAAA;IACxC,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAA;CACjE,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,WAA+B,EAC/B,QAAQ,EACR,MAAM,EACN,OAAe,EACf,gBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,cAAsB,EACtB,aAAkB,EAClB,oBAAoB,GACrB,EAAE,cAAc,2CA2KhB"}
@@ -1,12 +1,12 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ArrowUp, Image as ImageIcon, Square, X } from 'lucide-react';
3
3
  import { cn } from '../../lib/utils';
4
4
  import { Button } from '../ui/button';
5
5
  import { Textarea } from '../ui/textarea';
6
- export function ChatInput({ input, onInputChange, onSubmit, isResponding, placeholder = 'Ask anything...', inputRef, onStop, compact = false, imageAttachments = [], onRemoveImageAttachment, footerStartControls, footerControls, }) {
6
+ export function ChatInput({ input, onInputChange, onSubmit, isResponding, placeholder = 'Ask anything...', inputRef, onStop, compact = false, imageAttachments = [], onRemoveImageAttachment, footerStartControls, footerControls, submitDisabled = false, slashCommands = [], onSlashCommandSelect, }) {
7
7
  const hasInput = input.trim().length > 0;
8
8
  const hasAttachments = imageAttachments.length > 0;
9
- const canSubmit = hasInput || hasAttachments;
9
+ const canSubmit = !submitDisabled && (hasInput || hasAttachments);
10
10
  const handleKeyDown = (e) => {
11
11
  if (e.key === 'Enter') {
12
12
  if (e.shiftKey) {
@@ -41,7 +41,16 @@ export function ChatInput({ input, onInputChange, onSubmit, isResponding, placeh
41
41
  }
42
42
  // If type="submit", form handles submission
43
43
  };
44
- return (_jsx("div", { className: cn('isolate w-full p-2'), "data-chat-input-wrapper": true, children: _jsx("div", { className: "mx-auto max-w-5xl", children: _jsx("form", { onSubmit: (e) => onSubmit(e, isResponding ? 'queue' : 'send'), children: _jsxs("div", { className: cn('bg-background relative flex w-full flex-col rounded-3xl border', compact && !hasAttachments && 'h-14'), children: [!compact && hasAttachments && (_jsx("div", { className: "flex max-h-32 gap-2 overflow-x-auto px-3 pt-3", children: imageAttachments.map((attachment) => (_jsxs("div", { className: "bg-muted/70 border-border flex max-w-48 shrink-0 items-center gap-2 rounded-xl border p-1.5 pr-2", children: [_jsx("div", { className: "bg-background flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border", children: attachment.previewUrl ? (_jsx("img", { src: attachment.previewUrl, alt: "", className: "size-full object-cover", draggable: false })) : (_jsx(ImageIcon, { className: "text-muted-foreground size-4" })) }), _jsx("span", { className: "min-w-0 truncate text-xs font-medium", title: attachment.path, children: attachment.name }), onRemoveImageAttachment && (_jsx("button", { type: "button", onClick: () => onRemoveImageAttachment(attachment.id), className: "text-muted-foreground hover:bg-accent hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors", "aria-label": `Remove ${attachment.name}`, children: _jsx(X, { className: "size-3.5" }) }))] }, attachment.id))) })), _jsx("div", { className: cn('w-full px-5', compact ? 'py-4' : 'pb-2 pt-4'), children: _jsx(Textarea, { ref: inputRef, value: input, placeholder: placeholder, onChange: onInputChange, onKeyDown: handleKeyDown, className: cn('max-h-32 min-h-[24px] resize-none rounded-none border-0 !bg-transparent p-0 text-sm shadow-none focus:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:!bg-transparent', compact && 'max-h-6 min-h-6') }) }), !compact && (_jsxs("div", { className: "flex min-h-11 items-center justify-between gap-3 px-3 pb-3", children: [_jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-start gap-1", children: footerStartControls }), _jsx("div", { className: "min-w-0 flex-1" }), _jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-end gap-1.5", children: footerControls }), _jsxs(Button, { type: showStopButton ? 'button' : 'submit', size: "icon", className: "bg-primary text-primary-foreground size-8 cursor-pointer rounded-full hover:opacity-70 disabled:opacity-30", disabled: !canSubmit && !isResponding, onClick: handleButtonClick, children: [showStopButton ? (_jsx(Square, { className: "fill-primary-foreground size-4 animate-pulse" })) : (_jsx(ArrowUp, { className: "size-4" })), _jsx("span", { className: "sr-only", children: showStopButton
44
+ return (_jsx("div", { className: cn('isolate w-full p-2'), "data-chat-input-wrapper": true, children: _jsx("div", { className: "mx-auto max-w-5xl", children: _jsx("form", { onSubmit: (e) => {
45
+ if (submitDisabled && !isResponding) {
46
+ e.preventDefault();
47
+ return;
48
+ }
49
+ onSubmit(e, isResponding ? 'queue' : 'send');
50
+ }, children: _jsxs("div", { className: cn('bg-background relative flex w-full flex-col rounded-3xl border', compact && !hasAttachments && 'h-14'), children: [!compact && slashCommands.length > 0 && (_jsx("div", { className: "border-border bg-popover text-popover-foreground absolute bottom-full left-4 right-4 z-20 mb-2 overflow-hidden rounded-lg border shadow-lg", children: slashCommands.map((command) => (_jsxs("button", { type: "button", className: "hover:bg-accent hover:text-accent-foreground flex min-h-12 w-full cursor-pointer items-center gap-3 px-3 py-2.5 text-left transition-colors", onMouseDown: (event) => {
51
+ event.preventDefault();
52
+ onSlashCommandSelect?.(command);
53
+ }, children: [_jsxs("span", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: ["/", command.name] }), _jsx("span", { className: "min-w-0 text-xs", children: command.description })] }, command.id))) })), !compact && hasAttachments && (_jsx("div", { className: "flex max-h-32 gap-2 overflow-x-auto px-3 pt-3", children: imageAttachments.map((attachment) => (_jsxs("div", { className: "bg-muted/70 border-border flex max-w-48 shrink-0 items-center gap-2 rounded-xl border p-1.5 pr-2", children: [_jsx("div", { className: "bg-background flex size-9 shrink-0 items-center justify-center overflow-hidden rounded-lg border", children: attachment.previewUrl ? (_jsx("img", { src: attachment.previewUrl, alt: "", className: "size-full object-cover", draggable: false })) : (_jsx(ImageIcon, { className: "text-muted-foreground size-4" })) }), _jsx("span", { className: "min-w-0 truncate text-xs font-medium", title: attachment.path, children: attachment.name }), onRemoveImageAttachment && (_jsx("button", { type: "button", onClick: () => onRemoveImageAttachment(attachment.id), className: "text-muted-foreground hover:bg-accent hover:text-foreground flex size-6 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors", "aria-label": `Remove ${attachment.name}`, children: _jsx(X, { className: "size-3.5" }) }))] }, attachment.id))) })), _jsx("div", { className: cn('w-full px-5', compact ? 'py-4' : 'pb-2 pt-4'), children: _jsx(Textarea, { ref: inputRef, value: input, placeholder: placeholder, onChange: onInputChange, onKeyDown: handleKeyDown, className: cn('max-h-32 min-h-[24px] resize-none rounded-none border-0 !bg-transparent p-0 text-sm shadow-none focus:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 dark:!bg-transparent', compact && 'max-h-6 min-h-6') }) }), !compact && (_jsxs("div", { className: "flex min-h-11 items-center justify-between gap-3 px-3 pb-3", children: [_jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-start gap-1", children: footerStartControls }), _jsx("div", { className: "min-w-0 flex-1" }), _jsx("div", { className: "flex min-w-0 shrink-0 items-center justify-end gap-0.5", children: footerControls }), _jsxs(Button, { type: showStopButton ? 'button' : 'submit', size: "icon", className: "bg-primary text-primary-foreground size-8 cursor-pointer rounded-full hover:opacity-70 disabled:opacity-30", disabled: !canSubmit && !isResponding, onClick: handleButtonClick, children: [showStopButton ? (_jsx(Square, { className: "fill-primary-foreground size-4 animate-pulse" })) : (_jsx(ArrowUp, { className: "size-4" })), _jsx("span", { className: "sr-only", children: showStopButton
45
54
  ? 'Stop generating'
46
55
  : isResponding
47
56
  ? 'Steer response'
@@ -27,6 +27,11 @@ export type ChatMessage = {
27
27
  role: 'user' | 'assistant' | 'system';
28
28
  content?: string;
29
29
  parts?: ChatMessagePart[];
30
+ turn?: {
31
+ userMessageId?: string;
32
+ startedAtMs?: number;
33
+ completedAtMs?: number;
34
+ };
30
35
  };
31
36
  type MessageProps = {
32
37
  message: ChatMessage;
@@ -36,5 +41,6 @@ type MessageProps = {
36
41
  declare function PureMessage({ message, isLast, isStreaming, }: MessageProps): import("react/jsx-runtime").JSX.Element;
37
42
  export declare const Message: import("react").MemoExoticComponent<typeof PureMessage>;
38
43
  export declare function ThinkingMessage(): import("react/jsx-runtime").JSX.Element;
44
+ export declare function CompactingMessage(): import("react/jsx-runtime").JSX.Element;
39
45
  export {};
40
46
  //# sourceMappingURL=chat-message.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"chat-message.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-message.tsx"],"names":[],"mappings":"AAgCA,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GACD;IACE,IAAI,EAAE,iBAAiB,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB,QAAQ,CAAC,EAAE;QACT,EAAE,EAAE,MAAM,CAAA;QACV,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB,CAAA;CACF,CAAA;AAEL,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;CAC1B,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAmBD,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,MAAc,EACd,WAAmB,GACpB,EAAE,YAAY,2CAyed;AAED,eAAO,MAAM,OAAO,yDAAoB,CAAA;AAExC,wBAAgB,eAAe,4CAiB9B"}
1
+ {"version":3,"file":"chat-message.d.ts","sourceRoot":"","sources":["../../../src/components/chat/chat-message.tsx"],"names":[],"mappings":"AA+BA,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACnC;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GACD;IACE,IAAI,EAAE,iBAAiB,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,MAAM,CAAC,EAAE,OAAO,CAAA;IAEhB,QAAQ,CAAC,EAAE;QACT,EAAE,EAAE,MAAM,CAAA;QACV,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB,CAAA;CACF,CAAA;AAEL,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAA;IACzB,IAAI,CAAC,EAAE;QACL,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;CACF,CAAA;AAED,KAAK,YAAY,GAAG;IAClB,OAAO,EAAE,WAAW,CAAA;IACpB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAsvBD,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,MAAc,EACd,WAAmB,GACpB,EAAE,YAAY,2CAqgBd;AAED,eAAO,MAAM,OAAO,yDAAoB,CAAA;AAExC,wBAAgB,eAAe,4CAc9B;AAED,wBAAgB,iBAAiB,4CAkBhC"}