@delightui/components 0.1.104 → 0.1.106

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 (120) hide show
  1. package/README.md +104 -1
  2. package/dist/cjs/components/molecules/Modal/DemoModal.d.ts +8 -0
  3. package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
  4. package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
  5. package/dist/cjs/components/molecules/Modal/ModalContext/index.d.ts +3 -0
  6. package/dist/cjs/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
  7. package/dist/cjs/components/molecules/Modal/index.d.ts +2 -0
  8. package/dist/cjs/components/molecules/Popover/Popover.presenter.d.ts +26 -0
  9. package/dist/cjs/components/molecules/Select/Option/Option.types.d.ts +6 -0
  10. package/dist/cjs/components/molecules/Select/Select.Context.d.ts +1 -1
  11. package/dist/cjs/components/molecules/Select/Select.d.ts +5 -5
  12. package/dist/cjs/components/molecules/Select/Select.presenter.d.ts +1 -0
  13. package/dist/cjs/components/molecules/Select/Select.types.d.ts +5 -0
  14. package/dist/cjs/components/molecules/Select/index.d.ts +2 -9
  15. package/dist/cjs/components/molecules/index.d.ts +2 -0
  16. package/dist/cjs/components/utils/accessibilityUtils.d.ts +41 -0
  17. package/dist/cjs/components/utils/index.d.ts +2 -0
  18. package/dist/cjs/library.css +13 -0
  19. package/dist/cjs/library.js +2 -2
  20. package/dist/cjs/library.js.map +1 -1
  21. package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
  22. package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
  23. package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
  24. package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
  25. package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
  26. package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
  27. package/dist/esm/components/molecules/Popover/Popover.presenter.d.ts +26 -0
  28. package/dist/esm/components/molecules/Select/Option/Option.types.d.ts +6 -0
  29. package/dist/esm/components/molecules/Select/Select.Context.d.ts +1 -1
  30. package/dist/esm/components/molecules/Select/Select.d.ts +5 -5
  31. package/dist/esm/components/molecules/Select/Select.presenter.d.ts +1 -0
  32. package/dist/esm/components/molecules/Select/Select.types.d.ts +5 -0
  33. package/dist/esm/components/molecules/Select/index.d.ts +2 -9
  34. package/dist/esm/components/molecules/index.d.ts +2 -0
  35. package/dist/esm/components/utils/accessibilityUtils.d.ts +41 -0
  36. package/dist/esm/components/utils/index.d.ts +2 -0
  37. package/dist/esm/library.css +13 -0
  38. package/dist/esm/library.js +3 -3
  39. package/dist/esm/library.js.map +1 -1
  40. package/dist/index.d.ts +156 -12
  41. package/docs/README.md +264 -0
  42. package/docs/components/atoms/ActionImage.md +119 -0
  43. package/docs/components/atoms/Button.md +197 -0
  44. package/docs/components/atoms/Checkbox.md +299 -0
  45. package/docs/components/atoms/CheckboxItem.md +314 -0
  46. package/docs/components/atoms/Chip.md +380 -0
  47. package/docs/components/atoms/CustomToggle.md +270 -0
  48. package/docs/components/atoms/Icon.md +365 -0
  49. package/docs/components/atoms/IconButton.md +407 -0
  50. package/docs/components/atoms/Image.md +448 -0
  51. package/docs/components/atoms/Input.md +430 -0
  52. package/docs/components/atoms/ListItem.md +502 -0
  53. package/docs/components/atoms/Password.md +472 -0
  54. package/docs/components/atoms/RadioButton.md +614 -0
  55. package/docs/components/atoms/RadioButtonItem.md +588 -0
  56. package/docs/components/atoms/ResponsiveComponent.md +612 -0
  57. package/docs/components/atoms/SelectListItem.md +609 -0
  58. package/docs/components/atoms/Slider.md +605 -0
  59. package/docs/components/atoms/Spinner.md +605 -0
  60. package/docs/components/atoms/Text.md +463 -0
  61. package/docs/components/atoms/TextArea.md +670 -0
  62. package/docs/components/atoms/ToastNotification.md +668 -0
  63. package/docs/components/atoms/Toggle.md +737 -0
  64. package/docs/components/atoms/ToggleButton.md +751 -0
  65. package/docs/components/atoms/Tooltip.md +391 -0
  66. package/docs/components/molecules/Accordion.md +440 -0
  67. package/docs/components/molecules/AccordionGroup.md +547 -0
  68. package/docs/components/molecules/ActionCard.md +546 -0
  69. package/docs/components/molecules/Breadcrumb.md +403 -0
  70. package/docs/components/molecules/Breadcrumbs.md +485 -0
  71. package/docs/components/molecules/ButtonGroup.md +383 -0
  72. package/docs/components/molecules/Card.md +298 -0
  73. package/docs/components/molecules/ChipInput.md +646 -0
  74. package/docs/components/molecules/ContextMenu.md +768 -0
  75. package/docs/components/molecules/CustomTimeSelector.md +116 -0
  76. package/docs/components/molecules/DatePicker.md +516 -0
  77. package/docs/components/molecules/DateTimeSelector.md +166 -0
  78. package/docs/components/molecules/FormField.md +312 -0
  79. package/docs/components/molecules/Grid.md +577 -0
  80. package/docs/components/molecules/GridItem.md +834 -0
  81. package/docs/components/molecules/GridList.md +244 -0
  82. package/docs/components/molecules/List.md +485 -0
  83. package/docs/components/molecules/Modal.md +470 -0
  84. package/docs/components/molecules/ModalFooter.md +702 -0
  85. package/docs/components/molecules/ModalHeader.md +756 -0
  86. package/docs/components/molecules/ModalProvider.md +205 -0
  87. package/docs/components/molecules/Nav.md +530 -0
  88. package/docs/components/molecules/NavItem.md +572 -0
  89. package/docs/components/molecules/NavLink.md +499 -0
  90. package/docs/components/molecules/Option.md +521 -0
  91. package/docs/components/molecules/Pagination.md +592 -0
  92. package/docs/components/molecules/PaginationNumberField.md +722 -0
  93. package/docs/components/molecules/Popover.md +516 -0
  94. package/docs/components/molecules/ProgressBar.md +624 -0
  95. package/docs/components/molecules/RadioGroup.md +831 -0
  96. package/docs/components/molecules/RepeaterList.md +185 -0
  97. package/docs/components/molecules/Select.md +402 -0
  98. package/docs/components/molecules/SortableTrigger.md +82 -0
  99. package/docs/components/molecules/useModal.md +379 -0
  100. package/docs/components/organisms/Dropzone.md +346 -0
  101. package/docs/components/organisms/DropzoneClear.md +135 -0
  102. package/docs/components/organisms/DropzoneContent.md +216 -0
  103. package/docs/components/organisms/DropzoneFilename.md +191 -0
  104. package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
  105. package/docs/components/organisms/DropzoneTrigger.md +209 -0
  106. package/docs/components/organisms/Form.md +533 -0
  107. package/docs/components/organisms/SlideOutPanel.md +662 -0
  108. package/docs/components/organisms/TabContent.md +902 -0
  109. package/docs/components/organisms/TabItem.md +1091 -0
  110. package/docs/components/organisms/Table.md +611 -0
  111. package/docs/components/organisms/TableBody.md +679 -0
  112. package/docs/components/organisms/TableCell.md +482 -0
  113. package/docs/components/organisms/TableHeader.md +513 -0
  114. package/docs/components/organisms/TableHeaderCell.md +661 -0
  115. package/docs/components/organisms/TableRow.md +715 -0
  116. package/docs/components/organisms/Tabs.md +1330 -0
  117. package/docs/components/utils/ConditionalView.md +568 -0
  118. package/docs/components/utils/RenderStateView.md +726 -0
  119. package/docs/components/utils/WrapTextNodes.md +614 -0
  120. package/package.json +3 -2
