@hsafa/ui-sdk 0.3.3 → 0.4.1

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.
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Dynamic Page Complete Example
3
+ * Shows how to integrate Dynamic Page system with HsafaChat and ContentContainer
4
+ */
5
+
6
+ import React, { useState } from 'react';
7
+ import {
8
+ HsafaProvider,
9
+ HsafaChat,
10
+ ContentContainer,
11
+ DynamicPageTypeConfig,
12
+ } from '@hsafa/ui-sdk';
13
+
14
+ // ============================================================================
15
+ // Step 1: Create Your Custom Components
16
+ // ============================================================================
17
+
18
+ // Simple Chart Component
19
+ function ChartComponent({ data }: { data: any }) {
20
+ const maxValue = Math.max(
21
+ ...((data.series || []).flatMap((s: any) => s.values || []))
22
+ );
23
+
24
+ return (
25
+ <div style={{ width: '100%', height: '100%', padding: '8px' }}>
26
+ <h4 style={{ margin: '0 0 12px 0', fontSize: '14px', fontWeight: 600 }}>
27
+ {data.title || 'Chart'}
28
+ </h4>
29
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
30
+ {(data.series || []).map((series: any, i: number) => (
31
+ <div key={i}>
32
+ <div style={{ fontSize: '12px', marginBottom: '6px', opacity: 0.7 }}>
33
+ {series.name}
34
+ </div>
35
+ <div
36
+ style={{
37
+ display: 'flex',
38
+ gap: '4px',
39
+ alignItems: 'flex-end',
40
+ height: '80px',
41
+ }}
42
+ >
43
+ {(series.values || []).map((value: number, j: number) => (
44
+ <div
45
+ key={j}
46
+ style={{
47
+ flex: 1,
48
+ backgroundColor: '#3b82f6',
49
+ height: `${(value / maxValue) * 100}%`,
50
+ borderRadius: '4px 4px 0 0',
51
+ minWidth: '20px',
52
+ position: 'relative',
53
+ }}
54
+ title={`${series.name}: ${value}`}
55
+ >
56
+ <span
57
+ style={{
58
+ position: 'absolute',
59
+ top: '-20px',
60
+ left: '50%',
61
+ transform: 'translateX(-50%)',
62
+ fontSize: '11px',
63
+ whiteSpace: 'nowrap',
64
+ }}
65
+ >
66
+ {value}
67
+ </span>
68
+ </div>
69
+ ))}
70
+ </div>
71
+ </div>
72
+ ))}
73
+ </div>
74
+ </div>
75
+ );
76
+ }
77
+
78
+ // Simple Table Component
79
+ function TableComponent({ data }: { data: any }) {
80
+ return (
81
+ <div style={{ width: '100%', height: '100%', overflow: 'auto' }}>
82
+ <table style={{ width: '100%', borderCollapse: 'collapse' }}>
83
+ <thead>
84
+ <tr>
85
+ {(data.columns || []).map((col: string, i: number) => (
86
+ <th
87
+ key={i}
88
+ style={{
89
+ padding: '8px',
90
+ textAlign: 'left',
91
+ borderBottom: '2px solid #e5e7eb',
92
+ fontSize: '12px',
93
+ fontWeight: 600,
94
+ }}
95
+ >
96
+ {col}
97
+ </th>
98
+ ))}
99
+ </tr>
100
+ </thead>
101
+ <tbody>
102
+ {(data.rows || []).map((row: any[], i: number) => (
103
+ <tr key={i}>
104
+ {row.map((cell, j) => (
105
+ <td
106
+ key={j}
107
+ style={{
108
+ padding: '8px',
109
+ borderBottom: '1px solid #e5e7eb',
110
+ fontSize: '13px',
111
+ }}
112
+ >
113
+ {cell}
114
+ </td>
115
+ ))}
116
+ </tr>
117
+ ))}
118
+ </tbody>
119
+ </table>
120
+ </div>
121
+ );
122
+ }
123
+
124
+ // Simple Text Component
125
+ function TextComponent({ data }: { data: any }) {
126
+ return (
127
+ <div style={{ width: '100%', height: '100%', padding: '16px' }}>
128
+ {data.heading && (
129
+ <h2 style={{ margin: '0 0 12px 0', fontSize: '20px', fontWeight: 700 }}>
130
+ {data.heading}
131
+ </h2>
132
+ )}
133
+ {data.content && (
134
+ <p style={{ margin: 0, fontSize: '14px', lineHeight: 1.6 }}>
135
+ {data.content}
136
+ </p>
137
+ )}
138
+ </div>
139
+ );
140
+ }
141
+
142
+ // Metric Card Component
143
+ function MetricComponent({ data }: { data: any }) {
144
+ return (
145
+ <div
146
+ style={{
147
+ width: '100%',
148
+ height: '100%',
149
+ display: 'flex',
150
+ flexDirection: 'column',
151
+ alignItems: 'center',
152
+ justifyContent: 'center',
153
+ padding: '24px',
154
+ textAlign: 'center',
155
+ }}
156
+ >
157
+ <div style={{ fontSize: '36px', fontWeight: 700, marginBottom: '8px' }}>
158
+ {data.value}
159
+ </div>
160
+ <div style={{ fontSize: '14px', opacity: 0.7 }}>{data.label}</div>
161
+ {data.change && (
162
+ <div
163
+ style={{
164
+ marginTop: '8px',
165
+ fontSize: '12px',
166
+ color: data.change > 0 ? '#10b981' : '#ef4444',
167
+ }}
168
+ >
169
+ {data.change > 0 ? '↑' : '↓'} {Math.abs(data.change)}%
170
+ </div>
171
+ )}
172
+ </div>
173
+ );
174
+ }
175
+
176
+ // ============================================================================
177
+ // Step 2: Register Your Types
178
+ // ============================================================================
179
+
180
+ const dynamicPageTypes: DynamicPageTypeConfig[] = [
181
+ {
182
+ type: 'chart',
183
+ component: ChartComponent,
184
+ description: 'Display data as bar charts with multiple series',
185
+ variants: ['bar', 'line', 'area'],
186
+ },
187
+ {
188
+ type: 'table',
189
+ component: TableComponent,
190
+ description: 'Display data in a tabular format with rows and columns',
191
+ },
192
+ {
193
+ type: 'text',
194
+ component: TextComponent,
195
+ description: 'Display text content with optional heading',
196
+ },
197
+ {
198
+ type: 'metric',
199
+ component: MetricComponent,
200
+ description: 'Display a single metric value with label and change indicator',
201
+ },
202
+ ];
203
+
204
+ // ============================================================================
205
+ // Step 3: Create Your App Component
206
+ // ============================================================================
207
+
208
+ export function DynamicPageExampleApp() {
209
+ const [agentId] = useState('dynamic-page-demo');
210
+
211
+ return (
212
+ <HsafaProvider baseUrl="http://localhost:3000">
213
+ <ContentContainer
214
+ theme="dark"
215
+ enableBorderAnimation={true}
216
+ enableMargin={true}
217
+ chatWidth={420}
218
+ >
219
+ <div
220
+ style={{
221
+ padding: '32px',
222
+ display: 'flex',
223
+ flexDirection: 'column',
224
+ gap: '16px',
225
+ }}
226
+ >
227
+ <h1>Dynamic Page Example</h1>
228
+ <p>
229
+ Try asking the agent to create visualizations! For example:
230
+ </p>
231
+ <ul>
232
+ <li>"Create a 2x2 dashboard grid"</li>
233
+ <li>"Add a sales chart to the top-left area"</li>
234
+ <li>"Show me what types of visualizations you can create"</li>
235
+ <li>"Add a table with customer data to the bottom area"</li>
236
+ <li>"Update the chart to show Q4 data"</li>
237
+ </ul>
238
+ </div>
239
+ </ContentContainer>
240
+
241
+ <HsafaChat
242
+ agentId={agentId}
243
+ theme="dark"
244
+ defaultOpen={true}
245
+ dynamicPageTypes={dynamicPageTypes}
246
+ />
247
+ </HsafaProvider>
248
+ );
249
+ }
250
+
251
+ // ============================================================================
252
+ // Example Agent Prompts and Expected Behavior
253
+ // ============================================================================
254
+
255
+ /*
256
+
257
+ EXAMPLE 1: Create a Dashboard
258
+ User: "Create a dashboard with 3 rows and 2 columns"
259
+ Agent:
260
+ 1. Calls setGrid with gridTemplateColumns: "1fr 1fr", gridTemplateRows: "auto 1fr 1fr"
261
+ 2. Returns: "Grid created with 3 rows and 2 columns"
262
+
263
+ EXAMPLE 2: Add a Chart
264
+ User: "Add a sales chart showing monthly data"
265
+ Agent:
266
+ 1. Calls readAvailableTypes() to see what's available
267
+ 2. Calls setObject with:
268
+ {
269
+ object_name: "sales_chart",
270
+ type: "chart",
271
+ data: {
272
+ title: "Monthly Sales",
273
+ series: [{
274
+ name: "Revenue",
275
+ values: [1000, 1200, 1100, 1500]
276
+ }]
277
+ },
278
+ meta: { title: "Sales Chart" }
279
+ }
280
+ 3. Returns: "Chart added successfully"
281
+
282
+ EXAMPLE 3: Update Existing Data
283
+ User: "Add December data with value 1800 to the sales chart"
284
+ Agent:
285
+ 1. Calls editObject with:
286
+ {
287
+ object_name: "sales_chart",
288
+ json_patch: [
289
+ { op: "add", path: "/data/series/0/values/-", value: 1800 }
290
+ ]
291
+ }
292
+ 2. Returns: "Chart updated successfully"
293
+
294
+ EXAMPLE 4: Create Complex Layout
295
+ User: "Create a dashboard with header, main chart area, sidebar for metrics, and footer"
296
+ Agent:
297
+ 1. Calls setGrid with:
298
+ {
299
+ gridTemplateColumns: "2fr 1fr",
300
+ gridTemplateRows: "auto 1fr auto",
301
+ gap: "16px",
302
+ gridTemplateAreas: `
303
+ "header header"
304
+ "main sidebar"
305
+ "footer footer"
306
+ `
307
+ }
308
+ 2. Adds multiple objects using setObject for each area
309
+ 3. Returns: "Dashboard created with 4 sections"
310
+
311
+ EXAMPLE 5: Handle Errors Gracefully
312
+ User: "Delete the chart named 'nonexistent'"
313
+ Agent:
314
+ 1. Calls deleteObject({ object_name: "nonexistent" })
315
+ 2. Receives: { success: false, message: "Object 'nonexistent' not found..." }
316
+ 3. Responds: "I couldn't find a chart named 'nonexistent'. Here are the available objects: ..."
317
+
318
+ */
319
+
320
+ // ============================================================================
321
+ // Advanced Example: With State Management
322
+ // ============================================================================
323
+
324
+ export function AdvancedDynamicPageExample() {
325
+ const [chatId, setChatId] = useState(
326
+ `chat_${Date.now()}_${Math.random().toString(36).slice(2)}`
327
+ );
328
+
329
+ // You can track when dynamic page opens
330
+ const [dynamicPageActive, setDynamicPageActive] = useState(false);
331
+
332
+ return (
333
+ <HsafaProvider baseUrl="http://localhost:3000">
334
+ <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
335
+ {dynamicPageActive && (
336
+ <div
337
+ style={{
338
+ position: 'absolute',
339
+ top: '16px',
340
+ left: '16px',
341
+ zIndex: 1000,
342
+ padding: '8px 16px',
343
+ backgroundColor: '#10b981',
344
+ color: 'white',
345
+ borderRadius: '8px',
346
+ fontSize: '14px',
347
+ }}
348
+ >
349
+ Dynamic Page Active
350
+ </div>
351
+ )}
352
+
353
+ <ContentContainer
354
+ theme="dark"
355
+ enableBorderAnimation={true}
356
+ >
357
+ <YourMainApp />
358
+ </ContentContainer>
359
+
360
+ <HsafaChat
361
+ agentId="advanced-demo"
362
+ dynamicPageTypes={dynamicPageTypes}
363
+ onDynamicPageChange={(isActive) => setDynamicPageActive(isActive)}
364
+ />
365
+ </div>
366
+ </HsafaProvider>
367
+ );
368
+ }
369
+
370
+ // Placeholder for your main app
371
+ function YourMainApp() {
372
+ return (
373
+ <div style={{ padding: '32px' }}>
374
+ <h1>Your Application</h1>
375
+ <p>When the agent creates a dynamic page, it will overlay your content.</p>
376
+ </div>
377
+ );
378
+ }
379
+
380
+ export default DynamicPageExampleApp;