@v0-sdk/react 0.1.0 → 0.2.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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2025 Vercel, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # @v0-sdk/react
2
2
 
3
+ > **⚠️ Developer Preview**: This SDK is currently in beta and is subject to change. Use in production at your own risk.
4
+
3
5
  React components for rendering content from the v0 Platform API.
4
6
 
5
7
  ## Installation
@@ -17,14 +19,14 @@ pnpm add @v0-sdk/react
17
19
  ### Basic Usage
18
20
 
19
21
  ```tsx
20
- import { V0MessageRenderer } from '@v0-sdk/react'
22
+ import { Message } from '@v0-sdk/react'
21
23
 
22
24
  function ChatMessage({ apiResponse }) {
23
25
  // Parse the content from the API response
24
26
  const content = JSON.parse(apiResponse.content)
25
27
 
26
28
  return (
27
- <V0MessageRenderer
29
+ <Message
28
30
  content={content}
29
31
  messageId={apiResponse.id}
30
32
  role={apiResponse.role}
@@ -35,37 +37,121 @@ function ChatMessage({ apiResponse }) {
35
37
 
36
38
  ### With Streaming
37
39
 
40
+ The package provides built-in support for streaming responses from v0 API:
41
+
38
42
  ```tsx
39
- import { V0MessageRenderer } from '@v0-sdk/react'
43
+ import { StreamingMessage } from '@v0-sdk/react'
44
+ import { createClient } from 'v0-sdk'
40
45
 
