reachat 2.2.0 → 3.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.
Files changed (46) hide show
  1. package/dist/{CSVFileRenderer-BOdL4Jte.js → CSVFileRenderer-C2E4Xnkz.js} +2 -2
  2. package/dist/{CSVFileRenderer-BOdL4Jte.js.map → CSVFileRenderer-C2E4Xnkz.js.map} +1 -1
  3. package/dist/Chat.d.ts +12 -0
  4. package/dist/{Markdown/charts/ChartError.d.ts → ComponentCatalog/ComponentError.d.ts} +2 -2
  5. package/dist/ComponentCatalog/ComponentPre.d.ts +18 -0
  6. package/dist/ComponentCatalog/ComponentRenderer.d.ts +17 -0
  7. package/dist/ComponentCatalog/chartComponentDef.d.ts +36 -0
  8. package/dist/ComponentCatalog/componentCatalog.d.ts +44 -0
  9. package/dist/ComponentCatalog/componentCatalog.spec.d.ts +1 -0
  10. package/dist/ComponentCatalog/generatePrompt.d.ts +9 -0
  11. package/dist/ComponentCatalog/generatePrompt.spec.d.ts +1 -0
  12. package/dist/ComponentCatalog/index.d.ts +9 -0
  13. package/dist/ComponentCatalog/types.d.ts +108 -0
  14. package/dist/ComponentCatalog/validateSpec.d.ts +17 -0
  15. package/dist/ComponentCatalog/validateSpec.spec.d.ts +1 -0
  16. package/dist/{DefaultFileRenderer-C2MsQ9wz.js → DefaultFileRenderer-Day12qYs.js} +2 -2
  17. package/dist/{DefaultFileRenderer-C2MsQ9wz.js.map → DefaultFileRenderer-Day12qYs.js.map} +1 -1
  18. package/dist/Markdown/charts/ChartRenderer.d.ts +1 -1
  19. package/dist/Markdown/charts/ComponentError.d.ts +1 -0
  20. package/dist/Markdown/charts/index.d.ts +2 -6
  21. package/dist/Markdown/charts/types.d.ts +21 -0
  22. package/dist/Markdown/plugins/index.d.ts +1 -1
  23. package/dist/Markdown/plugins/remarkComponent.d.ts +27 -0
  24. package/dist/docs.json +275 -93
  25. package/dist/{index-DdRyk11n.js → index-CZSBRZbI.js} +524 -230
  26. package/dist/index-CZSBRZbI.js.map +1 -0
  27. package/dist/index.css +101 -1077
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +22 -22
  30. package/dist/index.umd.cjs +509 -215
  31. package/dist/index.umd.cjs.map +1 -1
  32. package/dist/stories/Changelog.mdx +1 -1
  33. package/dist/stories/Charts.stories.tsx +118 -130
  34. package/dist/stories/ComponentCatalog.stories.tsx +509 -0
  35. package/dist/stories/{ChartError.stories.tsx → ComponentError.stories.tsx} +14 -11
  36. package/dist/stories/Intro.mdx +1 -1
  37. package/dist/theme.d.ts +3 -0
  38. package/dist/utils/getChildText.d.ts +10 -0
  39. package/dist/utils/getChildText.spec.d.ts +1 -0
  40. package/package.json +27 -30
  41. package/dist/Markdown/charts/ChartPre.d.ts +0 -6
  42. package/dist/Markdown/charts/chartHelpers.d.ts +0 -40
  43. package/dist/Markdown/plugins/remarkChart.d.ts +0 -59
  44. package/dist/index-DdRyk11n.js.map +0 -1
  45. package/dist/stories/Integration.stories.tsx +0 -312
  46. /package/dist/{Markdown/charts/chartHelpers.spec.d.ts → ComponentCatalog/chartComponentDef.spec.d.ts} +0 -0
