@v0-sdk/react 0.1.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.
- package/README.md +233 -0
- package/dist/index.cjs +848 -0
- package/dist/index.d.ts +341 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +829 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React$1 from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Binary format for message content as returned by the v0 Platform API
|
|
6
|
+
* Each row is a tuple where the first element is the type and the rest are data
|
|
7
|
+
*/
|
|
8
|
+
type MessageBinaryFormat = [number, ...any[]][];
|
|
9
|
+
/**
|
|
10
|
+
* Individual row in the message binary format
|
|
11
|
+
*/
|
|
12
|
+
type MessageBinaryFormatRow = MessageBinaryFormat[number];
|
|
13
|
+
/**
|
|
14
|
+
* Props for the Message component
|
|
15
|
+
*/
|
|
16
|
+
interface MessageProps {
|
|
17
|
+
/**
|
|
18
|
+
* The parsed content from the v0 Platform API
|
|
19
|
+
* This should be the JSON.parsed value of the 'content' field from API responses
|
|
20
|
+
*/
|
|
21
|
+
content: MessageBinaryFormat;
|
|
22
|
+
/**
|
|
23
|
+
* Optional message ID for tracking purposes
|
|
24
|
+
*/
|
|
25
|
+
messageId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* Role of the message sender
|
|
28
|
+
*/
|
|
29
|
+
role?: 'user' | 'assistant' | 'system' | 'tool';
|
|
30
|
+
/**
|
|
31
|
+
* Whether the message is currently being streamed
|
|
32
|
+
*/
|
|
33
|
+
streaming?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Whether this is the last message in the conversation
|
|
36
|
+
*/
|
|
37
|
+
isLastMessage?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Custom className for styling the root container
|
|
40
|
+
*/
|
|
41
|
+
className?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Custom component renderers (react-markdown style)
|
|
44
|
+
* Override specific components by name
|
|
45
|
+
* Can be either a React component or an object with className for simple styling
|
|
46
|
+
*/
|
|
47
|
+
components?: {
|
|
48
|
+
CodeBlock?: React.ComponentType<{
|
|
49
|
+
language: string;
|
|
50
|
+
code: string;
|
|
51
|
+
className?: string;
|
|
52
|
+
}>;
|
|
53
|
+
MathPart?: React.ComponentType<{
|
|
54
|
+
content: string;
|
|
55
|
+
inline?: boolean;
|
|
56
|
+
className?: string;
|
|
57
|
+
}>;
|
|
58
|
+
CodeProjectPart?: React.ComponentType<{
|
|
59
|
+
title?: string;
|
|
60
|
+
filename?: string;
|
|
61
|
+
code?: string;
|
|
62
|
+
language?: string;
|
|
63
|
+
collapsed?: boolean;
|
|
64
|
+
className?: string;
|
|
65
|
+
}>;
|
|
66
|
+
ThinkingSection?: React.ComponentType<{
|
|
67
|
+
title?: string;
|
|
68
|
+
duration?: number;
|
|
69
|
+
thought?: string;
|
|
70
|
+
collapsed?: boolean;
|
|
71
|
+
onCollapse?: () => void;
|
|
72
|
+
className?: string;
|
|
73
|
+
children?: React.ReactNode;
|
|
74
|
+
brainIcon?: React.ReactNode;
|
|
75
|
+
chevronRightIcon?: React.ReactNode;
|
|
76
|
+
chevronDownIcon?: React.ReactNode;
|
|
77
|
+
}>;
|
|
78
|
+
TaskSection?: React.ComponentType<{
|
|
79
|
+
title?: string;
|
|
80
|
+
type?: string;
|
|
81
|
+
parts?: any[];
|
|
82
|
+
collapsed?: boolean;
|
|
83
|
+
onCollapse?: () => void;
|
|
84
|
+
className?: string;
|
|
85
|
+
children?: React.ReactNode;
|
|
86
|
+
taskIcon?: React.ReactNode;
|
|
87
|
+
chevronRightIcon?: React.ReactNode;
|
|
88
|
+
chevronDownIcon?: React.ReactNode;
|
|
89
|
+
}>;
|
|
90
|
+
Icon?: React.ComponentType<{
|
|
91
|
+
name: 'chevron-right' | 'chevron-down' | 'search' | 'folder' | 'settings' | 'file-text' | 'brain' | 'wrench';
|
|
92
|
+
className?: string;
|
|
93
|
+
}>;
|
|
94
|
+
p?: React.ComponentType<React.HTMLAttributes<HTMLParagraphElement>> | {
|
|
95
|
+
className?: string;
|
|
96
|
+
};
|
|
97
|
+
h1?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
98
|
+
className?: string;
|
|
99
|
+
};
|
|
100
|
+
h2?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
101
|
+
className?: string;
|
|
102
|
+
};
|
|
103
|
+
h3?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
104
|
+
className?: string;
|
|
105
|
+
};
|
|
106
|
+
h4?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
107
|
+
className?: string;
|
|
108
|
+
};
|
|
109
|
+
h5?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
110
|
+
className?: string;
|
|
111
|
+
};
|
|
112
|
+
h6?: React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>> | {
|
|
113
|
+
className?: string;
|
|
114
|
+
};
|
|
115
|
+
ul?: React.ComponentType<React.HTMLAttributes<HTMLUListElement>> | {
|
|
116
|
+
className?: string;
|
|
117
|
+
};
|
|
118
|
+
ol?: React.ComponentType<React.HTMLAttributes<HTMLOListElement>> | {
|
|
119
|
+
className?: string;
|
|
120
|
+
};
|
|
121
|
+
li?: React.ComponentType<React.HTMLAttributes<HTMLLIElement>> | {
|
|
122
|
+
className?: string;
|
|
123
|
+
};
|
|
124
|
+
blockquote?: React.ComponentType<React.HTMLAttributes<HTMLQuoteElement>> | {
|
|
125
|
+
className?: string;
|
|
126
|
+
};
|
|
127
|
+
code?: React.ComponentType<React.HTMLAttributes<HTMLElement>> | {
|
|
128
|
+
className?: string;
|
|
129
|
+
};
|
|
130
|
+
pre?: React.ComponentType<React.HTMLAttributes<HTMLPreElement>> | {
|
|
131
|
+
className?: string;
|
|
132
|
+
};
|
|
133
|
+
strong?: React.ComponentType<React.HTMLAttributes<HTMLElement>> | {
|
|
134
|
+
className?: string;
|
|
135
|
+
};
|
|
136
|
+
em?: React.ComponentType<React.HTMLAttributes<HTMLElement>> | {
|
|
137
|
+
className?: string;
|
|
138
|
+
};
|
|
139
|
+
a?: React.ComponentType<React.AnchorHTMLAttributes<HTMLAnchorElement>> | {
|
|
140
|
+
className?: string;
|
|
141
|
+
};
|
|
142
|
+
hr?: React.ComponentType<React.HTMLAttributes<HTMLHRElement>> | {
|
|
143
|
+
className?: string;
|
|
144
|
+
};
|
|
145
|
+
div?: React.ComponentType<React.HTMLAttributes<HTMLDivElement>> | {
|
|
146
|
+
className?: string;
|
|
147
|
+
};
|
|
148
|
+
span?: React.ComponentType<React.HTMLAttributes<HTMLSpanElement>> | {
|
|
149
|
+
className?: string;
|
|
150
|
+
};
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* @deprecated Use `components` instead. Will be removed in next major version.
|
|
154
|
+
*/
|
|
155
|
+
renderers?: {
|
|
156
|
+
CodeBlock?: React.ComponentType<{
|
|
157
|
+
language: string;
|
|
158
|
+
code: string;
|
|
159
|
+
className?: string;
|
|
160
|
+
}>;
|
|
161
|
+
MathRenderer?: React.ComponentType<{
|
|
162
|
+
content: string;
|
|
163
|
+
inline?: boolean;
|
|
164
|
+
className?: string;
|
|
165
|
+
}>;
|
|
166
|
+
MathPart?: React.ComponentType<{
|
|
167
|
+
content: string;
|
|
168
|
+
inline?: boolean;
|
|
169
|
+
className?: string;
|
|
170
|
+
}>;
|
|
171
|
+
Icon?: React.ComponentType<{
|
|
172
|
+
name: 'chevron-right' | 'chevron-down' | 'search' | 'folder' | 'settings' | 'file-text' | 'brain' | 'wrench';
|
|
173
|
+
className?: string;
|
|
174
|
+
}>;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
type MessageRendererProps = MessageProps;
|
|
178
|
+
type V0MessageRendererProps = MessageProps;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Core renderer component for v0 Platform API message content
|
|
182
|
+
*/
|
|
183
|
+
declare function MessageImpl({ content, messageId, role: _role, streaming: _streaming, isLastMessage: _isLastMessage, className, components, renderers, }: MessageProps): react_jsx_runtime.JSX.Element;
|
|
184
|
+
/**
|
|
185
|
+
* Main component for rendering v0 Platform API message content
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```tsx
|
|
189
|
+
* import { Message } from '@v0-sdk/react'
|
|
190
|
+
*
|
|
191
|
+
* function MyComponent({ apiResponse }) {
|
|
192
|
+
* const content = JSON.parse(apiResponse.content)
|
|
193
|
+
*
|
|
194
|
+
* return (
|
|
195
|
+
* <Message
|
|
196
|
+
* content={content}
|
|
197
|
+
* messageId={apiResponse.id}
|
|
198
|
+
* role={apiResponse.role}
|
|
199
|
+
* className="space-y-4"
|
|
200
|
+
* components={{
|
|
201
|
+
* p: ({ children, ...props }) => <p className="mb-4" {...props}>{children}</p>,
|
|
202
|
+
* h1: ({ children, ...props }) => <h1 className="mb-4 text-2xl font-bold" {...props}>{children}</h1>,
|
|
203
|
+
* CodeBlock: MyCustomCodeBlock,
|
|
204
|
+
* MathPart: MyCustomMathRenderer,
|
|
205
|
+
* }}
|
|
206
|
+
* />
|
|
207
|
+
* )
|
|
208
|
+
* }
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
declare const Message: React$1.MemoExoticComponent<typeof MessageImpl>;
|
|
212
|
+
|
|
213
|
+
interface IconProps {
|
|
214
|
+
name: 'chevron-right' | 'chevron-down' | 'search' | 'folder' | 'settings' | 'file-text' | 'brain' | 'wrench';
|
|
215
|
+
className?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Generic icon component that can be customized by consumers.
|
|
219
|
+
* By default, renders a simple fallback. Consumers should provide
|
|
220
|
+
* their own icon implementation via context or props.
|
|
221
|
+
*/
|
|
222
|
+
declare function Icon(props: IconProps): react_jsx_runtime.JSX.Element;
|
|
223
|
+
|
|
224
|
+
interface ThinkingSectionProps {
|
|
225
|
+
title?: string;
|
|
226
|
+
duration?: number;
|
|
227
|
+
thought?: string;
|
|
228
|
+
collapsed?: boolean;
|
|
229
|
+
onCollapse?: () => void;
|
|
230
|
+
className?: string;
|
|
231
|
+
children?: React$1.ReactNode;
|
|
232
|
+
iconRenderer?: React$1.ComponentType<IconProps>;
|
|
233
|
+
brainIcon?: React$1.ReactNode;
|
|
234
|
+
chevronRightIcon?: React$1.ReactNode;
|
|
235
|
+
chevronDownIcon?: React$1.ReactNode;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Generic thinking section component
|
|
239
|
+
* Renders a collapsible section with basic structure - consumers provide styling
|
|
240
|
+
*/
|
|
241
|
+
declare function ThinkingSection({ title, duration, thought, collapsed: initialCollapsed, onCollapse, className, children, iconRenderer, brainIcon, chevronRightIcon, chevronDownIcon, }: ThinkingSectionProps): react_jsx_runtime.JSX.Element;
|
|
242
|
+
|
|
243
|
+
interface TaskSectionProps {
|
|
244
|
+
title?: string;
|
|
245
|
+
type?: string;
|
|
246
|
+
parts?: any[];
|
|
247
|
+
collapsed?: boolean;
|
|
248
|
+
onCollapse?: () => void;
|
|
249
|
+
className?: string;
|
|
250
|
+
children?: React$1.ReactNode;
|
|
251
|
+
iconRenderer?: React$1.ComponentType<IconProps>;
|
|
252
|
+
taskIcon?: React$1.ReactNode;
|
|
253
|
+
chevronRightIcon?: React$1.ReactNode;
|
|
254
|
+
chevronDownIcon?: React$1.ReactNode;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Generic task section component
|
|
258
|
+
* Renders a collapsible task section with basic structure - consumers provide styling
|
|
259
|
+
*/
|
|
260
|
+
declare function TaskSection({ title, type, parts, collapsed: initialCollapsed, onCollapse, className, children, iconRenderer, taskIcon, chevronRightIcon, chevronDownIcon, }: TaskSectionProps): react_jsx_runtime.JSX.Element;
|
|
261
|
+
|
|
262
|
+
interface CodeProjectPartProps {
|
|
263
|
+
title?: string;
|
|
264
|
+
filename?: string;
|
|
265
|
+
code?: string;
|
|
266
|
+
language?: string;
|
|
267
|
+
collapsed?: boolean;
|
|
268
|
+
className?: string;
|
|
269
|
+
children?: React$1.ReactNode;
|
|
270
|
+
iconRenderer?: React$1.ComponentType<IconProps>;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Generic code project block component
|
|
274
|
+
* Renders a collapsible code project with basic structure - consumers provide styling
|
|
275
|
+
*/
|
|
276
|
+
declare function CodeProjectPart({ title, filename, code, language, collapsed: initialCollapsed, className, children, iconRenderer, }: CodeProjectPartProps): react_jsx_runtime.JSX.Element;
|
|
277
|
+
|
|
278
|
+
interface ContentPartRendererProps {
|
|
279
|
+
part: any;
|
|
280
|
+
iconRenderer?: React$1.ComponentType<IconProps>;
|
|
281
|
+
thinkingSectionRenderer?: React$1.ComponentType<{
|
|
282
|
+
title?: string;
|
|
283
|
+
duration?: number;
|
|
284
|
+
thought?: string;
|
|
285
|
+
collapsed?: boolean;
|
|
286
|
+
className?: string;
|
|
287
|
+
children?: React$1.ReactNode;
|
|
288
|
+
brainIcon?: React$1.ReactNode;
|
|
289
|
+
chevronRightIcon?: React$1.ReactNode;
|
|
290
|
+
chevronDownIcon?: React$1.ReactNode;
|
|
291
|
+
}>;
|
|
292
|
+
taskSectionRenderer?: React$1.ComponentType<{
|
|
293
|
+
title?: string;
|
|
294
|
+
type?: string;
|
|
295
|
+
parts?: any[];
|
|
296
|
+
collapsed?: boolean;
|
|
297
|
+
className?: string;
|
|
298
|
+
children?: React$1.ReactNode;
|
|
299
|
+
taskIcon?: React$1.ReactNode;
|
|
300
|
+
chevronRightIcon?: React$1.ReactNode;
|
|
301
|
+
chevronDownIcon?: React$1.ReactNode;
|
|
302
|
+
}>;
|
|
303
|
+
brainIcon?: React$1.ReactNode;
|
|
304
|
+
chevronRightIcon?: React$1.ReactNode;
|
|
305
|
+
chevronDownIcon?: React$1.ReactNode;
|
|
306
|
+
searchIcon?: React$1.ReactNode;
|
|
307
|
+
folderIcon?: React$1.ReactNode;
|
|
308
|
+
settingsIcon?: React$1.ReactNode;
|
|
309
|
+
wrenchIcon?: React$1.ReactNode;
|
|
310
|
+
}
|
|
311
|
+
declare function ContentPartRenderer({ part, iconRenderer, thinkingSectionRenderer, taskSectionRenderer, brainIcon, chevronRightIcon, chevronDownIcon, searchIcon, folderIcon, settingsIcon, wrenchIcon, }: ContentPartRendererProps): react_jsx_runtime.JSX.Element;
|
|
312
|
+
|
|
313
|
+
interface MathPartProps {
|
|
314
|
+
content: string;
|
|
315
|
+
inline?: boolean;
|
|
316
|
+
className?: string;
|
|
317
|
+
children?: React$1.ReactNode;
|
|
318
|
+
displayMode?: boolean;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Generic math renderer component
|
|
322
|
+
* Renders plain math content by default - consumers should provide their own math rendering
|
|
323
|
+
*/
|
|
324
|
+
declare function MathPart({ content, inline, className, children, }: MathPartProps): react_jsx_runtime.JSX.Element;
|
|
325
|
+
|
|
326
|
+
interface CodeBlockProps {
|
|
327
|
+
language: string;
|
|
328
|
+
code: string;
|
|
329
|
+
className?: string;
|
|
330
|
+
children?: React$1.ReactNode;
|
|
331
|
+
filename?: string;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Generic code block component
|
|
335
|
+
* Renders plain code by default - consumers should provide their own styling and highlighting
|
|
336
|
+
*/
|
|
337
|
+
declare function CodeBlock({ language, code, className, children, }: CodeBlockProps): react_jsx_runtime.JSX.Element;
|
|
338
|
+
|
|
339
|
+
export { ContentPartRenderer as AssistantMessageContentPart, CodeBlock, CodeProjectPart as CodeProjectBlock, CodeProjectPart, ContentPartRenderer, Icon, MathPart, MathPart as MathRenderer, Message, Message as MessageContent, Message as MessageRenderer, TaskSection, ThinkingSection, Message as V0MessageRenderer };
|
|
340
|
+
export type { CodeBlockProps, CodeProjectPartProps as CodeProjectBlockProps, CodeProjectPartProps, ContentPartRendererProps, IconProps, MathPartProps, MathPartProps as MathRendererProps, MessageBinaryFormat, MessageBinaryFormatRow, MessageProps, MessageRendererProps, TaskSectionProps, ThinkingSectionProps, V0MessageRendererProps };
|
|
341
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sources":["../src/types.ts","../src/components/message.tsx","../src/components/icon.tsx","../src/components/thinking-section.tsx","../src/components/task-section.tsx","../src/components/code-project-part.tsx","../src/components/content-part-renderer.tsx","../src/components/math-part.tsx","../src/components/code-block.tsx"],"sourcesContent":["/**\n * Binary format for message content as returned by the v0 Platform API\n * Each row is a tuple where the first element is the type and the rest are data\n */\nexport type MessageBinaryFormat = [number, ...any[]][]\n\n/**\n * Individual row in the message binary format\n */\nexport type MessageBinaryFormatRow = MessageBinaryFormat[number]\n\n/**\n * Props for the Message component\n */\nexport interface MessageProps {\n /**\n * The parsed content from the v0 Platform API\n * This should be the JSON.parsed value of the 'content' field from API responses\n */\n content: MessageBinaryFormat\n\n /**\n * Optional message ID for tracking purposes\n */\n messageId?: string\n\n /**\n * Role of the message sender\n */\n role?: 'user' | 'assistant' | 'system' | 'tool'\n\n /**\n * Whether the message is currently being streamed\n */\n streaming?: boolean\n\n /**\n * Whether this is the last message in the conversation\n */\n isLastMessage?: boolean\n\n /**\n * Custom className for styling the root container\n */\n className?: string\n\n /**\n * Custom component renderers (react-markdown style)\n * Override specific components by name\n * Can be either a React component or an object with className for simple styling\n */\n components?: {\n // Content components\n CodeBlock?: React.ComponentType<{\n language: string\n code: string\n className?: string\n }>\n MathPart?: React.ComponentType<{\n content: string\n inline?: boolean\n className?: string\n }>\n CodeProjectPart?: React.ComponentType<{\n title?: string\n filename?: string\n code?: string\n language?: string\n collapsed?: boolean\n className?: string\n }>\n ThinkingSection?: React.ComponentType<{\n title?: string\n duration?: number\n thought?: string\n collapsed?: boolean\n onCollapse?: () => void\n className?: string\n children?: React.ReactNode\n brainIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n }>\n TaskSection?: React.ComponentType<{\n title?: string\n type?: string\n parts?: any[]\n collapsed?: boolean\n onCollapse?: () => void\n className?: string\n children?: React.ReactNode\n taskIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n }>\n Icon?: React.ComponentType<{\n name:\n | 'chevron-right'\n | 'chevron-down'\n | 'search'\n | 'folder'\n | 'settings'\n | 'file-text'\n | 'brain'\n | 'wrench'\n className?: string\n }>\n\n // HTML elements (react-markdown style)\n // Can be either a React component or an object with className\n p?:\n | React.ComponentType<React.HTMLAttributes<HTMLParagraphElement>>\n | { className?: string }\n h1?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n h2?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n h3?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n h4?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n h5?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n h6?:\n | React.ComponentType<React.HTMLAttributes<HTMLHeadingElement>>\n | { className?: string }\n ul?:\n | React.ComponentType<React.HTMLAttributes<HTMLUListElement>>\n | { className?: string }\n ol?:\n | React.ComponentType<React.HTMLAttributes<HTMLOListElement>>\n | { className?: string }\n li?:\n | React.ComponentType<React.HTMLAttributes<HTMLLIElement>>\n | { className?: string }\n blockquote?:\n | React.ComponentType<React.HTMLAttributes<HTMLQuoteElement>>\n | { className?: string }\n code?:\n | React.ComponentType<React.HTMLAttributes<HTMLElement>>\n | { className?: string }\n pre?:\n | React.ComponentType<React.HTMLAttributes<HTMLPreElement>>\n | { className?: string }\n strong?:\n | React.ComponentType<React.HTMLAttributes<HTMLElement>>\n | { className?: string }\n em?:\n | React.ComponentType<React.HTMLAttributes<HTMLElement>>\n | { className?: string }\n a?:\n | React.ComponentType<React.AnchorHTMLAttributes<HTMLAnchorElement>>\n | { className?: string }\n hr?:\n | React.ComponentType<React.HTMLAttributes<HTMLHRElement>>\n | { className?: string }\n div?:\n | React.ComponentType<React.HTMLAttributes<HTMLDivElement>>\n | { className?: string }\n span?:\n | React.ComponentType<React.HTMLAttributes<HTMLSpanElement>>\n | { className?: string }\n }\n\n /**\n * @deprecated Use `components` instead. Will be removed in next major version.\n */\n renderers?: {\n CodeBlock?: React.ComponentType<{\n language: string\n code: string\n className?: string\n }>\n MathRenderer?: React.ComponentType<{\n content: string\n inline?: boolean\n className?: string\n }>\n MathPart?: React.ComponentType<{\n content: string\n inline?: boolean\n className?: string\n }>\n Icon?: React.ComponentType<{\n name:\n | 'chevron-right'\n | 'chevron-down'\n | 'search'\n | 'folder'\n | 'settings'\n | 'file-text'\n | 'brain'\n | 'wrench'\n className?: string\n }>\n }\n}\n\n// Backward compatibility exports\nexport type MessageRendererProps = MessageProps\nexport type V0MessageRendererProps = MessageProps\n// Note: MessageStyles/MessageRendererStyles/V0MessageRendererStyles removed as styles prop is no longer supported\n","import React from 'react'\nimport { MessageProps } from '../types'\nimport { MathPart } from './math-part'\nimport { CodeBlock } from './code-block'\nimport { CodeProjectPart } from './code-project-part'\nimport { ContentPartRenderer } from './content-part-renderer'\nimport { cn } from '../utils/cn'\n\n// Helper function to render HTML elements with component or className config\nfunction renderHtmlElement(\n tagName: string,\n key: string,\n props: any,\n children: any[],\n className: string | undefined,\n componentOrConfig: any,\n components: MessageProps['components'],\n): React.ReactNode {\n if (typeof componentOrConfig === 'function') {\n const Component = componentOrConfig\n return (\n <Component key={key} {...props} className={className}>\n {renderChildren(children, key, components)}\n </Component>\n )\n } else if (componentOrConfig && typeof componentOrConfig === 'object') {\n const mergedClassName = cn(className, componentOrConfig.className)\n return React.createElement(\n tagName,\n { key, ...props, className: mergedClassName },\n renderChildren(children, key, components),\n )\n } else {\n return React.createElement(\n tagName,\n { key, ...props, className },\n renderChildren(children, key, components),\n )\n }\n}\n\n/**\n * Core renderer component for v0 Platform API message content\n */\nfunction MessageImpl({\n content,\n messageId = 'unknown',\n role: _role = 'assistant',\n streaming: _streaming = false,\n isLastMessage: _isLastMessage = false,\n className,\n components,\n renderers, // deprecated\n}: MessageProps) {\n if (!Array.isArray(content)) {\n console.warn(\n 'MessageContent: content must be an array (MessageBinaryFormat)',\n )\n return null\n }\n\n // Merge components and renderers (backward compatibility)\n const mergedComponents = {\n ...components,\n // Map legacy renderers to new component names\n ...(renderers?.CodeBlock && { CodeBlock: renderers.CodeBlock }),\n ...(renderers?.MathRenderer && { MathPart: renderers.MathRenderer }),\n ...(renderers?.MathPart && { MathPart: renderers.MathPart }),\n ...(renderers?.Icon && { Icon: renderers.Icon }),\n }\n\n const elements = content.map(([type, ...data], index) => {\n const key = `${messageId}-${index}`\n\n // Markdown/text content (type 0)\n if (type === 0) {\n const markdownData = data[0]\n if (!Array.isArray(markdownData)) {\n return null\n }\n\n return (\n <div key={key}>\n {markdownData.map((item: any, mdIndex: number) => {\n const mdKey = `${key}-md-${mdIndex}`\n return renderMarkdownElement(item, mdKey, mergedComponents)\n })}\n </div>\n )\n }\n\n // Code block (type 1)\n if (type === 1) {\n const [language, code] = data\n const CodeBlockComponent = mergedComponents?.CodeBlock || CodeBlock\n return (\n <CodeBlockComponent\n key={key}\n language={language || 'text'}\n code={code || ''}\n />\n )\n }\n\n // Math (type 2 for inline, type 3 for block)\n if (type === 2 || type === 3) {\n const mathContent = data[0] || ''\n const MathPartComponent = mergedComponents?.MathPart || MathPart\n return (\n <MathPartComponent\n key={key}\n content={mathContent}\n inline={type === 2}\n />\n )\n }\n\n // Unknown type - render as text for debugging\n return <div key={key}>[Unknown content type: {type}]</div>\n })\n\n return <div className={className}>{elements}</div>\n}\n\nfunction renderMarkdownElement(\n item: any,\n key: string,\n components?: MessageProps['components'],\n): React.ReactNode {\n if (typeof item === 'string') {\n return <span key={key}>{item}</span>\n }\n\n if (Array.isArray(item)) {\n const [tagName, props, ...children] = item\n\n // Handle special v0 Platform API elements\n if (tagName === 'AssistantMessageContentPart') {\n return (\n <ContentPartRenderer\n key={key}\n part={props.part}\n iconRenderer={components?.Icon}\n thinkingSectionRenderer={components?.ThinkingSection}\n taskSectionRenderer={components?.TaskSection}\n />\n )\n }\n\n if (tagName === 'Codeblock') {\n const CustomCodeProjectPart = components?.CodeProjectPart\n const CodeProjectComponent = CustomCodeProjectPart || CodeProjectPart\n return (\n <CodeProjectComponent\n key={key}\n language={props.lang}\n code={children[0]}\n iconRenderer={components?.Icon}\n />\n )\n }\n\n if (tagName === 'text') {\n return <span key={key}>{children[0]}</span>\n }\n\n // Handle standard markdown elements\n const className = props?.className\n\n switch (tagName) {\n case 'p': {\n const componentOrConfig = components?.p\n if (typeof componentOrConfig === 'function') {\n const Component = componentOrConfig\n return (\n <Component key={key} {...props} className={className}>\n {renderChildren(children, key, components)}\n </Component>\n )\n } else if (componentOrConfig && typeof componentOrConfig === 'object') {\n const mergedClassName = cn(className, componentOrConfig.className)\n return (\n <p key={key} {...props} className={mergedClassName}>\n {renderChildren(children, key, components)}\n </p>\n )\n } else {\n return (\n <p key={key} {...props} className={className}>\n {renderChildren(children, key, components)}\n </p>\n )\n }\n }\n case 'h1':\n return renderHtmlElement(\n 'h1',\n key,\n props,\n children,\n className,\n components?.h1,\n components,\n )\n case 'h2':\n return renderHtmlElement(\n 'h2',\n key,\n props,\n children,\n className,\n components?.h2,\n components,\n )\n case 'h3':\n return renderHtmlElement(\n 'h3',\n key,\n props,\n children,\n className,\n components?.h3,\n components,\n )\n case 'h4':\n return renderHtmlElement(\n 'h4',\n key,\n props,\n children,\n className,\n components?.h4,\n components,\n )\n case 'h5':\n return renderHtmlElement(\n 'h5',\n key,\n props,\n children,\n className,\n components?.h5,\n components,\n )\n case 'h6':\n return renderHtmlElement(\n 'h6',\n key,\n props,\n children,\n className,\n components?.h6,\n components,\n )\n case 'ul':\n return renderHtmlElement(\n 'ul',\n key,\n props,\n children,\n className,\n components?.ul,\n components,\n )\n case 'ol':\n return renderHtmlElement(\n 'ol',\n key,\n props,\n children,\n className,\n components?.ol,\n components,\n )\n case 'li':\n return renderHtmlElement(\n 'li',\n key,\n props,\n children,\n className,\n components?.li,\n components,\n )\n case 'blockquote':\n return renderHtmlElement(\n 'blockquote',\n key,\n props,\n children,\n className,\n components?.blockquote,\n components,\n )\n case 'code':\n return renderHtmlElement(\n 'code',\n key,\n props,\n children,\n className,\n components?.code,\n components,\n )\n case 'pre':\n return renderHtmlElement(\n 'pre',\n key,\n props,\n children,\n className,\n components?.pre,\n components,\n )\n case 'strong':\n return renderHtmlElement(\n 'strong',\n key,\n props,\n children,\n className,\n components?.strong,\n components,\n )\n case 'em':\n return renderHtmlElement(\n 'em',\n key,\n props,\n children,\n className,\n components?.em,\n components,\n )\n case 'a': {\n const componentOrConfig = components?.a\n if (typeof componentOrConfig === 'function') {\n const Component = componentOrConfig\n return (\n <Component\n key={key}\n {...props}\n className={className}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {renderChildren(children, key, components)}\n </Component>\n )\n } else if (componentOrConfig && typeof componentOrConfig === 'object') {\n const mergedClassName = cn(className, componentOrConfig.className)\n return (\n <a\n key={key}\n {...props}\n className={mergedClassName}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {renderChildren(children, key, components)}\n </a>\n )\n } else {\n return (\n <a\n key={key}\n {...props}\n className={className}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {renderChildren(children, key, components)}\n </a>\n )\n }\n }\n case 'br':\n return <br key={key} />\n case 'hr': {\n const componentOrConfig = components?.hr\n if (typeof componentOrConfig === 'function') {\n const Component = componentOrConfig\n return <Component key={key} {...props} className={className} />\n } else if (componentOrConfig && typeof componentOrConfig === 'object') {\n const mergedClassName = cn(className, componentOrConfig.className)\n return <hr key={key} {...props} className={mergedClassName} />\n } else {\n return <hr key={key} {...props} className={className} />\n }\n }\n case 'div':\n return renderHtmlElement(\n 'div',\n key,\n props,\n children,\n className,\n components?.div,\n components,\n )\n case 'span':\n return renderHtmlElement(\n 'span',\n key,\n props,\n children,\n className,\n components?.span,\n components,\n )\n default:\n return (\n <span key={key}>{renderChildren(children, key, components)}</span>\n )\n }\n }\n\n return null\n}\n\nfunction renderChildren(\n children: any[],\n parentKey: string,\n components?: MessageProps['components'],\n): React.ReactNode[] {\n return children\n .map((child, index) => {\n const key = `${parentKey}-child-${index}`\n return renderMarkdownElement(child, key, components)\n })\n .filter(Boolean)\n}\n\n/**\n * Main component for rendering v0 Platform API message content\n *\n * @example\n * ```tsx\n * import { Message } from '@v0-sdk/react'\n *\n * function MyComponent({ apiResponse }) {\n * const content = JSON.parse(apiResponse.content)\n *\n * return (\n * <Message\n * content={content}\n * messageId={apiResponse.id}\n * role={apiResponse.role}\n * className=\"space-y-4\"\n * components={{\n * p: ({ children, ...props }) => <p className=\"mb-4\" {...props}>{children}</p>,\n * h1: ({ children, ...props }) => <h1 className=\"mb-4 text-2xl font-bold\" {...props}>{children}</h1>,\n * CodeBlock: MyCustomCodeBlock,\n * MathPart: MyCustomMathRenderer,\n * }}\n * />\n * )\n * }\n * ```\n */\nexport const Message = React.memo(MessageImpl)\n","import React, { createContext, useContext } from 'react'\n\n// Context for providing custom icon implementation\nconst IconContext = createContext<React.ComponentType<IconProps> | null>(null)\n\nexport interface IconProps {\n name:\n | 'chevron-right'\n | 'chevron-down'\n | 'search'\n | 'folder'\n | 'settings'\n | 'file-text'\n | 'brain'\n | 'wrench'\n className?: string\n}\n\n/**\n * Generic icon component that can be customized by consumers.\n * By default, renders a simple fallback. Consumers should provide\n * their own icon implementation via context or props.\n */\nexport function Icon(props: IconProps) {\n const CustomIcon = useContext(IconContext)\n\n // Use custom icon implementation if provided via context\n if (CustomIcon) {\n return <CustomIcon {...props} />\n }\n\n // Fallback implementation - consumers should override this\n return (\n <span\n className={props.className}\n data-icon={props.name}\n suppressHydrationWarning\n aria-label={props.name.replace('-', ' ')}\n >\n {getIconFallback(props.name)}\n </span>\n )\n}\n\n/**\n * Provider for custom icon implementation\n */\nexport function IconProvider({\n children,\n component,\n}: {\n children: React.ReactNode\n component: React.ComponentType<IconProps>\n}) {\n return (\n <IconContext.Provider value={component}>{children}</IconContext.Provider>\n )\n}\n\nfunction getIconFallback(name: string): string {\n const iconMap: Record<string, string> = {\n 'chevron-right': '▶',\n 'chevron-down': '▼',\n search: '🔍',\n folder: '📁',\n settings: '⚙️',\n 'file-text': '📄',\n brain: '🧠',\n wrench: '🔧',\n }\n return iconMap[name] || '•'\n}\n","import React, { useState } from 'react'\nimport { Icon, IconProps } from './icon'\n\nexport interface ThinkingSectionProps {\n title?: string\n duration?: number\n thought?: string\n collapsed?: boolean\n onCollapse?: () => void\n className?: string\n children?: React.ReactNode\n iconRenderer?: React.ComponentType<IconProps>\n brainIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n}\n\n/**\n * Generic thinking section component\n * Renders a collapsible section with basic structure - consumers provide styling\n */\nexport function ThinkingSection({\n title,\n duration,\n thought,\n collapsed: initialCollapsed = true,\n onCollapse,\n className,\n children,\n iconRenderer,\n brainIcon,\n chevronRightIcon,\n chevronDownIcon,\n}: ThinkingSectionProps) {\n const [internalCollapsed, setInternalCollapsed] = useState(initialCollapsed)\n const collapsed = onCollapse ? initialCollapsed : internalCollapsed\n const handleCollapse =\n onCollapse || (() => setInternalCollapsed(!internalCollapsed))\n\n // If children provided, use that (allows complete customization)\n if (children) {\n return <>{children}</>\n }\n\n return (\n <div className={className} data-component=\"thinking-section\">\n <button onClick={handleCollapse} data-expanded={!collapsed} data-button>\n <div data-icon-container>\n {collapsed ? (\n <>\n {brainIcon ||\n (iconRenderer ? (\n React.createElement(iconRenderer, { name: 'brain' })\n ) : (\n <Icon name=\"brain\" />\n ))}\n {chevronRightIcon ||\n (iconRenderer ? (\n React.createElement(iconRenderer, { name: 'chevron-right' })\n ) : (\n <Icon name=\"chevron-right\" />\n ))}\n </>\n ) : (\n chevronDownIcon ||\n (iconRenderer ? (\n React.createElement(iconRenderer, { name: 'chevron-down' })\n ) : (\n <Icon name=\"chevron-down\" />\n ))\n )}\n </div>\n <span data-title>\n {title || 'Thinking'}\n {duration && ` for ${Math.round(duration)}s`}\n </span>\n </button>\n {!collapsed && thought && (\n <div data-content>\n <div data-thought-container>\n {thought.split('\\n\\n').map((paragraph, index) => (\n <div key={index} data-paragraph>\n {paragraph}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { Icon, IconProps } from './icon'\n\nexport interface TaskSectionProps {\n title?: string\n type?: string\n parts?: any[]\n collapsed?: boolean\n onCollapse?: () => void\n className?: string\n children?: React.ReactNode\n iconRenderer?: React.ComponentType<IconProps>\n taskIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n}\n\nfunction getTypeIcon(\n type?: string,\n title?: string,\n iconRenderer?: React.ComponentType<IconProps>,\n) {\n // Check title content for specific cases\n if (title?.includes('No issues found')) {\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'wrench' })\n ) : (\n <Icon name=\"wrench\" />\n )\n }\n if (title?.includes('Analyzed codebase')) {\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'search' })\n ) : (\n <Icon name=\"search\" />\n )\n }\n\n // Fallback to type-based icons\n switch (type) {\n case 'task-search-web-v1':\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'search' })\n ) : (\n <Icon name=\"search\" />\n )\n case 'task-search-repo-v1':\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'folder' })\n ) : (\n <Icon name=\"folder\" />\n )\n case 'task-diagnostics-v1':\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'settings' })\n ) : (\n <Icon name=\"settings\" />\n )\n default:\n return iconRenderer ? (\n React.createElement(iconRenderer, { name: 'wrench' })\n ) : (\n <Icon name=\"wrench\" />\n )\n }\n}\n\nfunction renderTaskPart(\n part: any,\n index: number,\n iconRenderer?: React.ComponentType<IconProps>,\n) {\n if (part.type === 'search-web') {\n if (part.status === 'searching') {\n return <div key={index}>{`Searching \"${part.query}\"`}</div>\n }\n if (part.status === 'analyzing') {\n return <div key={index}>{`Analyzing ${part.count} results...`}</div>\n }\n if (part.status === 'complete' && part.answer) {\n return (\n <div key={index}>\n <p>{part.answer}</p>\n {part.sources && part.sources.length > 0 && (\n <div>\n {part.sources.map((source: any, sourceIndex: number) => (\n <a\n key={sourceIndex}\n href={source.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {source.title}\n </a>\n ))}\n </div>\n )}\n </div>\n )\n }\n }\n\n if (part.type === 'search-repo') {\n if (part.status === 'searching') {\n return <div key={index}>{`Searching \"${part.query}\"`}</div>\n }\n if (part.status === 'reading' && part.files) {\n return (\n <div key={index}>\n <span>Reading files</span>\n {part.files.map((file: string, fileIndex: number) => (\n <span key={fileIndex}>\n {iconRenderer ? (\n React.createElement(iconRenderer, { name: 'file-text' })\n ) : (\n <Icon name=\"file-text\" />\n )}{' '}\n {file}\n </span>\n ))}\n </div>\n )\n }\n }\n\n if (part.type === 'diagnostics') {\n if (part.status === 'checking') {\n return <div key={index}>Checking for issues...</div>\n }\n if (part.status === 'complete' && part.issues === 0) {\n return <div key={index}>✅ No issues found</div>\n }\n }\n\n return <div key={index}>{JSON.stringify(part)}</div>\n}\n\n/**\n * Generic task section component\n * Renders a collapsible task section with basic structure - consumers provide styling\n */\nexport function TaskSection({\n title,\n type,\n parts = [],\n collapsed: initialCollapsed = true,\n onCollapse,\n className,\n children,\n iconRenderer,\n taskIcon,\n chevronRightIcon,\n chevronDownIcon,\n}: TaskSectionProps) {\n const [internalCollapsed, setInternalCollapsed] = useState(initialCollapsed)\n const collapsed = onCollapse ? initialCollapsed : internalCollapsed\n const handleCollapse =\n onCollapse || (() => setInternalCollapsed(!internalCollapsed))\n\n // If children provided, use that (allows complete customization)\n if (children) {\n return <>{children}</>\n }\n\n // Count meaningful parts (parts that would render something)\n const meaningfulParts = parts.filter((part) => {\n // Check if the part would render meaningful content\n if (part.type === 'search-web') {\n return (\n part.status === 'searching' ||\n part.status === 'analyzing' ||\n (part.status === 'complete' && part.answer)\n )\n }\n if (part.type === 'starting-repo-search' && part.query) return true\n if (part.type === 'select-files' && part.filePaths?.length > 0) return true\n if (part.type === 'starting-web-search' && part.query) return true\n if (part.type === 'got-results' && part.count) return true\n if (part.type === 'finished-web-search' && part.answer) return true\n if (part.type === 'diagnostics-passed') return true\n if (part.type === 'fetching-diagnostics') return true\n // Add more meaningful part types as needed\n return false\n })\n\n // If there's only one meaningful part, show just the content without the collapsible wrapper\n if (meaningfulParts.length === 1) {\n return (\n <div className={className} data-component=\"task-section-inline\">\n <div data-part>\n {renderTaskPart(meaningfulParts[0], 0, iconRenderer)}\n </div>\n </div>\n )\n }\n\n return (\n <div className={className} data-component=\"task-section\">\n <button onClick={handleCollapse} data-expanded={!collapsed} data-button>\n <div data-icon-container>\n <div data-task-icon>\n {taskIcon || getTypeIcon(type, title, iconRenderer)}\n </div>\n {collapsed\n ? chevronRightIcon ||\n (iconRenderer ? (\n React.createElement(iconRenderer, { name: 'chevron-right' })\n ) : (\n <Icon name=\"chevron-right\" />\n ))\n : chevronDownIcon ||\n (iconRenderer ? (\n React.createElement(iconRenderer, { name: 'chevron-down' })\n ) : (\n <Icon name=\"chevron-down\" />\n ))}\n </div>\n <span data-title>{title || 'Task'}</span>\n </button>\n {!collapsed && (\n <div data-content>\n <div data-parts-container>\n {parts.map((part, index) => (\n <div key={index} data-part>\n {renderTaskPart(part, index, iconRenderer)}\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { CodeBlock } from './code-block'\nimport { Icon, IconProps } from './icon'\n\nexport interface CodeProjectPartProps {\n title?: string\n filename?: string\n code?: string\n language?: string\n collapsed?: boolean\n className?: string\n children?: React.ReactNode\n iconRenderer?: React.ComponentType<IconProps>\n}\n\n/**\n * Generic code project block component\n * Renders a collapsible code project with basic structure - consumers provide styling\n */\nexport function CodeProjectPart({\n title,\n filename,\n code,\n language = 'typescript',\n collapsed: initialCollapsed = true,\n className,\n children,\n iconRenderer,\n}: CodeProjectPartProps) {\n const [collapsed, setCollapsed] = useState(initialCollapsed)\n\n // If children provided, use that (allows complete customization)\n if (children) {\n return <>{children}</>\n }\n\n return (\n <div className={className} data-component=\"code-project-block\">\n <button\n onClick={() => setCollapsed(!collapsed)}\n data-expanded={!collapsed}\n >\n <div data-header>\n {iconRenderer ? (\n React.createElement(iconRenderer, { name: 'folder' })\n ) : (\n <Icon name=\"folder\" />\n )}\n <span data-title>{title || 'Code Project'}</span>\n </div>\n <span data-version>v1</span>\n </button>\n {!collapsed && (\n <div data-content>\n <div data-file-list>\n <div data-file data-active>\n {iconRenderer ? (\n React.createElement(iconRenderer, { name: 'file-text' })\n ) : (\n <Icon name=\"file-text\" />\n )}\n <span data-filename>{filename}</span>\n <span data-filepath>app/page.tsx</span>\n </div>\n {/* Additional files could be added here */}\n <div data-file>\n {iconRenderer ? (\n React.createElement(iconRenderer, { name: 'file-text' })\n ) : (\n <Icon name=\"file-text\" />\n )}\n <span data-filename>layout.tsx</span>\n <span data-filepath>app/layout.tsx</span>\n </div>\n <div data-file>\n {iconRenderer ? (\n React.createElement(iconRenderer, { name: 'file-text' })\n ) : (\n <Icon name=\"file-text\" />\n )}\n <span data-filename>globals.css</span>\n <span data-filepath>app/globals.css</span>\n </div>\n </div>\n {code && <CodeBlock language={language} code={code} />}\n </div>\n )}\n </div>\n )\n}\n","import React, { useState } from 'react'\nimport { ThinkingSection } from './thinking-section'\nimport { TaskSection } from './task-section'\nimport { IconProps } from './icon'\n\nexport interface ContentPartRendererProps {\n part: any\n iconRenderer?: React.ComponentType<IconProps>\n thinkingSectionRenderer?: React.ComponentType<{\n title?: string\n duration?: number\n thought?: string\n collapsed?: boolean\n className?: string\n children?: React.ReactNode\n brainIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n }>\n taskSectionRenderer?: React.ComponentType<{\n title?: string\n type?: string\n parts?: any[]\n collapsed?: boolean\n className?: string\n children?: React.ReactNode\n taskIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n }>\n // Individual icon props for direct icon usage\n brainIcon?: React.ReactNode\n chevronRightIcon?: React.ReactNode\n chevronDownIcon?: React.ReactNode\n searchIcon?: React.ReactNode\n folderIcon?: React.ReactNode\n settingsIcon?: React.ReactNode\n wrenchIcon?: React.ReactNode\n}\n\nexport function ContentPartRenderer({\n part,\n iconRenderer,\n thinkingSectionRenderer,\n taskSectionRenderer,\n brainIcon,\n chevronRightIcon,\n chevronDownIcon,\n searchIcon,\n folderIcon,\n settingsIcon,\n wrenchIcon,\n}: ContentPartRendererProps) {\n if (!part) return null\n\n const { type, parts = [], ...metadata } = part\n\n switch (type) {\n case 'task-thinking-v1': {\n const thinkingPart = parts.find((p: any) => p.type === 'thinking-end')\n const ThinkingComponent = thinkingSectionRenderer || ThinkingSection\n const [collapsed, setCollapsed] = useState(true)\n\n return (\n <ThinkingComponent\n title=\"Thought\"\n duration={thinkingPart?.duration}\n thought={thinkingPart?.thought}\n collapsed={collapsed}\n onCollapse={() => setCollapsed(!collapsed)}\n brainIcon={brainIcon}\n chevronRightIcon={chevronRightIcon}\n chevronDownIcon={chevronDownIcon}\n />\n )\n }\n\n case 'task-search-web-v1': {\n const TaskComponent = taskSectionRenderer || TaskSection\n const [collapsed, setCollapsed] = useState(true)\n\n return (\n <TaskComponent\n title={metadata.taskNameComplete || metadata.taskNameActive}\n type={type}\n parts={parts}\n collapsed={collapsed}\n onCollapse={() => setCollapsed(!collapsed)}\n taskIcon={searchIcon}\n chevronRightIcon={chevronRightIcon}\n chevronDownIcon={chevronDownIcon}\n />\n )\n }\n\n case 'task-search-repo-v1': {\n const TaskComponent = taskSectionRenderer || TaskSection\n const [collapsed, setCollapsed] = useState(true)\n\n return (\n <TaskComponent\n title={metadata.taskNameComplete || metadata.taskNameActive}\n type={type}\n parts={parts}\n collapsed={collapsed}\n onCollapse={() => setCollapsed(!collapsed)}\n taskIcon={folderIcon}\n chevronRightIcon={chevronRightIcon}\n chevronDownIcon={chevronDownIcon}\n />\n )\n }\n\n case 'task-diagnostics-v1': {\n const TaskComponent = taskSectionRenderer || TaskSection\n const [collapsed, setCollapsed] = useState(true)\n\n return (\n <TaskComponent\n title={metadata.taskNameComplete || metadata.taskNameActive}\n type={type}\n parts={parts}\n collapsed={collapsed}\n onCollapse={() => setCollapsed(!collapsed)}\n taskIcon={settingsIcon}\n chevronRightIcon={chevronRightIcon}\n chevronDownIcon={chevronDownIcon}\n />\n )\n }\n\n case 'task-start-v1':\n // Usually just indicates task start - can be hidden or show as status\n return null\n\n default:\n return <div data-unknown-part-type={type}>Unknown part type: {type}</div>\n }\n}\n","import React from 'react'\n\nexport interface MathPartProps {\n content: string\n inline?: boolean\n className?: string\n children?: React.ReactNode\n displayMode?: boolean\n}\n\n/**\n * Generic math renderer component\n * Renders plain math content by default - consumers should provide their own math rendering\n */\nexport function MathPart({\n content,\n inline = false,\n className = '',\n children,\n}: MathPartProps) {\n // If children provided, use that (allows complete customization)\n if (children) {\n return <>{children}</>\n }\n\n // Simple fallback - just render plain math content\n const Element = inline ? 'span' : 'div'\n\n return (\n <Element className={className} data-math-inline={inline}>\n {content}\n </Element>\n )\n}\n","import React from 'react'\n\nexport interface CodeBlockProps {\n language: string\n code: string\n className?: string\n children?: React.ReactNode\n filename?: string\n}\n\n/**\n * Generic code block component\n * Renders plain code by default - consumers should provide their own styling and highlighting\n */\nexport function CodeBlock({\n language,\n code,\n className = '',\n children,\n}: CodeBlockProps) {\n // If children provided, use that (allows complete customization)\n if (children) {\n return <>{children}</>\n }\n\n // Simple fallback - just render plain code\n return (\n <pre className={className} data-language={language}>\n <code>{code}</code>\n </pre>\n )\n}\n"],"names":[],"mappings":";;;AAAA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACO;AACP;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACA;;AC5KP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;AChCA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;ACRA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;ACjBA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;ACjBA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;ACdA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;AClCA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;ACXA;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;;;"}
|