@@ -0,0 +1,726 @@
1
+ # RenderStateView
2
+
3
+ ## Description
4
+
5
+ A utility component that manages different rendering states for data-driven components. RenderStateView provides a clean way to handle loading, empty, and filled states with customizable components for each state, making it perfect for data fetching scenarios where you need to display different content based on the presence and loading state of data.
6
+
7
+ ## Aliases
8
+
9
+ - RenderStateView
10
+ - State Renderer
11
+ - Data State Manager
12
+ - Conditional Renderer
13
+
14
+ ## Props Breakdown
15
+
16
+ **Extends:** Standalone interface (no HTML element inheritance)
17
+
18
+ | Prop | Type | Default | Required | Description |
19
+ |------|------|---------|----------|-------------|
20
+ | `className` | `string` | - | No | Additional CSS class names |
21
+ | `data` | `T \| null` | - | No | The data to render or check for presence |
22
+ | `isLoading` | `boolean` | - | No | Whether data is currently loading |
23
+ | `filled` | `React.ComponentType<{ data: T } & P>` | - | No | Component to render when data is present |
24
+ | `empty` | `React.ComponentType<P>` | - | No | Component to render when no data |
25
+ | `loading` | `React.ComponentType<P>` | - | No | Component to render during loading state |
26
+
27
+ This component does not add standard HTML attributes as it renders different components based on state.
28
+
29
+ ## Examples
30
+
31
+ ### Basic Data Loading States
32
+
33
+ ```tsx
34
+ import { RenderStateView, Spinner, Text, Button } from '@delightui/components';
35
+
36
+ function BasicRenderStateExample() {
37
+ const [users, setUsers] = useState<any[]>([]);
38
+ const [isLoading, setIsLoading] = useState(false);
39
+
40
+ const fetchUsers = async () => {
41
+ setIsLoading(true);
42
+ try {
43
+ // Simulate API call
44
+ await new Promise(resolve => setTimeout(resolve, 2000));
45
+ setUsers([
46
+ { id: 1, name: 'John Doe', email: 'john@example.com' },
47
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
48
+ ]);
49
+ } catch (error) {
50
+ setUsers([]);
51
+ } finally {
52
+ setIsLoading(false);
53
+ }
54
+ };
55
+
56
+ const LoadingComponent = () => (
57
+ <div style={{ textAlign: 'center', padding: '40px' }}>
58
+ <Spinner />
59
+ <Text>Loading users...</Text>
60
+ </div>
61
+ );
62
+
63
+ const EmptyComponent = () => (
64
+ <div style={{ textAlign: 'center', padding: '40px' }}>
65
+ <Text>No users found</Text>
66
+ <Button onClick={fetchUsers} style={{ marginTop: '16px' }}>
67
+ Load Users
68
+ </Button>
69
+ </div>
70
+ );
71
+
72
+ const FilledComponent = ({ data }: { data: any[] }) => (
73
+ <div>
74
+ <Text weight="Bold">Users ({data.length})</Text>
75
+ {data.map(user => (
76
+ <div key={user.id} style={{ padding: '8px', border: '1px solid #ccc', margin: '8px 0' }}>
77
+ <Text weight="Bold">{user.name}</Text>
78
+ <Text size="Small">{user.email}</Text>
79
+ </div>
80
+ ))}
81
+ </div>
82
+ );
83
+
84
+ return (
85
+ <div style={{ padding: '20px' }}>
86
+ <Button onClick={fetchUsers} disabled={isLoading}>
87
+ Fetch Users
88
+ </Button>
89
+
90
+ <RenderStateView
91
+ data={users.length > 0 ? users : null}
92
+ isLoading={isLoading}
93
+ loading={LoadingComponent}
94
+ empty={EmptyComponent}
95
+ filled={FilledComponent}
96
+ />
97
+ </div>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ### Product Catalog with Search
103
+
104
+ ```tsx
105
+ import { RenderStateView, Input, Text, Card, Button, Image } from '@delightui/components';
106
+
107
+ function ProductCatalogExample() {
108
+ const [products, setProducts] = useState<any[]>([]);
109
+ const [isLoading, setIsLoading] = useState(false);
110
+ const [searchTerm, setSearchTerm] = useState('');
111
+
112
+ const searchProducts = async (term: string) => {
113
+ setIsLoading(true);
114
+ try {
115
+ await new Promise(resolve => setTimeout(resolve, 1000));
116
+
117
+ const allProducts = [
118
+ { id: 1, name: 'Wireless Headphones', price: 199.99, image: '/images/headphones.jpg' },
119
+ { id: 2, name: 'Smart Watch', price: 299.99, image: '/images/watch.jpg' },
120
+ { id: 3, name: 'Bluetooth Speaker', price: 89.99, image: '/images/speaker.jpg' }
121
+ ];
122
+
123
+ const filtered = term
124
+ ? allProducts.filter(p => p.name.toLowerCase().includes(term.toLowerCase()))
125
+ : [];
126
+
127
+ setProducts(filtered);
128
+ } finally {
129
+ setIsLoading(false);
130
+ }
131
+ };
132
+
133
+ const LoadingSpinner = () => (
134
+ <div style={{ textAlign: 'center', padding: '60px' }}>
135
+ <Text>🔍 Searching products...</Text>
136
+ </div>
137
+ );
138
+
139
+ const EmptyState = () => (
140
+ <div style={{ textAlign: 'center', padding: '60px' }}>
141
+ <Text size="large">No products found</Text>
142
+ <Text>Try searching for "headphones", "watch", or "speaker"</Text>
143
+ </div>
144
+ );
145
+
146
+ const ProductGrid = ({ data }: { data: any[] }) => (
147
+ <div style={{
148
+ display: 'grid',
149
+ gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
150
+ gap: '20px',
151
+ marginTop: '20px'
152
+ }}>
153
+ {data.map(product => (
154
+ <Card key={product.id}>
155
+ <Image
156
+ src={product.image}
157
+ alt={product.name}
158
+ width="100%"
159
+ height={200}
160
+ fit="Cover"
161
+ />
162
+ <div style={{ padding: '16px' }}>
163
+ <Text weight="Bold">{product.name}</Text>
164
+ <Text size="large" weight="Bold" style={{ color: '#2e7d32' }}>
165
+ ${product.price}
166
+ </Text>
167
+ <Button style={{ marginTop: '8px', width: '100%' }}>
168
+ Add to Cart
169
+ </Button>
170
+ </div>
171
+ </Card>
172
+ ))}
173
+ </div>
174
+ );
175
+
176
+ return (
177
+ <div style={{ padding: '20px' }}>
178
+ <Input
179
+ value={searchTerm}
180
+ onValueChange={setSearchTerm}
181
+ placeholder="Search products..."
182
+ trailingIcon={
183
+ <Button
184
+ size="Small"
185
+ onClick={() => searchProducts(searchTerm)}
186
+ disabled={isLoading}
187
+ >
188
+ Search
189
+ </Button>
190
+ }
191
+ />
192
+
193
+ <RenderStateView
194
+ data={products.length > 0 ? products : null}
195
+ isLoading={isLoading}
196
+ loading={LoadingSpinner}
197
+ empty={EmptyState}
198
+ filled={ProductGrid}
199
+ />
200
+ </div>
201
+ );
202
+ }
203
+ ```
204
+
205
+ ### Dashboard Analytics
206
+
207
+ ```tsx
208
+ import { RenderStateView, Text, Card, ProgressBar, Button } from '@delightui/components';
209
+
210
+ function DashboardAnalyticsExample() {
211
+ const [analytics, setAnalytics] = useState<any>(null);
212
+ const [isLoading, setIsLoading] = useState(false);
213
+
214
+ const loadAnalytics = async () => {
215
+ setIsLoading(true);
216
+ try {
217
+ await new Promise(resolve => setTimeout(resolve, 1500));
218
+ setAnalytics({
219
+ pageViews: 125840,
220
+ uniqueVisitors: 45230,
221
+ bounceRate: 32.5,
222
+ conversionRate: 4.2,
223
+ revenueGrowth: 12.8,
224
+ topPages: [
225
+ { page: '/home', views: 25000 },
226
+ { page: '/products', views: 18500 },
227
+ { page: '/about', views: 12300 }
228
+ ]
229
+ });
230
+ } finally {
231
+ setIsLoading(false);
232
+ }
233
+ };
234
+
235
+ const LoadingDashboard = () => (
236
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '20px' }}>
237
+ {[1, 2, 3, 4].map(i => (
238
+ <Card key={i} style={{ padding: '20px', textAlign: 'center' }}>
239
+ <div style={{ width: '60px', height: '60px', backgroundColor: '#f0f0f0', borderRadius: '50%', margin: '0 auto 16px' }} />
240
+ <div style={{ width: '100px', height: '20px', backgroundColor: '#f0f0f0', margin: '0 auto 8px' }} />
241
+ <div style={{ width: '80px', height: '16px', backgroundColor: '#f0f0f0', margin: '0 auto' }} />
242
+ </Card>
243
+ ))}
244
+ </div>
245
+ );
246
+
247
+ const EmptyDashboard = () => (
248
+ <Card style={{ textAlign: 'center', padding: '60px' }}>
249
+ <Text size="large">📊 No Analytics Data</Text>
250
+ <Text>Analytics data is not available at the moment.</Text>
251
+ <Button onClick={loadAnalytics} style={{ marginTop: '16px' }}>
252
+ Reload Analytics
253
+ </Button>
254
+ </Card>
255
+ );
256
+
257
+ const AnalyticsDashboard = ({ data }: { data: any }) => (
258
+ <div>
259
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '20px', marginBottom: '30px' }}>
260
+ <Card style={{ padding: '20px', textAlign: 'center' }}>
261
+ <Text size="small" color="secondary">Page Views</Text>
262
+ <Text size="xl" weight="Bold">{data.pageViews.toLocaleString()}</Text>
263
+ </Card>
264
+
265
+ <Card style={{ padding: '20px', textAlign: 'center' }}>
266
+ <Text size="small" color="secondary">Unique Visitors</Text>
267
+ <Text size="xl" weight="Bold">{data.uniqueVisitors.toLocaleString()}</Text>
268
+ </Card>
269
+
270
+ <Card style={{ padding: '20px', textAlign: 'center' }}>
271
+ <Text size="small" color="secondary">Bounce Rate</Text>
272
+ <Text size="xl" weight="Bold">{data.bounceRate}%</Text>
273
+ </Card>
274
+
275
+ <Card style={{ padding: '20px', textAlign: 'center' }}>
276
+ <Text size="small" color="secondary">Conversion Rate</Text>
277
+ <Text size="xl" weight="Bold">{data.conversionRate}%</Text>
278
+ </Card>
279
+ </div>
280
+
281
+ <Card style={{ padding: '20px' }}>
282
+ <Text weight="Bold" style={{ marginBottom: '16px' }}>Top Pages</Text>
283
+ {data.topPages.map((page: any, index: number) => (
284
+ <div key={index} style={{ marginBottom: '12px' }}>
285
+ <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '4px' }}>
286
+ <Text>{page.page}</Text>
287
+ <Text weight="Bold">{page.views.toLocaleString()}</Text>
288
+ </div>
289
+ <ProgressBar
290
+ value={(page.views / data.topPages[0].views) * 100}
291
+ max={100}
292
+ />
293
+ </div>
294
+ ))}
295
+ </Card>
296
+ </div>
297
+ );
298
+
299
+ return (
300
+ <div style={{ padding: '20px' }}>
301
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
302
+ <Text size="xl" weight="Bold">Analytics Dashboard</Text>
303
+ <Button onClick={loadAnalytics} disabled={isLoading}>
304
+ Refresh Data
305
+ </Button>
306
+ </div>
307
+
308
+ <RenderStateView
309
+ data={analytics}
310
+ isLoading={isLoading}
311
+ loading={LoadingDashboard}
312
+ empty={EmptyDashboard}
313
+ filled={AnalyticsDashboard}
314
+ />
315
+ </div>
316
+ );
317
+ }
318
+ ```
319
+
320
+ ### User Profile Management
321
+
322
+ ```tsx
323
+ import { RenderStateView, Text, Card, Button, Image, Form, FormField, Input } from '@delightui/components';
324
+
325
+ function UserProfileExample() {
326
+ const [profile, setProfile] = useState<any>(null);
327
+ const [isLoading, setIsLoading] = useState(false);
328
+ const [isEditing, setIsEditing] = useState(false);
329
+
330
+ const loadProfile = async () => {
331
+ setIsLoading(true);
332
+ try {
333
+ await new Promise(resolve => setTimeout(resolve, 1000));
334
+ setProfile({
335
+ name: 'John Doe',
336
+ email: 'john.doe@example.com',
337
+ avatar: '/images/avatar.jpg',
338
+ role: 'Senior Developer',
339
+ department: 'Engineering',
340
+ joinDate: '2022-03-15',
341
+ projects: 24
342
+ });
343
+ } finally {
344
+ setIsLoading(false);
345
+ }
346
+ };
347
+
348
+ const ProfileSkeleton = () => (
349
+ <Card style={{ padding: '30px' }}>
350
+ <div style={{ display: 'flex', alignItems: 'center', gap: '20px', marginBottom: '20px' }}>
351
+ <div style={{ width: '80px', height: '80px', backgroundColor: '#f0f0f0', borderRadius: '50%' }} />
352
+ <div>
353
+ <div style={{ width: '150px', height: '24px', backgroundColor: '#f0f0f0', marginBottom: '8px' }} />
354
+ <div style={{ width: '200px', height: '16px', backgroundColor: '#f0f0f0' }} />
355
+ </div>
356
+ </div>
357
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '16px' }}>
358
+ {[1, 2, 3, 4].map(i => (
359
+ <div key={i}>
360
+ <div style={{ width: '80px', height: '16px', backgroundColor: '#f0f0f0', marginBottom: '4px' }} />
361
+ <div style={{ width: '120px', height: '20px', backgroundColor: '#f0f0f0' }} />
362
+ </div>
363
+ ))}
364
+ </div>
365
+ </Card>
366
+ );
367
+
368
+ const EmptyProfile = () => (
369
+ <Card style={{ textAlign: 'center', padding: '60px' }}>
370
+ <Text size="large">👤 No Profile Found</Text>
371
+ <Text>Unable to load profile information.</Text>
372
+ <Button onClick={loadProfile} style={{ marginTop: '16px' }}>
373
+ Retry Loading
374
+ </Button>
375
+ </Card>
376
+ );
377
+
378
+ const ProfileDisplay = ({ data }: { data: any }) => (
379
+ <Card style={{ padding: '30px' }}>
380
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '20px' }}>
381
+ <div style={{ display: 'flex', alignItems: 'center', gap: '20px' }}>
382
+ <Image
383
+ src={data.avatar}
384
+ alt={data.name}
385
+ width={80}
386
+ height={80}
387
+ fit="Cover"
388
+ style={{ borderRadius: '50%' }}
389
+ />
390
+ <div>
391
+ <Text size="xl" weight="Bold">{data.name}</Text>
392
+ <Text color="secondary">{data.email}</Text>
393
+ <Text>{data.role} • {data.department}</Text>
394
+ </div>
395
+ </div>
396
+ <Button onClick={() => setIsEditing(true)}>
397
+ Edit Profile
398
+ </Button>
399
+ </div>
400
+
401
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '20px' }}>
402
+ <div>
403
+ <Text size="small" color="secondary">Join Date</Text>
404
+ <Text weight="Bold">{data.joinDate}</Text>
405
+ </div>
406
+ <div>
407
+ <Text size="small" color="secondary">Projects</Text>
408
+ <Text weight="Bold">{data.projects}</Text>
409
+ </div>
410
+ <div>
411
+ <Text size="small" color="secondary">Department</Text>
412
+ <Text weight="Bold">{data.department}</Text>
413
+ </div>
414
+ <div>
415
+ <Text size="small" color="secondary">Role</Text>
416
+ <Text weight="Bold">{data.role}</Text>
417
+ </div>
418
+ </div>
419
+ </Card>
420
+ );
421
+
422
+ return (
423
+ <div style={{ padding: '20px' }}>
424
+ <Text size="xl" weight="Bold" style={{ marginBottom: '20px' }}>
425
+ User Profile
426
+ </Text>
427
+
428
+ <RenderStateView
429
+ data={profile}
430
+ isLoading={isLoading}
431
+ loading={ProfileSkeleton}
432
+ empty={EmptyProfile}
433
+ filled={ProfileDisplay}
434
+ />
435
+
436
+ {!profile && !isLoading && (
437
+ <Button onClick={loadProfile} style={{ marginTop: '20px' }}>
438
+ Load Profile
439
+ </Button>
440
+ )}
441
+ </div>
442
+ );
443
+ }
444
+ ```
445
+
446
+ ### Shopping Cart States
447
+
448
+ ```tsx
449
+ import { RenderStateView, Text, Button, Card, Image } from '@delightui/components';
450
+
451
+ function ShoppingCartExample() {
452
+ const [cartItems, setCartItems] = useState<any[]>([]);
453
+ const [isLoading, setIsLoading] = useState(false);
454
+
455
+ const loadCart = async () => {
456
+ setIsLoading(true);
457
+ try {
458
+ await new Promise(resolve => setTimeout(resolve, 800));
459
+ setCartItems([
460
+ { id: 1, name: 'Wireless Mouse', price: 29.99, quantity: 2, image: '/images/mouse.jpg' },
461
+ { id: 2, name: 'USB Cable', price: 12.99, quantity: 1, image: '/images/cable.jpg' }
462
+ ]);
463
+ } finally {
464
+ setIsLoading(false);
465
+ }
466
+ };
467
+
468
+ const clearCart = () => {
469
+ setCartItems([]);
470
+ };
471
+
472
+ const CartLoading = () => (
473
+ <Card style={{ padding: '30px', textAlign: 'center' }}>
474
+ <Text>🛒 Loading your cart...</Text>
475
+ </Card>
476
+ );
477
+
478
+ const EmptyCart = () => (
479
+ <Card style={{ padding: '60px', textAlign: 'center' }}>
480
+ <Text size="xl">🛒</Text>
481
+ <Text size="large" weight="Bold">Your cart is empty</Text>
482
+ <Text>Add some items to get started!</Text>
483
+ <Button onClick={loadCart} style={{ marginTop: '20px' }}>
484
+ Load Sample Items
485
+ </Button>
486
+ </Card>
487
+ );
488
+
489
+ const CartWithItems = ({ data }: { data: any[] }) => {
490
+ const total = data.reduce((sum, item) => sum + (item.price * item.quantity), 0);
491
+
492
+ return (
493
+ <div>
494
+ <Card style={{ padding: '20px', marginBottom: '20px' }}>
495
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
496
+ <Text size="large" weight="Bold">Shopping Cart ({data.length} items)</Text>
497
+ <Button type="Outlined" onClick={clearCart}>
498
+ Clear Cart
499
+ </Button>
500
+ </div>
501
+
502
+ {data.map(item => (
503
+ <div key={item.id} style={{
504
+ display: 'flex',
505
+ alignItems: 'center',
506
+ gap: '16px',
507
+ padding: '16px 0',
508
+ borderBottom: '1px solid #eee'
509
+ }}>
510
+ <Image
511
+ src={item.image}
512
+ alt={item.name}
513
+ width={60}
514
+ height={60}
515
+ fit="Cover"
516
+ style={{ borderRadius: '8px' }}
517
+ />
518
+ <div style={{ flex: 1 }}>
519
+ <Text weight="Bold">{item.name}</Text>
520
+ <Text size="small">Quantity: {item.quantity}</Text>
521
+ </div>
522
+ <Text weight="Bold">${(item.price * item.quantity).toFixed(2)}</Text>
523
+ </div>
524
+ ))}
525
+ </Card>
526
+
527
+ <Card style={{ padding: '20px' }}>
528
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
529
+ <Text size="large" weight="Bold">Total: ${total.toFixed(2)}</Text>
530
+ </div>
531
+ <Button style={{ width: '100%' }}>
532
+ Proceed to Checkout
533
+ </Button>
534
+ </Card>
535
+ </div>
536
+ );
537
+ };
538
+
539
+ return (
540
+ <div style={{ padding: '20px', maxWidth: '600px' }}>
541
+ <RenderStateView
542
+ data={cartItems.length > 0 ? cartItems : null}
543
+ isLoading={isLoading}
544
+ loading={CartLoading}
545
+ empty={EmptyCart}
546
+ filled={CartWithItems}
547
+ />
548
+ </div>
549
+ );
550
+ }
551
+ ```
552
+
553
+ ### File Upload Manager
554
+
555
+ ```tsx
556
+ import { RenderStateView, Text, Button, Card, ProgressBar } from '@delightui/components';
557
+
558
+ function FileUploadManagerExample() {
559
+ const [files, setFiles] = useState<any[]>([]);
560
+ const [isLoading, setIsLoading] = useState(false);
561
+
562
+ const uploadFiles = async () => {
563
+ setIsLoading(true);
564
+ try {
565
+ await new Promise(resolve => setTimeout(resolve, 2000));
566
+ setFiles([
567
+ { id: 1, name: 'document.pdf', size: '2.4 MB', status: 'completed', uploadDate: '2024-01-15' },
568
+ { id: 2, name: 'image.jpg', size: '1.8 MB', status: 'completed', uploadDate: '2024-01-15' }
569
+ ]);
570
+ } finally {
571
+ setIsLoading(false);
572
+ }
573
+ };
574
+
575
+ const UploadingState = () => (
576
+ <Card style={{ padding: '40px', textAlign: 'center' }}>
577
+ <Text>📤 Uploading files...</Text>
578
+ <ProgressBar value={65} max={100} style={{ marginTop: '16px' }} />
579
+ <Text size="small" style={{ marginTop: '8px' }}>65% complete</Text>
580
+ </Card>
581
+ );
582
+
583
+ const NoFilesState = () => (
584
+ <Card style={{ padding: '60px', textAlign: 'center', border: '2px dashed #ccc' }}>
585
+ <Text size="xl">📁</Text>
586
+ <Text size="large" weight="Bold">No files uploaded</Text>
587
+ <Text>Drag and drop files here or click to upload</Text>
588
+ <Button onClick={uploadFiles} style={{ marginTop: '20px' }}>
589
+ Upload Sample Files
590
+ </Button>
591
+ </Card>
592
+ );
593
+
594
+ const FilesList = ({ data }: { data: any[] }) => (
595
+ <div>
596
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
597
+ <Text size="large" weight="Bold">Uploaded Files ({data.length})</Text>
598
+ <Button onClick={uploadFiles}>
599
+ Upload More
600
+ </Button>
601
+ </div>
602
+
603
+ {data.map(file => (
604
+ <Card key={file.id} style={{ padding: '16px', marginBottom: '12px' }}>
605
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
606
+ <div>
607
+ <Text weight="Bold">{file.name}</Text>
608
+ <Text size="small" color="secondary">
609
+ {file.size} • Uploaded {file.uploadDate}
610
+ </Text>
611
+ </div>
612
+ <div style={{ display: 'flex', gap: '8px' }}>
613
+ <Button size="Small" type="Outlined">Download</Button>
614
+ <Button size="Small" style="Destructive">Delete</Button>
615
+ </div>
616
+ </div>
617
+ </Card>
618
+ ))}
619
+ </div>
620
+ );
621
+
622
+ return (
623
+ <div style={{ padding: '20px', maxWidth: '600px' }}>
624
+ <Text size="xl" weight="Bold" style={{ marginBottom: '20px' }}>
625
+ File Manager
626
+ </Text>
627
+
628
+ <RenderStateView
629
+ data={files.length > 0 ? files : null}
630
+ isLoading={isLoading}
631
+ loading={UploadingState}
632
+ empty={NoFilesState}
633
+ filled={FilesList}
634
+ />
635
+ </div>
636
+ );
637
+ }
638
+ ```
639
+
640
+ ### Custom Error States
641
+
642
+ ```tsx
643
+ import { RenderStateView, Text, Button, Card } from '@delightui/components';
644
+
645
+ function CustomErrorStatesExample() {
646
+ const [data, setData] = useState<any>(null);
647
+ const [isLoading, setIsLoading] = useState(false);
648
+ const [error, setError] = useState<string>('');
649
+
650
+ const fetchData = async (shouldFail = false) => {
651
+ setIsLoading(true);
652
+ setError('');
653
+ try {
654
+ await new Promise(resolve => setTimeout(resolve, 1000));
655
+ if (shouldFail) {
656
+ throw new Error('Network error occurred');
657
+ }
658
+ setData({ message: 'Data loaded successfully!' });
659
+ } catch (err) {
660
+ setError(err instanceof Error ? err.message : 'Unknown error');
661
+ setData(null);
662
+ } finally {
663
+ setIsLoading(false);
664
+ }
665
+ };
666
+
667
+ const LoadingComponent = () => (
668
+ <Card style={{ padding: '40px', textAlign: 'center' }}>
669
+ <Text>⏳ Loading data...</Text>
670
+ </Card>
671
+ );
672
+
673
+ const ErrorComponent = () => (
674
+ <Card style={{ padding: '40px', textAlign: 'center', backgroundColor: '#ffebee' }}>
675
+ <Text size="large">❌ Error Occurred</Text>
676
+ <Text>{error}</Text>
677
+ <div style={{ marginTop: '20px', display: 'flex', gap: '12px', justifyContent: 'center' }}>
678
+ <Button onClick={() => fetchData(false)}>Retry</Button>
679
+ <Button type="Outlined" onClick={() => setError('')}>Dismiss</Button>
680
+ </div>
681
+ </Card>
682
+ );
683
+
684
+ const SuccessComponent = ({ data }: { data: any }) => (
685
+ <Card style={{ padding: '40px', textAlign: 'center', backgroundColor: '#e8f5e8' }}>
686
+ <Text size="large">✅ Success!</Text>
687
+ <Text>{data.message}</Text>
688
+ </Card>
689
+ );
690
+
691
+ // Use error state to determine what to show
692
+ const currentData = error ? null : data;
693
+
694
+ return (
695
+ <div style={{ padding: '20px', maxWidth: '400px' }}>
696
+ <Text size="xl" weight="Bold" style={{ marginBottom: '20px' }}>
697
+ Error Handling Demo
698
+ </Text>
699
+
700
+ <div style={{ marginBottom: '20px', display: 'flex', gap: '12px' }}>
701
+ <Button onClick={() => fetchData(false)}>Load Success</Button>
702
+ <Button onClick={() => fetchData(true)}>Trigger Error</Button>
703
+ </div>
704
+
705
+ {error ? (
706
+ <ErrorComponent />
707
+ ) : (
708
+ <RenderStateView
709
+ data={currentData}
710
+ isLoading={isLoading}
711
+ loading={LoadingComponent}
712
+ empty={() => (
713
+ <Card style={{ padding: '40px', textAlign: 'center' }}>
714
+ <Text>📭 No data available</Text>
715
+ <Button onClick={() => fetchData(false)} style={{ marginTop: '16px' }}>
716
+ Load Data
717
+ </Button>
718
+ </Card>
719
+ )}
720
+ filled={SuccessComponent}
721
+ />
722
+ )}
723
+ </div>
724
+ );
725
+ }
726
+ ```