@@ -0,0 +1,509 @@
1
+ import React from 'react';
2
+ import { Meta } from '@storybook/react';
3
+ import { subHours } from 'date-fns';
4
+ import { z } from 'zod';
5
+ import {
6
+ Chat,
7
+ Session,
8
+ SessionsList,
9
+ SessionGroups,
10
+ NewSessionButton,
11
+ SessionMessages,
12
+ ChatInput,
13
+ SessionMessagePanel,
14
+ SessionMessagesHeader,
15
+ componentCatalog
16
+ } from 'reachat';
17
+
18
+ export default {
19
+ title: 'Demos/ComponentCatalog',
20
+ component: Chat
21
+ } as Meta;
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Sample components
25
+ // ---------------------------------------------------------------------------
26
+
27
+ const WeatherCard = ({
28
+ city,
29
+ temperature,
30
+ condition
31
+ }: {
32
+ city: string;
33
+ temperature: number;
34
+ condition: string;
35
+ }) => (
36
+ <div
37
+ style={{
38
+ padding: '16px',
39
+ borderRadius: '12px',
40
+ background:
41
+ condition === 'sunny'
42
+ ? 'linear-gradient(135deg, #f6d365 0%, #fda085 100%)'
43
+ : condition === 'rainy'
44
+ ? 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
45
+ : 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)',
46
+ color: condition === 'rainy' ? '#fff' : '#1a1a2e',
47
+ minWidth: 200
48
+ }}
49
+ >
50
+ <div style={{ fontSize: '14px', opacity: 0.8 }}>{condition}</div>
51
+ <div style={{ fontSize: '24px', fontWeight: 700 }}>{city}</div>
52
+ <div style={{ fontSize: '36px', fontWeight: 300 }}>{temperature}°F</div>
53
+ </div>
54
+ );
55
+
56
+ const AlertBox = ({
57
+ title,
58
+ message,
59
+ severity
60
+ }: {
61
+ title: string;
62
+ message: string;
63
+ severity: string;
64
+ }) => {
65
+ const colors: Record<string, { bg: string; border: string; text: string }> = {
66
+ info: { bg: '#e3f2fd', border: '#90caf9', text: '#1565c0' },
67
+ warning: { bg: '#fff3e0', border: '#ffcc80', text: '#e65100' },
68
+ error: { bg: '#ffebee', border: '#ef9a9a', text: '#c62828' },
69
+ success: { bg: '#e8f5e9', border: '#a5d6a7', text: '#2e7d32' }
70
+ };
71
+ const c = colors[severity] || colors.info;
72
+ return (
73
+ <div
74
+ style={{
75
+ padding: '12px 16px',
76
+ borderRadius: '8px',
77
+ border: `1px solid ${c.border}`,
78
+ background: c.bg,
79
+ color: c.text
80
+ }}
81
+ >
82
+ <div style={{ fontWeight: 600, marginBottom: 4 }}>{title}</div>
83
+ <div style={{ fontSize: '14px' }}>{message}</div>
84
+ </div>
85
+ );
86
+ };
87
+
88
+ const StatusBadge = ({
89
+ label,
90
+ status
91
+ }: {
92
+ label: string;
93
+ status: string;
94
+ }) => {
95
+ const colors: Record<string, string> = {
96
+ online: '#22c55e',
97
+ offline: '#ef4444',
98
+ away: '#f59e0b',
99
+ busy: '#ef4444'
100
+ };
101
+ return (
102
+ <span
103
+ style={{
104
+ display: 'inline-flex',
105
+ alignItems: 'center',
106
+ gap: 6,
107
+ padding: '4px 12px',
108
+ borderRadius: '999px',
109
+ background: `${colors[status] || '#6b7280'}20`,
110
+ color: colors[status] || '#6b7280',
111
+ fontSize: '13px',
112
+ fontWeight: 500
113
+ }}
114
+ >
115
+ <span
116
+ style={{
117
+ width: 8,
118
+ height: 8,
119
+ borderRadius: '50%',
120
+ background: colors[status] || '#6b7280'
121
+ }}
122
+ />
123
+ {label}
124
+ </span>
125
+ );
126
+ };
127
+
128
+ const DataCard = ({
129
+ title,
130
+ value,
131
+ unit,
132
+ trend
133
+ }: {
134
+ title: string;
135
+ value: number;
136
+ unit?: string;
137
+ trend?: string;
138
+ }) => (
139
+ <div
140
+ style={{
141
+ padding: '16px',
142
+ borderRadius: '12px',
143
+ border: '1px solid #e5e7eb',
144
+ background: '#fff',
145
+ minWidth: 160
146
+ }}
147
+ >
148
+ <div style={{ fontSize: '12px', color: '#6b7280', marginBottom: 4 }}>
149
+ {title}
150
+ </div>
151
+ <div style={{ fontSize: '28px', fontWeight: 700, color: '#111827' }}>
152
+ {value}
153
+ {unit && (
154
+ <span style={{ fontSize: '14px', fontWeight: 400, marginLeft: 2 }}>
155
+ {unit}
156
+ </span>
157
+ )}
158
+ </div>
159
+ {trend && (
160
+ <div
161
+ style={{
162
+ fontSize: '12px',
163
+ color: trend.startsWith('+') ? '#22c55e' : '#ef4444',
164
+ marginTop: 4
165
+ }}
166
+ >
167
+ {trend}
168
+ </div>
169
+ )}
170
+ </div>
171
+ );
172
+
173
+ const RowLayout = ({
174
+ children
175
+ }: {
176
+ children?: React.ReactNode;
177
+ }) => (
178
+ <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>{children}</div>
179
+ );
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // Catalog
183
+ // ---------------------------------------------------------------------------
184
+
185
+ const catalog = componentCatalog({
186
+ WeatherCard: {
187
+ description: 'Displays current weather conditions for a city',
188
+ props: z.object({
189
+ city: z.string().describe('City name'),
190
+ temperature: z.number().describe('Temperature in Fahrenheit'),
191
+ condition: z.enum(['sunny', 'cloudy', 'rainy']).describe(
192
+ 'Current weather condition'
193
+ )
194
+ }),
195
+ component: WeatherCard as any
196
+ },
197
+ AlertBox: {
198
+ description: 'Displays an alert or notification box',
199
+ props: z.object({
200
+ title: z.string().describe('Alert title'),
201
+ message: z.string().describe('Alert message body'),
202
+ severity: z.enum(['info', 'warning', 'error', 'success']).describe(
203
+ 'Severity level'
204
+ )
205
+ }),
206
+ component: AlertBox as any
207
+ },
208
+ StatusBadge: {
209
+ description: 'Displays a status indicator badge',
210
+ props: z.object({
211
+ label: z.string().describe('Display label'),
212
+ status: z.enum(['online', 'offline', 'away', 'busy']).describe(
213
+ 'Current status'
214
+ )
215
+ }),
216
+ component: StatusBadge as any
217
+ },
218
+ DataCard: {
219
+ description: 'Displays a single metric or KPI',
220
+ props: z.object({
221
+ title: z.string().describe('Metric name'),
222
+ value: z.number().describe('Metric value'),
223
+ unit: z.string().optional(),
224
+ trend: z.string().optional()
225
+ }),
226
+ component: DataCard as any
227
+ },
228
+ Row: {
229
+ description:
230
+ 'A horizontal flex layout container — use as a parent to lay out child components side-by-side',
231
+ props: z.object({}),
232
+ component: RowLayout as any
233
+ }
234
+ });
235
+
236
+ // ---------------------------------------------------------------------------
237
+ // Session data
238
+ // ---------------------------------------------------------------------------
239
+
240
+ const weatherSpec = {
241
+ type: 'WeatherCard',
242
+ props: { city: 'San Francisco', temperature: 68, condition: 'cloudy' }
243
+ };
244
+
245
+ const alertSpec = {
246
+ type: 'AlertBox',
247
+ props: {
248
+ title: 'Deployment Successful',
249
+ message:
250
+ 'Version 2.4.1 has been deployed to production. All health checks passing.',
251
+ severity: 'success'
252
+ }
253
+ };
254
+
255
+ const multiWeatherSpec = [
256
+ {
257
+ type: 'WeatherCard',
258
+ props: { city: 'San Francisco', temperature: 68, condition: 'cloudy' }
259
+ },
260
+ {
261
+ type: 'WeatherCard',
262
+ props: { city: 'New York', temperature: 45, condition: 'rainy' }
263
+ },
264
+ {
265
+ type: 'WeatherCard',
266
+ props: { city: 'Miami', temperature: 82, condition: 'sunny' }
267
+ }
268
+ ];
269
+
270
+ const dashboardSpec = {
271
+ type: 'Row',
272
+ props: {},
273
+ children: [
274
+ {
275
+ type: 'DataCard',
276
+ props: {
277
+ title: 'Revenue',
278
+ value: 12450,
279
+ unit: '$',
280
+ trend: '+12.5% from last month'
281
+ }
282
+ },
283
+ {
284
+ type: 'DataCard',
285
+ props: {
286
+ title: 'Active Users',
287
+ value: 8423,
288
+ trend: '+5.2% from last week'
289
+ }
290
+ },
291
+ {
292
+ type: 'DataCard',
293
+ props: { title: 'Error Rate', value: 0.3, unit: '%', trend: '-0.1%' }
294
+ }
295
+ ]
296
+ };
297
+
298
+ const sessions: Session[] = [
299
+ {
300
+ id: 'session-1',
301
+ title: 'Dynamic Components Demo',
302
+ createdAt: subHours(new Date(), 2),
303
+ updatedAt: new Date(),
304
+ conversations: [
305
+ {
306
+ id: 'conv-1',
307
+ question: "What's the weather in San Francisco?",
308
+ response: `Here's the current weather:
309
+
310
+ \`\`\`component
311
+ ${JSON.stringify(weatherSpec, null, 2)}
312
+ \`\`\`
313
+
314
+ Looks like a typical foggy day in the city!`,
315
+ createdAt: subHours(new Date(), 2)
316
+ },
317
+ {
318
+ id: 'conv-2',
319
+ question: 'Show me weather for multiple cities',
320
+ response: `Here's a comparison of weather across three cities:
321
+
322
+ \`\`\`component
323
+ ${JSON.stringify(multiWeatherSpec, null, 2)}
324
+ \`\`\`
325
+
326
+ San Francisco is mild, New York is rainy, and Miami is warm and sunny.`,
327
+ createdAt: subHours(new Date(), 1.5)
328
+ },
329
+ {
330
+ id: 'conv-3',
331
+ question: 'Any deployment updates?',
332
+ response: `Yes! Here's the latest update:
333
+
334
+ \`\`\`component
335
+ ${JSON.stringify(alertSpec, null, 2)}
336
+ \`\`\`
337
+
338
+ Everything looks good. All services are healthy.`,
339
+ createdAt: subHours(new Date(), 1)
340
+ },
341
+ {
342
+ id: 'conv-4',
343
+ question: 'Show me the dashboard metrics',
344
+ response: `Here's your dashboard overview with nested components:
345
+
346
+ \`\`\`component
347
+ ${JSON.stringify(dashboardSpec, null, 2)}
348
+ \`\`\`
349
+
350
+ Revenue is trending up and error rates are down. Looking great!`,
351
+ createdAt: subHours(new Date(), 0.5)
352
+ }
353
+ ]
354
+ }
355
+ ];
356
+
357
+ const errorSessions: Session[] = [
358
+ {
359
+ id: 'session-errors',
360
+ title: 'Error Handling Demo',
361
+ createdAt: subHours(new Date(), 1),
362
+ updatedAt: new Date(),
363
+ conversations: [
364
+ {
365
+ id: 'conv-err-1',
366
+ question: 'Show me an unknown component',
367
+ response: `Here's a component that doesn't exist in the catalog:
368
+
369
+ \`\`\`component
370
+ { "type": "NonExistentWidget", "props": { "foo": "bar" } }
371
+ \`\`\`
372
+
373
+ The error should be displayed gracefully above.`,
374
+ createdAt: subHours(new Date(), 1)
375
+ },
376
+ {
377
+ id: 'conv-err-2',
378
+ question: 'Show me invalid JSON',
379
+ response: `Here's some broken JSON:
380
+
381
+ \`\`\`component
382
+ { type: WeatherCard, props: invalid }
383
+ \`\`\`
384
+
385
+ The parser should handle this gracefully.`,
386
+ createdAt: subHours(new Date(), 0.5)
387
+ },
388
+ {
389
+ id: 'conv-err-3',
390
+ question: 'Show me invalid props',
391
+ response: `Here's a valid component type with wrong props:
392
+
393
+ \`\`\`component
394
+ { "type": "WeatherCard", "props": { "city": 123, "temperature": "not-a-number", "condition": "unknown" } }
395
+ \`\`\`
396
+
397
+ Zod validation should catch the prop type mismatches.`,
398
+ createdAt: new Date()
399
+ }
400
+ ]
401
+ }
402
+ ];
403
+
404
+ // ---------------------------------------------------------------------------
405
+ // Stories
406
+ // ---------------------------------------------------------------------------
407
+
408
+ const storyStyle = {
409
+ position: 'absolute' as const,
410
+ top: 0,
411
+ left: 0,
412
+ right: 0,
413
+ bottom: 0,
414
+ padding: 20,
415
+ margin: 20,
416
+ borderRadius: 5
417
+ };
418
+
419
+ export const BasicExample = () => (
420
+ <div className="dark:bg-gray-950 bg-white" style={storyStyle}>
421
+ <Chat
422
+ viewType="console"
423
+ sessions={sessions}
424
+ activeSessionId="session-1"
425
+ components={catalog}
426
+ >
427
+ <SessionsList>
428
+ <NewSessionButton />
429
+ <SessionGroups />
430
+ </SessionsList>
431
+ <SessionMessagePanel>
432
+ <SessionMessagesHeader />
433
+ <SessionMessages />
434
+ <ChatInput />
435
+ </SessionMessagePanel>
436
+ </Chat>
437
+ </div>
438
+ );
439
+
440
+ export const ErrorHandling = () => (
441
+ <div className="dark:bg-gray-950 bg-white" style={storyStyle}>
442
+ <Chat
443
+ viewType="console"
444
+ sessions={errorSessions}
445
+ activeSessionId="session-errors"
446
+ components={catalog}
447
+ >
448
+ <SessionsList>
449
+ <NewSessionButton />
450
+ <SessionGroups />
451
+ </SessionsList>
452
+ <SessionMessagePanel>
453
+ <SessionMessagesHeader />
454
+ <SessionMessages />
455
+ <ChatInput />
456
+ </SessionMessagePanel>
457
+ </Chat>
458
+ </div>
459
+ );
460
+
461
+ export const ChatViewOnly = () => (
462
+ <div
463
+ className="dark:bg-gray-950 bg-white"
464
+ style={{ ...storyStyle, maxWidth: 800, marginLeft: 'auto', marginRight: 'auto' }}
465
+ >
466
+ <Chat
467
+ viewType="chat"
468
+ sessions={sessions}
469
+ activeSessionId="session-1"
470
+ components={catalog}
471
+ >
472
+ <SessionMessagePanel>
473
+ <SessionMessagesHeader />
474
+ <SessionMessages />
475
+ <ChatInput />
476
+ </SessionMessagePanel>
477
+ </Chat>
478
+ </div>
479
+ );
480
+
481
+ export const SystemPromptPreview = () => {
482
+ const prompt = catalog.systemPrompt();
483
+ return (
484
+ <div style={{ padding: 40, maxWidth: 800 }}>
485
+ <h2 style={{ marginBottom: 16, fontSize: 20, fontWeight: 600 }}>
486
+ Generated LLM System Prompt
487
+ </h2>
488
+ <p style={{ marginBottom: 16, color: '#6b7280', fontSize: 14 }}>
489
+ This is what <code>catalog.systemPrompt()</code> generates.
490
+ Include this in your LLM system message so it knows how to use
491
+ your registered components.
492
+ </p>
493
+ <pre
494
+ style={{
495
+ padding: 20,
496
+ borderRadius: 8,
497
+ background: '#1e1e2e',
498
+ color: '#cdd6f4',
499
+ fontSize: 13,
500
+ lineHeight: 1.6,
501
+ overflow: 'auto',
502
+ whiteSpace: 'pre-wrap'
503
+ }}
504
+ >
505
+ {prompt}
506
+ </pre>
507
+ </div>
508
+ );
509
+ };
@@ -2,16 +2,20 @@ import React from 'react';
2
2
  import { Meta } from '@storybook/react';
