@v0-sdk/react 0.5.0 → 3.0.0-canary.9e23bac

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 CHANGED
@@ -1,299 +1,72 @@
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.
3
+ React hooks for building apps with the v0 API.
4
4
 
5
- Headless React components and hooks for rendering content from the v0 Platform API.
5
+ ## Install
6
6
 
7
- ## Features
7
+ ```sh
8
+ npm install @v0-sdk/react react swr
9
+ ```
8
10
 
9
- - **Headless by design** - Works with React Native, TUIs, and any React renderer
10
- - **Flexible rendering** - Use provided JSX components or build your own with headless hooks
11
- - **Customizable** - Override any component or styling
12
- - **Zero DOM dependencies** - No `react-dom` required
13
- - **Streaming support** - Real-time message streaming with `useStreamingMessage`
14
- - **Backward compatible** - Drop-in replacement for existing implementations
11
+ ## Getting started
15
12
 
16
- ## Installation
13
+ Create backend routes that authenticate with the server-side `v0` SDK, then pass those route URLs to the hooks. For example, this Next.js route proxies a streaming message request while keeping `V0_API_KEY` on the server:
17
14
 
18
- ```bash
19
- npm install @v0-sdk/react
20
- # or
21
- yarn add @v0-sdk/react
22
- # or
23
- pnpm add @v0-sdk/react
24
- ```
15
+ ```ts
16
+ // app/api/v0/chats/[chatId]/messages/stream/route.ts
17
+ import { v0 } from 'v0'
25
18
 
26
- ## Usage
19
+ export async function POST(request: Request, { params }: { params: Promise<{ chatId: string }> }) {
20
+ // Perform your own authentication and validation
27
21
 
28
- ### Basic JSX Components (Web/React DOM)
22
+ const { chatId } = await params
23
+ const body = await request.json()
29
24
 
30
- ```tsx
31
- import { Message, StreamingMessage } from '@v0-sdk/react'
25
+ const result = await v0.messages.sendStream({ chatId, ...body })
32
26
 
33
- function ChatMessage({ content }) {
34
- return (
35
- <Message
36
- content={content}
37
- messageId="msg-1"
38
- role="assistant"
39
- className="my-message"
40
- />
41
- )
42
- }
43
-
44
- function StreamingChat({ stream }) {
45
- return (
46
- <StreamingMessage
47
- stream={stream}
48
- messageId="streaming-msg"
49
- role="assistant"
50
- onComplete={(content) => console.log('Complete:', content)}
51
- />
52
- )
27
+ return result.toResponse()
53
28
  }
54
29
  ```
55
30
 
56
- ### Headless Hooks (React Native/Ink/TUI)
31
+ The client can call that route with the corresponding hook:
57
32
 
58
33
  ```tsx
59
- import { useMessage, useStreamingMessageData } from '@v0-sdk/react'
60
- import { Text, View } from 'react-native' // or any other renderer
34
+ import { useChat, useMessages, useSendMessage } from '@v0-sdk/react'
61
35
 
