@melony/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 +237 -0
- package/dist/index.cjs +2371 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +165 -0
- package/dist/index.d.ts +165 -0
- package/dist/index.js +2334 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
# @melony/react
|
|
2
|
+
|
|
3
|
+
React components and hooks for building AI chat interfaces with Melony.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @melony/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { MelonyStoreProvider, Thread, ThreadSidebar, useMelony } from "@melony/react";
|
|
15
|
+
|
|
16
|
+
function ThreadApp() {
|
|
17
|
+
const { threads, activeThreadId, messages, isLoading } = useMelony();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<div style={{ display: 'flex', height: '100vh' }}>
|
|
21
|
+
<ThreadSidebar threads={threads} activeThreadId={activeThreadId} />
|
|
22
|
+
<Thread messages={messages} isLoading={isLoading} />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default function App() {
|
|
28
|
+
return (
|
|
29
|
+
<MelonyStoreProvider api="/api/chat">
|
|
30
|
+
<ThreadApp />
|
|
31
|
+
</MelonyStoreProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Architecture
|
|
37
|
+
|
|
38
|
+
Melony React uses an **event-based architecture** where all actions are dispatched as events:
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
const { dispatchEvent } = useMelony();
|
|
42
|
+
|
|
43
|
+
// Create a thread
|
|
44
|
+
dispatchEvent({ type: 'createThread' });
|
|
45
|
+
|
|
46
|
+
// Switch thread
|
|
47
|
+
dispatchEvent({ type: 'switchThread', data: { threadId: 'abc' } });
|
|
48
|
+
|
|
49
|
+
// Send a message
|
|
50
|
+
dispatchEvent({
|
|
51
|
+
type: 'sendMessage',
|
|
52
|
+
data: {
|
|
53
|
+
role: 'user',
|
|
54
|
+
content: [{ type: 'text', data: { content: 'Hello!' } }]
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Core Components
|
|
60
|
+
|
|
61
|
+
### `MelonyStoreProvider`
|
|
62
|
+
|
|
63
|
+
The main provider that manages threads, messages, and API communication.
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
<MelonyStoreProvider
|
|
67
|
+
api="/api/chat"
|
|
68
|
+
onLoadHistory={async (threadId) => {
|
|
69
|
+
// Load message history when switching threads
|
|
70
|
+
const res = await fetch(`/api/threads/${threadId}/messages`);
|
|
71
|
+
return res.json();
|
|
72
|
+
}}
|
|
73
|
+
onThreadsChange={(threads) => {
|
|
74
|
+
// Persist threads (e.g., to localStorage)
|
|
75
|
+
localStorage.setItem('threads', JSON.stringify(threads));
|
|
76
|
+
}}
|
|
77
|
+
onEvent={(event) => {
|
|
78
|
+
// Handle custom events
|
|
79
|
+
console.log('Event:', event.type);
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<App />
|
|
83
|
+
</MelonyStoreProvider>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `Thread`
|
|
87
|
+
|
|
88
|
+
The main thread interface component.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
<Thread
|
|
92
|
+
messages={messages}
|
|
93
|
+
isLoading={isLoading}
|
|
94
|
+
placeholder="Type a message..."
|
|
95
|
+
components={{
|
|
96
|
+
// Custom components for Server-Driven UI
|
|
97
|
+
'weather-card': WeatherCard,
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### `ThreadSidebar`
|
|
103
|
+
|
|
104
|
+
Sidebar showing list of conversation threads.
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
<ThreadSidebar
|
|
108
|
+
threads={threads}
|
|
109
|
+
activeThreadId={activeThreadId}
|
|
110
|
+
width={280}
|
|
111
|
+
/>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Hooks
|
|
115
|
+
|
|
116
|
+
### `useMelony()`
|
|
117
|
+
|
|
118
|
+
Main hook to access store state and dispatch events.
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
const {
|
|
122
|
+
// State
|
|
123
|
+
threads, // Thread[] - all threads
|
|
124
|
+
activeThreadId, // string | null
|
|
125
|
+
activeThread, // Thread | undefined
|
|
126
|
+
messages, // ChatMessage[] - messages in active thread
|
|
127
|
+
isLoading, // boolean
|
|
128
|
+
error, // Error | null
|
|
129
|
+
|
|
130
|
+
// Methods
|
|
131
|
+
dispatchEvent, // (event: Event) => void
|
|
132
|
+
getThread, // (id: string) => Thread | undefined
|
|
133
|
+
getThreadMessages, // (id: string) => ChatMessage[]
|
|
134
|
+
} = useMelony();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### `useDispatchedEvent()`
|
|
138
|
+
|
|
139
|
+
Listen to events dispatched through the system.
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
useDispatchedEvent((event) => {
|
|
143
|
+
if (event.type === 'sendMessage') {
|
|
144
|
+
console.log('Message sent!');
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Event Types
|
|
150
|
+
|
|
151
|
+
| Event | Data | Description |
|
|
152
|
+
|-------|------|-------------|
|
|
153
|
+
| `createThread` | `{ initialMessage?, title? }` | Create a new thread |
|
|
154
|
+
| `switchThread` | `{ threadId }` | Switch to a thread |
|
|
155
|
+
| `deleteThread` | `{ threadId }` | Delete a thread |
|
|
156
|
+
| `updateThreadTitle` | `{ threadId, title }` | Update thread title |
|
|
157
|
+
| `sendMessage` | `{ role, content, threadId? }` | Send a message |
|
|
158
|
+
| `clearThread` | `{ threadId? }` | Clear thread messages |
|
|
159
|
+
|
|
160
|
+
## UI Components
|
|
161
|
+
|
|
162
|
+
Layout: `Row`, `Col`, `Box`, `Spacer`, `Divider`, `List`, `ListItem`
|
|
163
|
+
Content: `Text`, `Heading`, `Image`, `Icon`, `Badge`, `Chart`
|
|
164
|
+
Forms: `Button`, `Input`, `Textarea`, `Select`, `Checkbox`, `RadioGroup`, `Form`, `Label`
|
|
165
|
+
Containers: `Card`
|
|
166
|
+
|
|
167
|
+
## Server-Driven UI
|
|
168
|
+
|
|
169
|
+
Components can render UI from server events:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
// Server sends:
|
|
173
|
+
yield {
|
|
174
|
+
type: 'ui',
|
|
175
|
+
ui: {
|
|
176
|
+
type: 'card',
|
|
177
|
+
props: { title: 'Weather' },
|
|
178
|
+
children: [
|
|
179
|
+
{ type: 'text', props: { value: '72°F' } }
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Renderer automatically displays the Card with Text
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Theming
|
|
188
|
+
|
|
189
|
+
```tsx
|
|
190
|
+
<MelonyStoreProvider
|
|
191
|
+
api="/api/chat"
|
|
192
|
+
theme={{
|
|
193
|
+
colors: {
|
|
194
|
+
primary: '#6366f1',
|
|
195
|
+
background: '#ffffff',
|
|
196
|
+
},
|
|
197
|
+
radius: {
|
|
198
|
+
md: '8px',
|
|
199
|
+
},
|
|
200
|
+
}}
|
|
201
|
+
>
|
|
202
|
+
<App />
|
|
203
|
+
</MelonyStoreProvider>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Migration from Legacy Hooks
|
|
207
|
+
|
|
208
|
+
If you're using the deprecated hooks (`useMelonyRuntime`, `useMelonyThread`, `useMelonyThreads`):
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
// Before:
|
|
212
|
+
const { messages, sendMessage } = useMelonyThread({ api: '/api/chat' });
|
|
213
|
+
const { threads, createThread } = useMelonyThreads({ threads, activeThreadId });
|
|
214
|
+
|
|
215
|
+
// After:
|
|
216
|
+
// 1. Wrap with MelonyStoreProvider
|
|
217
|
+
// 2. Use useMelony()
|
|
218
|
+
const { messages, threads, dispatchEvent } = useMelony();
|
|
219
|
+
|
|
220
|
+
// Send message via event
|
|
221
|
+
dispatchEvent({
|
|
222
|
+
type: 'sendMessage',
|
|
223
|
+
data: { role: 'user', content: [...] }
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Create thread via event
|
|
227
|
+
dispatchEvent({ type: 'createThread' });
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Development
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
pnpm build # Build
|
|
234
|
+
pnpm dev # Watch mode
|
|
235
|
+
pnpm typecheck # Type check
|
|
236
|
+
pnpm clean # Clean dist
|
|
237
|
+
```
|