3
3
  import {
4
4
  Chat,
5
- remarkChart,
6
- chartComponents,
7
- ChartError
5
+ ComponentError,
6
+ componentCatalog,
7
+ createChartComponentDef
8
8
  } from 'reachat';
9
9
 
10
10
  export default {
11
- title: 'Components/ChartError',
12
- component: ChartError
11
+ title: 'Components/ComponentError',
12
+ component: ComponentError
13
13
  } as Meta;
14
14
 
15
+ const catalog = componentCatalog({
16
+ Chart: createChartComponentDef()
17
+ });
18
+
15
19
  const Wrapper = ({ children }: { children: React.ReactNode }) => (
16
20
  <div
17
21
  className="dark:bg-gray-950 bg-white"
@@ -28,8 +32,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
28
32
  viewType="chat"
29
33
  sessions={[]}
30
34
  activeSessionId=""
31
- remarkPlugins={[remarkChart]}
32
- markdownComponents={chartComponents}
35
+ components={catalog}
33
36
  >
34
37
  <div style={{ maxWidth: 500 }}>{children}</div>
35
38
  </Chat>
@@ -38,7 +41,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => (
38
41
 
39
42
  export const Default = () => (
40
43
  <Wrapper>
41
- <ChartError
44
+ <ComponentError
42
45
  title="Failed to render chart"
43
46
  message="The chart data could not be parsed. Please check the JSON format."
44
47
  />
@@ -47,7 +50,7 @@ export const Default = () => (
47
50
 
48
51
  export const WithCode = () => (
49
52
  <Wrapper>
50
- <ChartError
53
+ <ComponentError
51
54
  title="Invalid chart configuration"
52
55
  message="The 'type' field is missing from the chart configuration."
53
56
  code={`{
@@ -62,7 +65,7 @@ export const WithCode = () => (
62
65
 
63
66
  export const Warning = () => (
64
67
  <Wrapper>
65
- <ChartError
68
+ <ComponentError
66
69
  variant="warning"
67
70
  title="Chart data incomplete"
68
71
  message="Some data points are missing values. The chart may not display correctly."
@@ -72,7 +75,7 @@ export const Warning = () => (
72
75
 
73
76
  export const WarningWithCode = () => (
74
77
  <Wrapper>
75
- <ChartError
78
+ <ComponentError
76
79
  variant="warning"
77
80
  title="Unsupported chart type"
78
81
  message="The chart type 'scatter' is not supported. Falling back to bar chart."
@@ -1,4 +1,4 @@
1
- import { Meta } from '@storybook/addon-docs';
1
+ import { Meta } from '@storybook/addon-docs/blocks';
2
2
 
3
3
  <Meta title="Docs/Intro" />
4
4
 
package/dist/theme.d.ts CHANGED
@@ -159,5 +159,8 @@ export interface ChatTheme {
159
159
  title: string;
160
160
  };
161
161
  };
162
+ component?: {
163
+ base?: string;
164
+ };
162
165
  }
163
166
  export declare const chatTheme: ChatTheme;
@@ -0,0 +1,10 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * Recursively extracts text content from React children.
4
+ * Handles strings, numbers, arrays, and React elements by traversing
5
+ * their children props.
6
+ *
7
+ * @param children - The React children to extract text from
8
+ * @returns The concatenated text content as a string
9
+ */
10
+ export declare function getChildText(children: React.ReactNode): string;
@@ -0,0 +1 @@
1
+ export {};