62
- function HeadlessMessage({ content }) {
63
- const messageData = useMessage({
64
- content,
65
- messageId: 'msg-1',
66
- role: 'assistant',
36
+ export function Chat({ chatId }: { chatId: string }) {
37
+ const chat = useChat(`/api/v0/chats/${chatId}`)
38
+ const messages = useMessages(`/api/v0/chats/${chatId}/messages`, {
39
+ limit: 50,
67
40
  })
41
+ const send = useSendMessage(`/api/v0/chats/${chatId}/messages/stream`)
68
42
 
69
- return (
70
- <View>
71
- {messageData.elements.map((element) => (
72
- <Text key={element.key}>
73
- {element.type === 'text' ? element.data : JSON.stringify(element)}
74
- </Text>
75
- ))}
76
- </View>
77
- )
78
- }
79
-
80
- function HeadlessStreamingMessage({ stream }) {
81
- const streamingData = useStreamingMessageData({
82
- stream,
83
- messageId: 'streaming-msg',
84
- role: 'assistant',
85
- })
86
-
87
- if (streamingData.error) {
88
- return <Text style={{ color: 'red' }}>Error: {streamingData.error}</Text>
43
+ if (chat.isLoading || messages.isLoading) {
44
+ return <p>Loading…</p>
89
45
  }
90
46
 
91
- if (streamingData.isStreaming && !streamingData.messageData) {
92
- return <Text>Loading...</Text>
47
+ if (chat.error || messages.error) {
48
+ return <p>Unable to load the chat.</p>
93
49
  }
94
50
 
95
51
  return (
96
- <View>
97
- {streamingData.messageData?.elements.map((element) => (
98
- <Text key={element.key}>
99
- {element.type === 'text' ? element.data : JSON.stringify(element)}
100
- </Text>
101
- ))}
102
- </View>
103
- )
104
- }
105
- ```
106
-
107
- ### Ink CLI Example
52
+ <main>
53
+ <h1>{chat.data?.title}</h1>
108
54
 
109
- ```tsx
110
- import { useMessage } from '@v0-sdk/react'
111
- import { Text, Box } from 'ink'
112
-
113
- function CliMessage({ content }) {
114
- const messageData = useMessage({
115
- content,
116
- messageId: 'cli-msg',
117
- role: 'assistant',
118
- })
119
-
120
- return (
121
- <Box flexDirection="column">
122
- {messageData.elements.map((element) => (
123
- <Text key={element.key}>
124
- {element.type === 'text' ? element.data : `[${element.type}]`}
125
- </Text>
55
+ {messages.data?.messages.map((message) => (
56
+ <article key={message.id}>{message.content}</article>
126
57
  ))}
127
- </Box>
128
- )
129
- }
130
- ```
131
-
132
- ## Available Hooks
133
-
134
- ### Core Hooks
135
-
136
- - `useMessage(props)` - Process message content into headless data structure
137
- - `useStreamingMessageData(props)` - Handle streaming messages with real-time updates
138
- - `useStreamingMessage(stream, options)` - Low-level streaming hook
139
-
140
- ### Component Hooks
141
-
142
- - `useIcon(props)` - Icon data and fallbacks
143
- - `useCodeBlock(props)` - Code block processing
144
- - `useMath(props)` - Math content processing
145
- - `useThinkingSection(props)` - Thinking section state management
146
- - `useTaskSection(props)` - Task section state and processing
147
- - `useCodeProject(props)` - Code project structure
148
- - `useContentPart(part)` - Content part analysis and processing
149
-
150
- ## Available Components
151
-
152
- All components are optional JSX renderers that work with DOM environments. For headless usage, use the corresponding hooks instead.
153
-
154
- - `Message` - Main message renderer
155
- - `StreamingMessage` - Streaming message with loading states
156
- - `Icon` - Generic icon component with fallbacks
157
- - `CodeBlock` - Code syntax highlighting
158
- - `MathPart` - Math content rendering
159
- - `ThinkingSection` - Collapsible thinking sections
160
- - `TaskSection` - Collapsible task sections
161
- - `CodeProjectPart` - Code project file browser
162
- - `ContentPartRenderer` - Handles different content part types
163
-
164
- ## Supported Task Types
165
-
166
- The package automatically handles all v0 Platform API task types:
167
-
168
- ### Explicitly Supported Tasks
169
-
170
- - `task-thinking-v1` - AI reasoning and thought processes
171
- - `task-search-web-v1` - Web search operations with results
172
- - `task-search-repo-v1` - Repository/codebase search functionality
173
- - `task-diagnostics-v1` - Code analysis and issue detection
174
- - `task-read-file-v1` - File reading operations
175
- - `task-coding-v1` - Code generation and editing tasks
176
- - `task-generate-design-inspiration-v1` - Design inspiration generation
177
- - `task-start-v1` - Task initialization (usually hidden)
178
58
 
179
- ### Future-Proof Support
180
-
181
- Any new task type following the `task-*-v1` pattern will be automatically supported with:
182
-
183
- - Auto-generated readable titles
184
- - Appropriate icon selection
185
- - Proper task section rendering
186
- - Graceful fallback handling
187
-
188
- ## Customization
189
-
190
- ### Custom Components
191
-
192
- ```tsx
193
- import { Message } from '@v0-sdk/react'
194
-
195
- function CustomMessage({ content }) {
196
- return (
197
- <Message
198
- content={content}
199
- components={{
200
- // Override specific HTML elements
201
- p: ({ children }) => <MyParagraph>{children}</MyParagraph>,
202
- code: ({ children }) => <MyCode>{children}</MyCode>,
203
-
204
- // Override v0-specific components
205
- CodeBlock: ({ language, code }) => (
206
- <MyCodeHighlighter lang={language}>{code}</MyCodeHighlighter>
207
- ),
208
- Icon: ({ name }) => <MyIcon icon={name} />,
209
- }}
210
- />
59
+ <button
60
+ disabled={send.isMutating}
61
+ onClick={async () => {
62
+ const response = await send.trigger({ message: 'Build a dashboard' })
63
+ await response.text()
64
+ await messages.mutate()
65
+ }}
66
+ >
67
+ Send message
68
+ </button>
69
+ </main>
211
70
  )
212
71
  }
213
72
  ```
214
-
215
- ### Headless Custom Rendering
216
-
217
- ```tsx
218
- import { useMessage } from '@v0-sdk/react'
219
-
220
- function CustomHeadlessMessage({ content }) {
221
- const messageData = useMessage({ content })
222
-
223
- const renderElement = (element) => {
224
- switch (element.type) {
225
- case 'text':
226
- return <MyText>{element.data}</MyText>
227
- case 'code-project':
228
- return <MyCodeProject {...element.data} />
229
- case 'html':
230
- return <MyHtmlElement {...element.data} />
231
- default:
232
- return null
233
- }
234
- }
235
-
236
- return <MyContainer>{messageData.elements.map(renderElement)}</MyContainer>
237
- }
238
- ```
239
-
240
- ## TypeScript Support
241
-
242
- Full TypeScript support with exported types:
243
-
244
- ```tsx
245
- import type {
246
- MessageData,
247
- MessageElement,
248
- StreamingMessageData,
249
- IconData,
250
- CodeBlockData,
251
- // ... and many more
252
- } from '@v0-sdk/react'
253
- ```
254
-
255
- ## Migration from Previous Versions
256
-
257
- This version is backward compatible. Existing code will continue to work unchanged. To adopt headless patterns:
258
-
259
- 1. **Keep existing JSX components** for web/DOM environments
260
- 2. **Use headless hooks** for React Native, Ink, or custom renderers
261
- 3. **Gradually migrate** components as needed
262
-
263
- ## React Native Example
264
-
265
- ```tsx
266
- import { useMessage, useIcon } from '@v0-sdk/react'
267
- import { View, Text, ScrollView } from 'react-native'
268
-
269
- function RNMessage({ content }) {
270
- const messageData = useMessage({ content })
271
-
272
- const renderElement = (element) => {
273
- if (element.type === 'text') {
274
- return <Text key={element.key}>{element.data}</Text>
275
- }
276
-
277
- if (element.type === 'html' && element.data.tagName === 'p') {
278
- return (
279
- <Text key={element.key} style={{ marginVertical: 8 }}>
280
- {element.children?.map(renderElement)}
281
- </Text>
282
- )
283
- }
284
-
285
- return <Text key={element.key}>[{element.type}]</Text>
286
- }
287
-
288
- return <ScrollView>{messageData.elements.map(renderElement)}</ScrollView>
289
- }
290
-
291
- function RNIcon({ name }) {
292
- const iconData = useIcon({ name })
293
- return <Text>{iconData.fallback}</Text>
294
- }
295
- ```
296
-
297
- ## License
298
-
299
- Apache-2.0