41
- function StreamingMessage({ apiResponse, isStreaming }) {
42
- const content = JSON.parse(apiResponse.content)
46
+ const v0 = createClient()
47
+
48
+ function ChatDemo() {
49
+ const [stream, setStream] = useState<ReadableStream<Uint8Array> | null>(null)
50
+
51
+ const handleSendMessage = async (message: string) => {
52
+ const response = await v0.chats.create({
53
+ message,
54
+ responseMode: 'experimental_stream',
55
+ })
56
+ setStream(response)
57
+ }
43
58
 
44
59
  return (
45
- <V0MessageRenderer
46
- content={content}
47
- messageId={apiResponse.id}
48
- role={apiResponse.role}
49
- streaming={isStreaming}
50
- isLastMessage={true}
51
- />
60
+ <div>
61
+ {stream && (
62
+ <StreamingMessage
63
+ stream={stream}
64
+ messageId="demo-message"
65
+ role="assistant"
66
+ onComplete={(content) => console.log('Stream complete:', content)}
67
+ />
68
+ )}
69
+ </div>
52
70
  )
53
71
  }
54
72
  ```
55
73
 
56
- ### Custom Styling
74
+ ### Using the Streaming Hook
75
+
76
+ For more control, use the `useStreamingMessage` hook directly:
57
77
 
58
78
  ```tsx
59
- import { V0MessageRenderer } from '@v0-sdk/react'
79
+ import { useStreamingMessage, Message } from '@v0-sdk/react'
80
+
81
+ function CustomStreamingComponent({
82
+ stream,
83
+ }: {
84
+ stream: ReadableStream<Uint8Array>
85
+ }) {
86
+ const { content, isStreaming, error, isComplete } =
87
+ useStreamingMessage(stream)
88
+
89
+ if (error) return <div>Error: {error}</div>
90
+
91
+ return (
92
+ <div>
93
+ <div>Status: {isStreaming ? 'Streaming...' : 'Complete'}</div>
94
+ <Message
95
+ content={content}
96
+ streaming={isStreaming}
97
+ isLastMessage={true}
98
+ messageId="custom-streaming"
99
+ role="assistant"
100
+ />
101
+ </div>
102
+ )
103
+ }
104
+ ```
105
+
106
+ ### Custom Component Styling
107
+
108
+ The `Message` component supports custom component renderers for complete control over styling and behavior:
109
+
110
+ ```tsx
111
+ import { Message, CodeBlock, MathPart } from '@v0-sdk/react'
112
+
113
+ // Custom code block with syntax highlighting
114
+ function CustomCodeBlock({ language, code, className }) {
115
+ return (
116
+ <div className="my-code-block">
117
+ <div className="code-header">{language}</div>
118
+ <pre className={className}>
119
+ <code>{code}</code>
120
+ </pre>
121
+ </div>
122
+ )
123
+ }
124
+
125
+ // Custom math renderer
126
+ function CustomMathPart({ content, inline, className }) {
127
+ return (
128
+ <span className={`my-math ${inline ? 'inline' : 'block'} ${className}`}>
129
+ {content}
130
+ </span>
131
+ )
132
+ }
60
133
 
61
134
  function StyledMessage({ apiResponse }) {
62
135
  const content = JSON.parse(apiResponse.content)
63
136
 
64
137
  return (
65
- <V0MessageRenderer
138
+ <Message
66
139
  content={content}
67
140
  messageId={apiResponse.id}
68
141
  role={apiResponse.role}
142
+ components={{
143
+ CodeBlock: CustomCodeBlock,
144
+ MathPart: CustomMathPart,
145
+ // Style HTML elements with simple className objects
146
+ p: { className: 'my-paragraph-styles' },
147
+ h1: { className: 'my-heading-styles' },
148
+ // Or use custom components for full control
149
+ blockquote: ({ children, ...props }) => (
150
+ <div className="my-custom-blockquote" {...props}>
151
+ {children}
152
+ </div>
153
+ ),
154
+ }}
69
155
  className="my-custom-message-styles"
70
156
  />
71
157
  )
@@ -74,7 +160,7 @@ function StyledMessage({ apiResponse }) {
74
160
 
75
161
  ## API Reference
76
162
 
77
- ### V0MessageRenderer
163
+ ### Message
78
164
 
79
165
  The main component for rendering v0 Platform API message content.
80
166
 
@@ -87,7 +173,69 @@ The main component for rendering v0 Platform API message content.
87
173
  | `role` | `'user' \| 'assistant' \| 'system' \| 'tool'` | `'assistant'` | Role of the message sender |
88
174
  | `streaming` | `boolean` | `false` | Whether the message is currently being streamed |
89
175
  | `isLastMessage` | `boolean` | `false` | Whether this is the last message in the conversation |
90
- | `className` | `string` | `undefined` | Custom className for styling |
176
+ | `className` | `string` | `undefined` | Custom className for styling the root container |
177
+ | `components` | `ComponentOverrides` | `undefined` | Custom component renderers (see Custom Components section) |
178
+
179
+ ### Individual Components
180
+
181
+ You can also use individual components directly:
182
+
183
+ ```tsx
184
+ import {
185
+ CodeBlock,
186
+ MathPart,
187
+ ThinkingSection,
188
+ TaskSection,
189
+ CodeProjectPart
190
+ } from '@v0-sdk/react'
191
+
192
+ // Use components directly
193
+ <CodeBlock language="javascript" code="console.log('Hello')" />
194
+ <MathPart content="E = mc^2" inline />
195
+ <ThinkingSection title="Planning" thought="Let me think about this..." />
196
+ ```
197
+
198
+ #### CodeBlock
199
+
200
+ | Prop | Type | Default | Description |
201
+ | ----------- | ----------------- | ------------ | -------------------------------------------- |
202
+ | `language` | `string` | **required** | Programming language for syntax highlighting |
203
+ | `code` | `string` | **required** | The code content to display |
204
+ | `filename` | `string` | `undefined` | Optional filename to display |
205
+ | `className` | `string` | `undefined` | Custom styling |
206
+ | `children` | `React.ReactNode` | `undefined` | Custom content (overrides code prop) |
207
+
208
+ #### MathPart
209
+
210
+ | Prop | Type | Default | Description |
211
+ | ------------- | ----------------- | ------------ | --------------------------------------- |
212
+ | `content` | `string` | **required** | The mathematical expression |
213
+ | `inline` | `boolean` | `false` | Whether to render inline or as block |
214
+ | `displayMode` | `boolean` | `undefined` | Alternative to inline for display mode |
215
+ | `className` | `string` | `undefined` | Custom styling |
216
+ | `children` | `React.ReactNode` | `undefined` | Custom content (overrides content prop) |
217
+
218
+ #### ThinkingSection
219
+
220
+ | Prop | Type | Default | Description |
221
+ | ------------ | ------------ | ----------- | ---------------------------- |
222
+ | `title` | `string` | `undefined` | Section title |
223
+ | `thought` | `string` | `undefined` | The thinking content |
224
+ | `duration` | `number` | `undefined` | Duration in milliseconds |
225
+ | `collapsed` | `boolean` | `false` | Whether section is collapsed |
226
+ | `onCollapse` | `() => void` | `undefined` | Collapse toggle handler |
227
+ | `className` | `string` | `undefined` | Custom styling |
228
+
229
+ #### TaskSection
230
+
231
+ | Prop | Type | Default | Description |
232
+ | ------------ | ------------ | ----------- | ---------------------------- |
233
+ | `title` | `string` | `undefined` | Section title |
234
+ | `type` | `string` | `undefined` | Task type |
235
+ | `parts` | `any[]` | `undefined` | Task content parts |
236
+ | `collapsed` | `boolean` | `false` | Whether section is collapsed |
237
+ | `onCollapse` | `() => void` | `undefined` | Collapse toggle handler |
238
+ | `className` | `string` | `undefined` | Custom styling |
91
239
 
92
240
  ### Types
93
241
 
@@ -99,16 +247,17 @@ type MessageBinaryFormat = [number, ...any[]][]
99
247
 
100
248
  The binary format for message content as returned by the v0 Platform API. Each row is a tuple where the first element is the type and the rest are data.
101
249
 
102
- #### V0MessageRendererProps
250
+ #### MessageProps
103
251
 
104
252
  ```typescript
105
- interface V0MessageRendererProps {
253
+ interface MessageProps {
106
254
  content: MessageBinaryFormat
107
255
  messageId?: string
108
256
  role?: 'user' | 'assistant' | 'system' | 'tool'
109
257
  streaming?: boolean
110
258
  isLastMessage?: boolean
111
259
  className?: string
260
+ components?: ComponentOverrides
112
261
  }
113
262
  ```
114
263
 
@@ -117,50 +266,61 @@ interface V0MessageRendererProps {
117
266
  ### Supported Content Types
118
267
 
119
268
  - **Markdown/Text Content**: Paragraphs, headings, lists, links, emphasis, code spans, etc.
120
- - **Code Blocks**: Syntax-highlighted code blocks with support for 25+ programming languages
121
- - **Mathematical Expressions**: Inline and block math using KaTeX
122
- - **Extensible**: Easy to extend with additional content types
123
-
124
- ### Syntax Highlighting
125
-
126
- Code blocks are automatically syntax-highlighted using Prism.js with support for:
127
-
128
- - JavaScript/TypeScript
129
- - Python, Java, C/C++, C#
130
- - PHP, Ruby, Go, Rust
131
- - Swift, Kotlin, Scala
132
- - SQL, JSON, YAML
133
- - Markdown, CSS/SCSS
134
- - Bash/Shell scripts
135
- - And many more...
136
-
137
- ### Math Rendering
269
+ - **Code Blocks**: Syntax-highlighted code blocks with filename support
270
+ - **Mathematical Expressions**: Inline and block math expressions
271
+ - **Thinking Sections**: Collapsible reasoning/thinking content
272
+ - **Task Sections**: Structured task and workflow content
273
+ - **Code Projects**: Multi-file code project display
274
+ - **Rich Components**: Full component customization support
138
275
 
139
- Mathematical expressions are rendered using KaTeX:
276
+ ### Component Customization
140
277
 
141
- - Inline math: `$E = mc^2$`
142
- - Block math: `$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$`
278
+ The `components` prop allows you to override any part of the rendering:
143
279
 
144
- ## CSS Styling
280
+ ```tsx
281
+ // Simple className-based styling
282
+ <Message
283
+ content={content}
284
+ components={{
285
+ p: { className: 'my-paragraph' },
286
+ h1: { className: 'text-2xl font-bold' }
287
+ }}
288
+ />
289
+
290
+ // Full component replacement
291
+ <Message
292
+ content={content}
293
+ components={{
294
+ CodeBlock: MyCustomCodeBlock,
295
+ MathPart: MyCustomMathRenderer,
296
+ ThinkingSection: MyCustomThinking
297
+ }}
298
+ />
299
+ ```
145
300
 
146
- The component uses Tailwind CSS classes by default. You can:
301
+ ### Default Styling
147
302
 
148
- 1. **Use Tailwind CSS**: The component works out of the box with Tailwind
149
- 2. **Custom CSS**: Override styles using the `className` prop
150
- 3. **CSS Modules**: Import your own styles and pass via `className`
303
+ The components use Tailwind CSS classes by default but can work with any CSS framework:
151
304
 
152
- ### Required CSS
305
+ 1. **Tailwind CSS**: Works out of the box
306
+ 2. **Custom CSS**: Use the `className` prop and `components` overrides
307
+ 3. **CSS Modules**: Pass CSS module classes via `className` and `components`
308
+ 4. **Styled Components**: Wrap components with styled-components
153
309
 
154
- Make sure to include KaTeX CSS for math rendering:
310
+ ## Backward Compatibility
155
311
 
156
- ```css
157
- @import 'katex/dist/katex.min.css';
158
- ```
312
+ The package maintains backward compatibility with previous versions:
159
313
 
160
- Or import it in your JavaScript:
314
+ ```tsx
315
+ // These all work and refer to the same component
316
+ import { Message } from '@v0-sdk/react'
317
+ import { MessageRenderer } from '@v0-sdk/react'
318
+ import { V0MessageRenderer } from '@v0-sdk/react'
161
319
 
162
- ```javascript
163
- import 'katex/dist/katex.min.css'
320
+ // These are all equivalent
321
+ <Message content={content} />
322
+ <MessageRenderer content={content} />
323
+ <V0MessageRenderer content={content} />
164
324
  ```
165
325
 
166
326
  ## Examples
@@ -168,8 +328,7 @@ import 'katex/dist/katex.min.css'
168
328
  ### Complete Chat Interface
169
329
 
170
330
  ```tsx
171
- import { V0MessageRenderer } from '@v0-sdk/react'
172
- import 'katex/dist/katex.min.css'
331
+ import { Message } from '@v0-sdk/react'
173
332
 
174
333
  function ChatInterface({ messages }) {
175
334
  return (
@@ -184,7 +343,7 @@ function ChatInterface({ messages }) {
184
343
  <span className="role">{message.role}</span>
185
344
  <span className="timestamp">{message.createdAt}</span>
186
345
  </div>
187
- <V0MessageRenderer
346
+ <Message
188
347
  content={content}
189
348
  messageId={message.id}
190
349
  role={message.role}
@@ -199,17 +358,75 @@ function ChatInterface({ messages }) {
199
358
  }
200
359
  ```
201
360
 
361
+ ### Custom Theme Example
362
+
363
+ ```tsx
364
+ import { Message, CodeBlock, MathPart } from '@v0-sdk/react'
365
+
366
+ // Dark theme code block
367
+ function DarkCodeBlock({ language, code, filename }) {
368
+ return (
369
+ <div className="bg-gray-900 rounded-lg overflow-hidden">
370
+ {filename && (
371
+ <div className="bg-gray-800 px-4 py-2 text-gray-300 text-sm">
372
+ {filename}
373
+ </div>
374
+ )}
375
+ <div className="bg-gray-700 px-2 py-1 text-xs text-gray-400">
376
+ {language}
377
+ </div>
378
+ <pre className="p-4 text-green-400 overflow-x-auto">
379
+ <code>{code}</code>
380
+ </pre>
381
+ </div>
382
+ )
383
+ }
384
+
385
+ // Elegant math renderer
386
+ function ElegantMath({ content, inline }) {
387
+ return (
388
+ <span
389
+ className={`
390
+ ${inline ? 'mx-1' : 'block text-center my-4'}
391
+ font-serif text-blue-600
392
+ `}
393
+ >
394
+ {content}
395
+ </span>
396
+ )
397
+ }
398
+
399
+ function ThemedChat({ apiResponse }) {
400
+ const content = JSON.parse(apiResponse.content)
401
+
402
+ return (
403
+ <Message
404
+ content={content}
405
+ components={{
406
+ CodeBlock: DarkCodeBlock,
407
+ MathPart: ElegantMath,
408
+ h1: { className: 'text-3xl font-bold text-gray-800 mb-4' },
409
+ h2: { className: 'text-2xl font-semibold text-gray-700 mb-3' },
410
+ p: { className: 'text-gray-600 leading-relaxed mb-4' },
411
+ blockquote: { className: 'border-l-4 border-blue-500 pl-4 italic' },
412
+ }}
413
+ className="max-w-4xl mx-auto p-6"
414
+ />
415
+ )
416
+ }
417
+ ```
418
+
202
419
  ### Error Handling
203
420
 
204
421
  ```tsx
205
- import { V0MessageRenderer } from '@v0-sdk/react'
422
+ import { Message } from '@v0-sdk/react'
206
423
 
207
424
  function SafeMessageRenderer({ apiResponse }) {
208
425
  try {
209
426
  const content = JSON.parse(apiResponse.content)
210
427
 
211
428
  return (
212
- <V0MessageRenderer
429
+ <Message
213
430
  content={content}
214
431
  messageId={apiResponse.id}
215
432
  role={apiResponse.role}
@@ -217,17 +434,44 @@ function SafeMessageRenderer({ apiResponse }) {
217
434
  )
218
435
  } catch (error) {
219
436
  console.error('Failed to parse message content:', error)
220
-
221
- return <div className="error-message">Failed to render message content</div>
437
+ return (
438
+ <div className="error-message p-4 bg-red-50 border border-red-200 rounded">
439
+ <p className="text-red-700">Failed to render message content</p>
440
+ <pre className="text-xs text-red-600 mt-2 overflow-x-auto">
441
+ {error.message}
442
+ </pre>
443
+ </div>
444
+ )
222
445
  }
223
446
  }
224
447
  ```
225
448
 
449
+ ## TypeScript
450
+
451
+ The package is written in TypeScript and includes comprehensive type definitions. All components and props are fully typed for the best development experience.
452
+
453
+ ```tsx
454
+ import type {
455
+ MessageProps,
456
+ CodeBlockProps,
457
+ MathPartProps,
458
+ MessageBinaryFormat,
459
+ } from '@v0-sdk/react'
460
+
461
+ // Type-safe usage
462
+ const myMessage: MessageProps = {
463
+ content: parsedContent,
464
+ role: 'assistant',
465
+ streaming: false,
466
+ }
467
+ ```
468
+
226
469
  ## Requirements
227
470
 
228
471
  - React 18+ or React 19+
229
472
  - Modern browser with ES2020+ support
473
+ - TypeScript 4.5+ (if using TypeScript)
230
474
 
231
475
  ## License
232
476
 
233
- MIT
477
+ Apache 2.0