mirror of
https://github.com/run-llama/chat-ui.git
synced 2026-07-21 11:25:22 -04:00
docs: manually review docs (#112)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@llamaindex/chat-ui-docs': patch
|
||||
---
|
||||
|
||||
Manually review most of the docs
|
||||
+37
-199
@@ -32,70 +32,46 @@ The library provides several built-in annotation types:
|
||||
- **ARTIFACT** - Interactive code and document artifacts
|
||||
- **SUGGESTED_QUESTIONS** - Follow-up question suggestions
|
||||
|
||||
## Image Annotations
|
||||
## Using Annotations
|
||||
|
||||
Display images within chat messages with zoom and preview functionality.
|
||||
|
||||
### Creating Image Annotations
|
||||
|
||||
```typescript
|
||||
// Server-side: Add image annotation to message
|
||||
const imageAnnotation = {
|
||||
type: 'IMAGE',
|
||||
data: {
|
||||
url: 'https://example.com/chart.png',
|
||||
alt: 'Sales chart for Q4 2024',
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
role: 'assistant',
|
||||
content: 'Here is the sales chart you requested:',
|
||||
annotations: [imageAnnotation],
|
||||
}
|
||||
```
|
||||
|
||||
### Streaming Image Annotations
|
||||
|
||||
```typescript
|
||||
// In your API route
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
// Send text content first
|
||||
controller.enqueue(
|
||||
encoder.encode('0:"Here is the chart you requested:\\n"\\n')
|
||||
)
|
||||
|
||||
// Send image annotation
|
||||
const annotation = {
|
||||
type: 'IMAGE',
|
||||
data: {
|
||||
url: '/api/generated-chart.png',
|
||||
alt: 'Generated sales chart',
|
||||
},
|
||||
}
|
||||
|
||||
controller.enqueue(encoder.encode(`8:${JSON.stringify([annotation])}\\n`))
|
||||
|
||||
controller.close()
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### Client-side Rendering
|
||||
|
||||
Images automatically render when using the content components:
|
||||
Annotations automatically render when using the `annotations` property on a message. Here's an example of how to render an image annotation:
|
||||
|
||||
```tsx
|
||||
<ChatMessage message={message}>
|
||||
<ChatMessage.Content>
|
||||
<ChatMessage.Content.Markdown />
|
||||
<ChatMessage.Content.Image />{' '}
|
||||
{/* Automatically renders IMAGE annotations */}
|
||||
</ChatMessage.Content>
|
||||
</ChatMessage>
|
||||
const handler = useChat({
|
||||
initialMessages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: 'Here is an image',
|
||||
annotations: [
|
||||
{
|
||||
type: 'image',
|
||||
data: {
|
||||
url: '/llama.png',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<ChatSection
|
||||
handler={handler}
|
||||
className="block h-full flex-row gap-4 p-0 md:flex md:p-5"
|
||||
>
|
||||
<ChatMessage message={message}>
|
||||
<ChatMessage.Content>
|
||||
<ChatMessage.Content.Markdown />
|
||||
<ChatMessage.Content.Image />{' '}
|
||||
{/* Automatically renders IMAGE annotations */}
|
||||
</ChatMessage.Content>
|
||||
</ChatMessage>
|
||||
</ChatSection>
|
||||
)
|
||||
```
|
||||
|
||||
In the example above, the `ChatMessage.Content.Image` component automatically renders the image annotation retrieved from the `annotations` property on the message which is retrieved by the `useChatMessage` hook.
|
||||
The annotation is then passed to the `ChatImage` component which renders the image.
|
||||
|
||||
## File Annotations
|
||||
|
||||
Display file attachments with download links and preview capabilities.
|
||||
@@ -135,39 +111,6 @@ const fileAnnotation = {
|
||||
}
|
||||
```
|
||||
|
||||
### File Upload Integration
|
||||
|
||||
```typescript
|
||||
// Handle file uploads in your API
|
||||
export async function POST(request: Request) {
|
||||
const formData = await request.formData()
|
||||
const files = formData.getAll('files') as File[]
|
||||
|
||||
const fileAnnotations = await Promise.all(
|
||||
files.map(async file => {
|
||||
const url = await uploadFile(file) // Your upload logic
|
||||
|
||||
return {
|
||||
type: 'DOCUMENT_FILE',
|
||||
data: {
|
||||
files: [
|
||||
{
|
||||
id: generateId(),
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
url,
|
||||
size: file.size,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
return streamResponse(content, fileAnnotations)
|
||||
}
|
||||
```
|
||||
|
||||
## Source Annotations
|
||||
|
||||
Display citations and source references with document grouping.
|
||||
@@ -471,6 +414,8 @@ function WeatherWidget() {
|
||||
}
|
||||
```
|
||||
|
||||
## Annotation Utilities
|
||||
|
||||
### getAnnotationData
|
||||
|
||||
Extract annotation data by type from messages:
|
||||
@@ -482,113 +427,6 @@ import { getAnnotationData } from '@llamaindex/chat-ui'
|
||||
return getAnnotationData<WeatherData>(message, 'weather')
|
||||
```
|
||||
|
||||
## Annotation Utilities
|
||||
|
||||
### getCustomAnnotations
|
||||
|
||||
Extract custom annotations from a message:
|
||||
|
||||
```tsx
|
||||
import { getCustomAnnotations } from '@llamaindex/chat-ui'
|
||||
|
||||
function useWeatherData() {
|
||||
const { message } = useChatMessage()
|
||||
|
||||
return getCustomAnnotations<WeatherData>(message.annotations, 'weather')
|
||||
}
|
||||
```
|
||||
|
||||
## Server-side Implementation
|
||||
|
||||
### Streaming Annotations
|
||||
|
||||
```typescript
|
||||
// API route for streaming with annotations
|
||||
export async function POST(request: Request) {
|
||||
const { messages } = await request.json()
|
||||
|
||||
const stream = new ReadableStream({
|
||||
async start(controller) {
|
||||
const encoder = new TextEncoder()
|
||||
|
||||
// Send initial text
|
||||
controller.enqueue(
|
||||
encoder.encode('0:"Let me analyze the weather data for you.\\n"\\n')
|
||||
)
|
||||
|
||||
// Process and get weather data
|
||||
const weatherData = await getWeatherData(location)
|
||||
|
||||
// Send weather annotation
|
||||
const annotation = {
|
||||
type: 'weather',
|
||||
data: weatherData,
|
||||
}
|
||||
|
||||
controller.enqueue(encoder.encode(`8:${JSON.stringify([annotation])}\\n`))
|
||||
|
||||
// Send follow-up text
|
||||
controller.enqueue(
|
||||
encoder.encode('0:"Would you like a detailed forecast?"\\n')
|
||||
)
|
||||
|
||||
controller.close()
|
||||
},
|
||||
})
|
||||
|
||||
return new Response(stream, {
|
||||
headers: {
|
||||
'Content-Type': 'text/plain; charset=utf-8',
|
||||
'X-Vercel-AI-Data-Stream': 'v1',
|
||||
},
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### Annotation Processing
|
||||
|
||||
```typescript
|
||||
// Process different annotation types
|
||||
function createAnnotations(data: any) {
|
||||
const annotations = []
|
||||
|
||||
// Add image if generated
|
||||
if (data.imageUrl) {
|
||||
annotations.push({
|
||||
type: 'IMAGE',
|
||||
data: {
|
||||
url: data.imageUrl,
|
||||
alt: data.imageDescription,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Add sources if referenced
|
||||
if (data.sources?.length > 0) {
|
||||
annotations.push({
|
||||
type: 'sources',
|
||||
data: {
|
||||
nodes: data.sources.map(source => ({
|
||||
id: source.id,
|
||||
url: source.url,
|
||||
metadata: source.metadata,
|
||||
})),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Add custom weather data
|
||||
if (data.weather) {
|
||||
annotations.push({
|
||||
type: 'weather',
|
||||
data: data.weather,
|
||||
})
|
||||
}
|
||||
|
||||
return annotations
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Artifacts](./artifacts.mdx) - Learn about interactive code and document artifacts
|
||||
|
||||
+1
-101
@@ -3,7 +3,7 @@ title: Hooks
|
||||
description: Understanding the hook system for accessing chat state and functionality
|
||||
---
|
||||
|
||||
The hook system provides access to chat state, context, and functionality throughout the component tree. These hooks enable deep customization and integration with the chat interface.
|
||||
The hook system provides access to chat state (e.g. message content), context, and functionality throughout the component tree without the need to pass props. These hooks enable deep customization and integration with the chat interface.
|
||||
|
||||
## Context Hooks
|
||||
|
||||
@@ -348,106 +348,6 @@ function useCustomChat() {
|
||||
}
|
||||
```
|
||||
|
||||
### Message Analytics Hook
|
||||
|
||||
Track message interactions:
|
||||
|
||||
```tsx
|
||||
import { useChatMessage, useChatUI } from '@llamaindex/chat-ui'
|
||||
|
||||
function useMessageAnalytics() {
|
||||
const { message } = useChatMessage()
|
||||
const { requestData, setRequestData } = useChatUI()
|
||||
|
||||
const trackMessageView = () => {
|
||||
// Track message viewed
|
||||
console.log('Message viewed:', message.id)
|
||||
}
|
||||
|
||||
const trackMessageCopy = () => {
|
||||
// Track message copied
|
||||
setRequestData({
|
||||
...requestData,
|
||||
copiedMessages: [...(requestData?.copiedMessages || []), message.id],
|
||||
})
|
||||
}
|
||||
|
||||
const trackMessageRegenerate = () => {
|
||||
// Track message regenerated
|
||||
console.log('Message regenerated:', message.id)
|
||||
}
|
||||
|
||||
return {
|
||||
trackMessageView,
|
||||
trackMessageCopy,
|
||||
trackMessageRegenerate,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Usage Patterns
|
||||
|
||||
### Conditional Rendering
|
||||
|
||||
```tsx
|
||||
function ConditionalComponent() {
|
||||
const { isLoading, error, messages } = useChatUI()
|
||||
|
||||
if (isLoading) return <LoadingSpinner />
|
||||
if (error) return <ErrorMessage error={error} />
|
||||
if (messages.length === 0) return <EmptyState />
|
||||
|
||||
return <MessageList />
|
||||
}
|
||||
```
|
||||
|
||||
### Event Handling
|
||||
|
||||
```tsx
|
||||
function EventHandler() {
|
||||
const { append, setRequestData } = useChatUI()
|
||||
|
||||
const handleQuestionClick = async (question: string) => {
|
||||
// Track question selection
|
||||
setRequestData({ selectedQuestion: question })
|
||||
|
||||
// Send message
|
||||
await append({
|
||||
role: 'user',
|
||||
content: question,
|
||||
})
|
||||
}
|
||||
|
||||
return <SuggestedQuestions onQuestionSelect={handleQuestionClick} />
|
||||
}
|
||||
```
|
||||
|
||||
### Data Transformation
|
||||
|
||||
```tsx
|
||||
function MessageStats() {
|
||||
const { messages } = useChatUI()
|
||||
|
||||
const stats = useMemo(() => {
|
||||
const userMessages = messages.filter(m => m.role === 'user').length
|
||||
const assistantMessages = messages.filter(
|
||||
m => m.role === 'assistant'
|
||||
).length
|
||||
const totalChars = messages.reduce((sum, m) => sum + m.content.length, 0)
|
||||
|
||||
return { userMessages, assistantMessages, totalChars }
|
||||
}, [messages])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>User messages: {stats.userMessages}</p>
|
||||
<p>Assistant messages: {stats.assistantMessages}</p>
|
||||
<p>Total characters: {stats.totalChars}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Context Boundaries
|
||||
|
||||
### Context Availability
|
||||
|
||||
@@ -40,7 +40,7 @@ The fastest way to add a chatbot to your project is using the Shadcn CLI command
|
||||
npx shadcn@latest add https://ui.llamaindex.ai/r/chat.json
|
||||
```
|
||||
|
||||
For more information on configuration, please see detailed guide in [Getting Started](./getting-started.mdx).
|
||||
For more information on configuration, please see detailed guide in [Getting Started](/docs/chat-ui/getting-started).
|
||||
|
||||
## Quick Example
|
||||
|
||||
@@ -79,11 +79,3 @@ Chat UI is designed to work with any chat backend that implements Vercel's [Stre
|
||||
|
||||
- **NextJS** - [NextJS Example](https://github.com/run-llama/chat-ui/tree/main/examples/nextjs)
|
||||
- **FastAPI** - [FastAPI Example](https://github.com/run-llama/chat-ui/tree/main/examples/fastapi)
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Getting Started](./getting-started.mdx) - Installation and basic setup
|
||||
- [Core Components](./core-components.mdx) - Detailed guide to main components
|
||||
- [Widgets](./widgets.mdx) - Comprehensive widget documentation
|
||||
- [Annotations](./annotations.mdx) - Working with rich content
|
||||
- [Examples](./examples.mdx) - Real-world implementation examples
|
||||
|
||||
+106
-110
@@ -3,7 +3,9 @@ title: Widgets
|
||||
description: Comprehensive guide to specialized content widgets for rich chat experiences
|
||||
---
|
||||
|
||||
Widgets are specialized components for displaying and interacting with different types of content in chat messages. They provide rich functionality beyond simple text, enabling multimedia, interactive elements, and custom annotations.
|
||||
Widgets are specialized components for displaying and interacting with rich content in chat messages. They provide functionality beyond simple text, enabling multimedia, interactive elements, and custom annotations.
|
||||
|
||||
This section describes how to use them standalone.
|
||||
|
||||
## Content Widgets
|
||||
|
||||
@@ -41,13 +43,6 @@ def fibonacci(n):
|
||||
return n
|
||||
return fibonacci(n-1) + fibonacci(n-2)
|
||||
```
|
||||
````
|
||||
|
||||
This algorithm has O(2^n) complexity [^1].
|
||||
|
||||
[^1]: Introduction to Algorithms, Chapter 15
|
||||
|
||||
````
|
||||
|
||||
### CodeBlock
|
||||
|
||||
@@ -66,6 +61,7 @@ function CodeDisplay({ code, language, filename }) {
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
````
|
||||
|
||||
**Props:**
|
||||
@@ -141,6 +137,8 @@ function DocumentEdit({ content, onChange, title }) {
|
||||
|
||||
## Annotation Widgets
|
||||
|
||||
Used for rendering additional rich content in a chat message. See [Annotations](./annotations.mdx) for more information on how to add annotations to a message.
|
||||
|
||||
### ChatImage
|
||||
|
||||
Displays images with preview and zoom functionality.
|
||||
@@ -148,17 +146,15 @@ Displays images with preview and zoom functionality.
|
||||
```tsx
|
||||
import { ChatImage } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const imageAnnotation = {
|
||||
type: 'IMAGE',
|
||||
data: {
|
||||
url: 'https://example.com/image.jpg',
|
||||
alt: 'Description of the image',
|
||||
},
|
||||
}
|
||||
|
||||
function ImageDisplay() {
|
||||
return <ChatImage /> // Automatically renders from context
|
||||
return (
|
||||
<ChatImage
|
||||
data={{
|
||||
url: 'https://example.com/image.jpg',
|
||||
alt: 'Description of the image',
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -176,24 +172,22 @@ Displays file attachments with download and preview.
|
||||
```tsx
|
||||
import { ChatFiles } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const fileAnnotation = {
|
||||
type: 'DOCUMENT_FILE',
|
||||
data: {
|
||||
files: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'report.pdf',
|
||||
type: 'application/pdf',
|
||||
url: '/files/report.pdf',
|
||||
size: 1024000,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function FileDisplay() {
|
||||
return <ChatFiles /> // Automatically renders from context
|
||||
return (
|
||||
<ChatFiles
|
||||
data={{
|
||||
files: [
|
||||
{
|
||||
id: '1',
|
||||
name: 'report.pdf',
|
||||
type: 'application/pdf',
|
||||
url: '/files/report.pdf',
|
||||
size: 1024000,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -212,25 +206,23 @@ Displays source citations with document grouping.
|
||||
```tsx
|
||||
import { ChatSources } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const sourceAnnotation = {
|
||||
type: 'sources',
|
||||
data: {
|
||||
nodes: [
|
||||
{
|
||||
id: '1',
|
||||
url: '/documents/paper.pdf',
|
||||
metadata: {
|
||||
title: 'Research Paper',
|
||||
page_number: 5,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function SourceDisplay() {
|
||||
return <ChatSources /> // Automatically renders from context
|
||||
return (
|
||||
<ChatSources
|
||||
data={{
|
||||
nodes: [
|
||||
{
|
||||
id: '1',
|
||||
url: '/documents/paper.pdf',
|
||||
metadata: {
|
||||
title: 'Research Paper',
|
||||
page_number: 5,
|
||||
},
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -248,21 +240,20 @@ Displays collapsible process events and status updates.
|
||||
```tsx
|
||||
import { ChatEvents } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const eventAnnotation = {
|
||||
type: 'events',
|
||||
data: [
|
||||
{
|
||||
type: 'function_call',
|
||||
name: 'search_documents',
|
||||
args: { query: 'machine learning' },
|
||||
result: 'Found 15 relevant documents',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
function EventDisplay() {
|
||||
return <ChatEvents /> // Automatically renders from context
|
||||
return (
|
||||
<ChatEvents
|
||||
data={[
|
||||
{
|
||||
type: 'function_call',
|
||||
name: 'search_documents',
|
||||
args: { query: 'machine learning' },
|
||||
result: 'Found 15 relevant documents',
|
||||
},
|
||||
]}
|
||||
showLoading={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -273,23 +264,23 @@ Displays agent-specific events with progress tracking.
|
||||
```tsx
|
||||
import { ChatAgentEvents } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const agentAnnotation = {
|
||||
type: 'agent_events',
|
||||
data: {
|
||||
agent_name: 'Research Assistant',
|
||||
progress: 75,
|
||||
current_step: 'Analyzing documents',
|
||||
events: [
|
||||
{ step: 'Searching', status: 'completed' },
|
||||
{ step: 'Analyzing', status: 'in_progress' },
|
||||
{ step: 'Summarizing', status: 'pending' },
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function AgentEventDisplay() {
|
||||
return <ChatAgentEvents /> // Automatically renders from context
|
||||
return (
|
||||
<ChatAgentEvents
|
||||
data={{
|
||||
agent_name: 'Research Assistant',
|
||||
progress: 75,
|
||||
current_step: 'Analyzing documents',
|
||||
events: [
|
||||
{ step: 'Searching', status: 'completed' },
|
||||
{ step: 'Analyzing', status: 'in_progress' },
|
||||
{ step: 'Summarizing', status: 'pending' },
|
||||
],
|
||||
}}
|
||||
isFinished={true}
|
||||
isLast={false}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -300,20 +291,18 @@ Interactive follow-up question suggestions.
|
||||
```tsx
|
||||
import { SuggestedQuestions } from '@llamaindex/chat-ui/widgets'
|
||||
|
||||
// From annotation data
|
||||
const suggestionsAnnotation = {
|
||||
type: 'suggested_questions',
|
||||
data: {
|
||||
questions: [
|
||||
'Can you explain this in more detail?',
|
||||
'What are the practical applications?',
|
||||
'How does this compare to other approaches?',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
function QuestionSuggestions() {
|
||||
return <SuggestedQuestions /> // Automatically renders from context
|
||||
function QuestionSuggestions({ append, requestData }) {
|
||||
return (
|
||||
<SuggestedQuestions
|
||||
questions={[
|
||||
'Can you explain this in more detail?',
|
||||
'What are the practical applications?',
|
||||
'How does this compare to other approaches?',
|
||||
]}
|
||||
append={append}
|
||||
requestData={requestData}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -442,7 +431,7 @@ function CitationLink({ source, index }) {
|
||||
|
||||
### Automatic Rendering
|
||||
|
||||
Widgets automatically render based on message annotations:
|
||||
Annotation widgets render based on message annotations through dedicated annotation components:
|
||||
|
||||
```tsx
|
||||
import { ChatMessage } from '@llamaindex/chat-ui'
|
||||
@@ -461,6 +450,8 @@ function MessageWithWidgets({ message }) {
|
||||
}
|
||||
```
|
||||
|
||||
The `ChatMessage.Content.*` components internally use the annotation pattern described in [Annotations](./annotations.mdx), extracting data with `getAnnotationData` and passing it to the respective widgets.
|
||||
|
||||
### Manual Widget Usage
|
||||
|
||||
Use widgets independently for custom layouts:
|
||||
@@ -492,11 +483,9 @@ function CustomMessageLayout({ message }) {
|
||||
|
||||
### Custom Widget Creation
|
||||
|
||||
Create custom widgets by following the pattern:
|
||||
Create custom widgets by following this pattern:
|
||||
|
||||
```tsx
|
||||
import { useChatMessage, getAnnotationData } from '@llamaindex/chat-ui'
|
||||
|
||||
interface WeatherData {
|
||||
location: string
|
||||
temperature: number
|
||||
@@ -505,15 +494,7 @@ interface WeatherData {
|
||||
windSpeed: number
|
||||
}
|
||||
|
||||
export function CustomWeatherWidget() {
|
||||
const { message } = useChatMessage()
|
||||
|
||||
const weatherData = getAnnotationData<WeatherData>(message, 'weather')
|
||||
|
||||
if (!weatherData?.[0]) return null
|
||||
|
||||
const data = weatherData[0]
|
||||
|
||||
export function WeatherWidget({ data }: { data: WeatherData }) {
|
||||
return (
|
||||
<div className="rounded-lg bg-blue-50 p-4">
|
||||
<h3 className="font-semibold">{data.location}</h3>
|
||||
@@ -522,6 +503,21 @@ export function CustomWeatherWidget() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Usage example
|
||||
function App() {
|
||||
return (
|
||||
<WeatherWidget
|
||||
data={{
|
||||
location: 'San Francisco',
|
||||
temperature: 22,
|
||||
condition: 'Partly cloudy',
|
||||
humidity: 65,
|
||||
windSpeed: 8,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Reference in New Issue
Block a user