@delightui/components 0.1.105 → 0.1.107

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 (102) 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/index.d.ts +2 -0
  9. package/dist/cjs/library.css +19 -6
  10. package/dist/cjs/library.js +3 -3
  11. package/dist/cjs/library.js.map +1 -1
  12. package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
  13. package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
  14. package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
  15. package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
  16. package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
  17. package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
  18. package/dist/esm/components/molecules/index.d.ts +2 -0
  19. package/dist/esm/library.css +19 -6
  20. package/dist/esm/library.js +3 -3
  21. package/dist/esm/library.js.map +1 -1
  22. package/dist/index.d.ts +108 -2
  23. package/docs/README.md +264 -0
  24. package/docs/components/atoms/ActionImage.md +119 -0
  25. package/docs/components/atoms/Button.md +197 -0
  26. package/docs/components/atoms/Checkbox.md +299 -0
  27. package/docs/components/atoms/CheckboxItem.md +314 -0
  28. package/docs/components/atoms/Chip.md +380 -0
  29. package/docs/components/atoms/CustomToggle.md +270 -0
  30. package/docs/components/atoms/Icon.md +365 -0
  31. package/docs/components/atoms/IconButton.md +407 -0
  32. package/docs/components/atoms/Image.md +448 -0
  33. package/docs/components/atoms/Input.md +430 -0
  34. package/docs/components/atoms/ListItem.md +502 -0
  35. package/docs/components/atoms/Password.md +472 -0
  36. package/docs/components/atoms/RadioButton.md +614 -0
  37. package/docs/components/atoms/RadioButtonItem.md +588 -0
  38. package/docs/components/atoms/ResponsiveComponent.md +612 -0
  39. package/docs/components/atoms/SelectListItem.md +609 -0
  40. package/docs/components/atoms/Slider.md +605 -0
  41. package/docs/components/atoms/Spinner.md +605 -0
  42. package/docs/components/atoms/Text.md +463 -0
  43. package/docs/components/atoms/TextArea.md +670 -0
  44. package/docs/components/atoms/ToastNotification.md +668 -0
  45. package/docs/components/atoms/Toggle.md +737 -0
  46. package/docs/components/atoms/ToggleButton.md +751 -0
  47. package/docs/components/atoms/Tooltip.md +391 -0
  48. package/docs/components/molecules/Accordion.md +440 -0
  49. package/docs/components/molecules/AccordionGroup.md +547 -0
  50. package/docs/components/molecules/ActionCard.md +546 -0
  51. package/docs/components/molecules/Breadcrumb.md +403 -0
  52. package/docs/components/molecules/Breadcrumbs.md +485 -0
  53. package/docs/components/molecules/ButtonGroup.md +383 -0
  54. package/docs/components/molecules/Card.md +298 -0
  55. package/docs/components/molecules/ChipInput.md +646 -0
  56. package/docs/components/molecules/ContextMenu.md +768 -0
  57. package/docs/components/molecules/CustomTimeSelector.md +116 -0
  58. package/docs/components/molecules/DatePicker.md +516 -0
  59. package/docs/components/molecules/DateTimeSelector.md +166 -0
  60. package/docs/components/molecules/FormField.md +312 -0
  61. package/docs/components/molecules/Grid.md +577 -0
  62. package/docs/components/molecules/GridItem.md +834 -0
  63. package/docs/components/molecules/GridList.md +244 -0
  64. package/docs/components/molecules/List.md +485 -0
  65. package/docs/components/molecules/Modal.md +470 -0
  66. package/docs/components/molecules/ModalFooter.md +702 -0
  67. package/docs/components/molecules/ModalHeader.md +756 -0
  68. package/docs/components/molecules/ModalProvider.md +205 -0
  69. package/docs/components/molecules/Nav.md +530 -0
  70. package/docs/components/molecules/NavItem.md +572 -0
  71. package/docs/components/molecules/NavLink.md +499 -0
  72. package/docs/components/molecules/Option.md +521 -0
  73. package/docs/components/molecules/Pagination.md +592 -0
  74. package/docs/components/molecules/PaginationNumberField.md +722 -0
  75. package/docs/components/molecules/Popover.md +516 -0
  76. package/docs/components/molecules/ProgressBar.md +624 -0
  77. package/docs/components/molecules/RadioGroup.md +831 -0
  78. package/docs/components/molecules/RepeaterList.md +185 -0
  79. package/docs/components/molecules/Select.md +402 -0
  80. package/docs/components/molecules/SortableTrigger.md +82 -0
  81. package/docs/components/molecules/useModal.md +379 -0
  82. package/docs/components/organisms/Dropzone.md +346 -0
  83. package/docs/components/organisms/DropzoneClear.md +135 -0
  84. package/docs/components/organisms/DropzoneContent.md +216 -0
  85. package/docs/components/organisms/DropzoneFilename.md +191 -0
  86. package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
  87. package/docs/components/organisms/DropzoneTrigger.md +209 -0
  88. package/docs/components/organisms/Form.md +533 -0
  89. package/docs/components/organisms/SlideOutPanel.md +662 -0
  90. package/docs/components/organisms/TabContent.md +902 -0
  91. package/docs/components/organisms/TabItem.md +1091 -0
  92. package/docs/components/organisms/Table.md +611 -0
  93. package/docs/components/organisms/TableBody.md +679 -0
  94. package/docs/components/organisms/TableCell.md +482 -0
  95. package/docs/components/organisms/TableHeader.md +513 -0
  96. package/docs/components/organisms/TableHeaderCell.md +661 -0
  97. package/docs/components/organisms/TableRow.md +715 -0
  98. package/docs/components/organisms/Tabs.md +1330 -0
  99. package/docs/components/utils/ConditionalView.md +568 -0
  100. package/docs/components/utils/RenderStateView.md +726 -0
  101. package/docs/components/utils/WrapTextNodes.md +614 -0
  102. package/package.json +3 -2
@@ -0,0 +1,605 @@
1
+ # Spinner
2
+
3
+ A loading indicator component that displays an animated spinner to indicate processing, loading, or waiting states. This component provides visual feedback to users during asynchronous operations and helps maintain engagement during loading periods.
4
+
5
+ ## Aliases
6
+
7
+ - Spinner
8
+ - LoadingSpinner
9
+ - Loader
10
+
11
+ ## Props Breakdown
12
+
13
+ **Extends:** Standalone interface (no HTML element inheritance)
14
+
15
+ | Prop | Type | Default | Required | Description |
16
+ |------|------|---------|----------|-------------|
17
+ | `className` | `string` | `undefined` | No | Additional class for styling |
18
+
19
+ *Note: This component has a standalone interface and does not inherit from any HTML element attributes. It only accepts the props explicitly defined above.*
20
+
21
+ ## Examples
22
+
23
+ ### Basic Spinner
24
+
25
+ ```tsx
26
+ import { Spinner } from '@delightui/components';
27
+
28
+ function BasicSpinnerExample() {
29
+ return (
30
+ <div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}>
31
+ <Spinner />
32
+ </div>
33
+ );
34
+ }
35
+ ```
36
+
37
+ ### Loading State in Button
38
+
39
+ ```tsx
40
+ import { Button, Spinner } from '@delightui/components';
41
+
42
+ function LoadingButtonExample() {
43
+ const [isLoading, setIsLoading] = useState(false);
44
+
45
+ const handleClick = async () => {
46
+ setIsLoading(true);
47
+ // Simulate API call
48
+ await new Promise(resolve => setTimeout(resolve, 2000));
49
+ setIsLoading(false);
50
+ };
51
+
52
+ return (
53
+ <Button
54
+ onClick={handleClick}
55
+ disabled={isLoading}
56
+ leadingIcon={isLoading ? <Spinner /> : undefined}
57
+ >
58
+ {isLoading ? 'Loading...' : 'Submit'}
59
+ </Button>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ### Form Loading State
65
+
66
+ ```tsx
67
+ import { Form, FormField, Input, Button, Spinner, Text } from '@delightui/components';
68
+
69
+ function FormLoadingExample() {
70
+ const [isSubmitting, setIsSubmitting] = useState(false);
71
+
72
+ const handleSubmit = async (data: any) => {
73
+ setIsSubmitting(true);
74
+ try {
75
+ // Simulate form submission
76
+ await new Promise(resolve => setTimeout(resolve, 3000));
77
+ console.log('Form submitted:', data);
78
+ } finally {
79
+ setIsSubmitting(false);
80
+ }
81
+ };
82
+
83
+ return (
84
+ <Form onSubmit={handleSubmit}>
85
+ <FormField name="name" label="Name" required>
86
+ <Input placeholder="Enter your name" disabled={isSubmitting} />
87
+ </FormField>
88
+
89
+ <FormField name="email" label="Email" required>
90
+ <Input
91
+ inputType="Email"
92
+ placeholder="Enter your email"
93
+ disabled={isSubmitting}
94
+ />
95
+ </FormField>
96
+
97
+ {isSubmitting ? (
98
+ <div style={{
99
+ display: 'flex',
100
+ alignItems: 'center',
101
+ gap: '12px',
102
+ justifyContent: 'center',
103
+ padding: '20px'
104
+ }}>
105
+ <Spinner />
106
+ <Text>Submitting your information...</Text>
107
+ </div>
108
+ ) : (
109
+ <Button type="submit">
110
+ Submit Form
111
+ </Button>
112
+ )}
113
+ </Form>
114
+ );
115
+ }
116
+ ```
117
+
118
+ ### Data Loading State
119
+
120
+ ```tsx
121
+ import { Spinner, Text, Button } from '@delightui/components';
122
+
123
+ function DataLoadingExample() {
124
+ const [data, setData] = useState<string[] | null>(null);
125
+ const [loading, setLoading] = useState(false);
126
+ const [error, setError] = useState<string | null>(null);
127
+
128
+ const loadData = async () => {
129
+ setLoading(true);
130
+ setError(null);
131
+ try {
132
+ // Simulate data fetching
133
+ await new Promise(resolve => setTimeout(resolve, 2000));
134
+ setData(['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5']);
135
+ } catch (err) {
136
+ setError('Failed to load data');
137
+ } finally {
138
+ setLoading(false);
139
+ }
140
+ };
141
+
142
+ return (
143
+ <div style={{ padding: '20px', border: '1px solid #ccc', borderRadius: '8px' }}>
144
+ <div style={{ marginBottom: '16px' }}>
145
+ <Button onClick={loadData} disabled={loading}>
146
+ Load Data
147
+ </Button>
148
+ </div>
149
+
150
+ {loading && (
151
+ <div style={{
152
+ display: 'flex',
153
+ flexDirection: 'column',
154
+ alignItems: 'center',
155
+ gap: '12px',
156
+ padding: '40px'
157
+ }}>
158
+ <Spinner />
159
+ <Text color="secondary">Loading data...</Text>
160
+ </div>
161
+ )}
162
+
163
+ {error && (
164
+ <Text color="error">{error}</Text>
165
+ )}
166
+
167
+ {data && !loading && (
168
+ <div>
169
+ <Text weight="bold" style={{ marginBottom: '8px' }}>
170
+ Loaded Data:
171
+ </Text>
172
+ <ul>
173
+ {data.map((item, index) => (
174
+ <li key={index}>
175
+ <Text>{item}</Text>
176
+ </li>
177
+ ))}
178
+ </ul>
179
+ </div>
180
+ )}
181
+ </div>
182
+ );
183
+ }
184
+ ```
185
+
186
+ ### Page Loading Overlay
187
+
188
+ ```tsx
189
+ import { Spinner, Text } from '@delightui/components';
190
+
191
+ function PageLoadingOverlayExample() {
192
+ const [isPageLoading, setIsPageLoading] = useState(false);
193
+
194
+ const simulatePageLoad = () => {
195
+ setIsPageLoading(true);
196
+ setTimeout(() => setIsPageLoading(false), 3000);
197
+ };
198
+
199
+ return (
200
+ <div style={{ position: 'relative', minHeight: '300px' }}>
201
+ <div>
202
+ <Text weight="bold" style={{ marginBottom: '16px' }}>
203
+ Page Content
204
+ </Text>
205
+ <Text style={{ marginBottom: '16px' }}>
206
+ This is some page content that would be covered by the loading overlay.
207
+ </Text>
208
+ <Button onClick={simulatePageLoad}>
209
+ Simulate Page Loading
210
+ </Button>
211
+ </div>
212
+
213
+ {isPageLoading && (
214
+ <div style={{
215
+ position: 'absolute',
216
+ top: 0,
217
+ left: 0,
218
+ right: 0,
219
+ bottom: 0,
220
+ backgroundColor: 'rgba(255, 255, 255, 0.8)',
221
+ display: 'flex',
222
+ flexDirection: 'column',
223
+ alignItems: 'center',
224
+ justifyContent: 'center',
225
+ gap: '16px',
226
+ zIndex: 1000
227
+ }}>
228
+ <Spinner />
229
+ <Text weight="medium">Loading page...</Text>
230
+ </div>
231
+ )}
232
+ </div>
233
+ );
234
+ }
235
+ ```
236
+
237
+ ### Card Loading State
238
+
239
+ ```tsx
240
+ import { Spinner, Text, Button } from '@delightui/components';
241
+
242
+ function CardLoadingExample() {
243
+ const [cards, setCards] = useState([
244
+ { id: 1, loading: false, content: 'Card 1 content loaded' },
245
+ { id: 2, loading: false, content: 'Card 2 content loaded' },
246
+ { id: 3, loading: false, content: 'Card 3 content loaded' }
247
+ ]);
248
+
249
+ const loadCard = async (cardId: number) => {
250
+ setCards(prev => prev.map(card =>
251
+ card.id === cardId ? { ...card, loading: true } : card
252
+ ));
253
+
254
+ // Simulate loading
255
+ await new Promise(resolve => setTimeout(resolve, 2000));
256
+
257
+ setCards(prev => prev.map(card =>
258
+ card.id === cardId ? {
259
+ ...card,
260
+ loading: false,
261
+ content: `Updated content for Card ${cardId} - ${new Date().toLocaleTimeString()}`
262
+ } : card
263
+ ));
264
+ };
265
+
266
+ return (
267
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))', gap: '16px' }}>
268
+ {cards.map(card => (
269
+ <div
270
+ key={card.id}
271
+ style={{
272
+ border: '1px solid #ccc',
273
+ borderRadius: '8px',
274
+ padding: '16px',
275
+ minHeight: '150px',
276
+ display: 'flex',
277
+ flexDirection: 'column'
278
+ }}
279
+ >
280
+ <Text weight="bold" style={{ marginBottom: '12px' }}>
281
+ Card {card.id}
282
+ </Text>
283
+
284
+ {card.loading ? (
285
+ <div style={{
286
+ flex: 1,
287
+ display: 'flex',
288
+ flexDirection: 'column',
289
+ alignItems: 'center',
290
+ justifyContent: 'center',
291
+ gap: '8px'
292
+ }}>
293
+ <Spinner />
294
+ <Text size="small" color="secondary">Loading...</Text>
295
+ </div>
296
+ ) : (
297
+ <>
298
+ <Text style={{ flex: 1, marginBottom: '12px' }}>
299
+ {card.content}
300
+ </Text>
301
+ <Button
302
+ size="Small"
303
+ type="Outlined"
304
+ onClick={() => loadCard(card.id)}
305
+ >
306
+ Refresh
307
+ </Button>
308
+ </>
309
+ )}
310
+ </div>
311
+ ))}
312
+ </div>
313
+ );
314
+ }
315
+ ```
316
+
317
+ ### List Loading with Placeholder
318
+
319
+ ```tsx
320
+ import { Spinner, Text, Button } from '@delightui/components';
321
+
322
+ function ListLoadingExample() {
323
+ const [items, setItems] = useState<string[]>([]);
324
+ const [loading, setLoading] = useState(false);
325
+ const [hasMore, setHasMore] = useState(true);
326
+
327
+ const loadItems = async () => {
328
+ setLoading(true);
329
+ // Simulate loading more items
330
+ await new Promise(resolve => setTimeout(resolve, 1500));
331
+
332
+ const newItems = Array.from({ length: 5 }, (_, i) =>
333
+ `Item ${items.length + i + 1}`
334
+ );
335
+
336
+ setItems(prev => [...prev, ...newItems]);
337
+ setHasMore(items.length + newItems.length < 20);
338
+ setLoading(false);
339
+ };
340
+
341
+ return (
342
+ <div style={{
343
+ border: '1px solid #ccc',
344
+ borderRadius: '8px',
345
+ padding: '16px',
346
+ maxWidth: '300px'
347
+ }}>
348
+ <Text weight="bold" style={{ marginBottom: '16px' }}>
349
+ Item List
350
+ </Text>
351
+
352
+ <div style={{ marginBottom: '16px' }}>
353
+ {items.map((item, index) => (
354
+ <div
355
+ key={index}
356
+ style={{
357
+ padding: '8px 0',
358
+ borderBottom: index < items.length - 1 ? '1px solid #eee' : 'none'
359
+ }}
360
+ >
361
+ <Text>{item}</Text>
362
+ </div>
363
+ ))}
364
+ </div>
365
+
366
+ {loading && (
367
+ <div style={{
368
+ display: 'flex',
369
+ alignItems: 'center',
370
+ justifyContent: 'center',
371
+ gap: '8px',
372
+ padding: '16px'
373
+ }}>
374
+ <Spinner />
375
+ <Text size="small" color="secondary">Loading more items...</Text>
376
+ </div>
377
+ )}
378
+
379
+ {!loading && hasMore && (
380
+ <Button
381
+ onClick={loadItems}
382
+ size="Small"
383
+ style={{ width: '100%' }}
384
+ >
385
+ Load More
386
+ </Button>
387
+ )}
388
+
389
+ {!hasMore && items.length > 0 && (
390
+ <Text size="small" color="secondary" style={{ textAlign: 'center' }}>
391
+ All items loaded
392
+ </Text>
393
+ )}
394
+ </div>
395
+ );
396
+ }
397
+ ```
398
+
399
+ ### Search with Loading
400
+
401
+ ```tsx
402
+ import { Input, Spinner, Text } from '@delightui/components';
403
+
404
+ function SearchLoadingExample() {
405
+ const [searchTerm, setSearchTerm] = useState('');
406
+ const [loading, setLoading] = useState(false);
407
+ const [results, setResults] = useState<string[]>([]);
408
+
409
+ const mockData = [
410
+ 'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
411
+ 'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon'
412
+ ];
413
+
414
+ useEffect(() => {
415
+ if (searchTerm.trim() === '') {
416
+ setResults([]);
417
+ return;
418
+ }
419
+
420
+ setLoading(true);
421
+ const timeoutId = setTimeout(() => {
422
+ const filteredResults = mockData.filter(item =>
423
+ item.toLowerCase().includes(searchTerm.toLowerCase())
424
+ );
425
+ setResults(filteredResults);
426
+ setLoading(false);
427
+ }, 800);
428
+
429
+ return () => clearTimeout(timeoutId);
430
+ }, [searchTerm]);
431
+
432
+ return (
433
+ <div style={{ maxWidth: '300px' }}>
434
+ <Input
435
+ value={searchTerm}
436
+ onValueChange={setSearchTerm}
437
+ placeholder="Search items..."
438
+ leadingIcon={loading ? <Spinner /> : <Icon name="SearchFilled" />}
439
+ />
440
+
441
+ <div style={{ marginTop: '16px', minHeight: '100px' }}>
442
+ {loading ? (
443
+ <div style={{
444
+ display: 'flex',
445
+ alignItems: 'center',
446
+ justifyContent: 'center',
447
+ padding: '20px'
448
+ }}>
449
+ <Text color="secondary">Searching...</Text>
450
+ </div>
451
+ ) : results.length > 0 ? (
452
+ <div>
453
+ {results.map((result, index) => (
454
+ <div
455
+ key={index}
456
+ style={{
457
+ padding: '8px',
458
+ borderBottom: '1px solid #eee'
459
+ }}
460
+ >
461
+ <Text>{result}</Text>
462
+ </div>
463
+ ))}
464
+ </div>
465
+ ) : searchTerm.trim() !== '' ? (
466
+ <div style={{ padding: '20px', textAlign: 'center' }}>
467
+ <Text color="secondary">No results found</Text>
468
+ </div>
469
+ ) : null}
470
+ </div>
471
+ </div>
472
+ );
473
+ }
474
+ ```
475
+
476
+ ### Custom Styled Spinner
477
+
478
+ ```tsx
479
+ import { Spinner } from '@delightui/components';
480
+
481
+ function CustomStyledSpinnerExample() {
482
+ return (
483
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '24px', alignItems: 'center' }}>
484
+ <div>
485
+ <Text style={{ marginBottom: '8px' }}>Default Spinner</Text>
486
+ <Spinner />
487
+ </div>
488
+
489
+ <div>
490
+ <Text style={{ marginBottom: '8px' }}>Large Custom Spinner</Text>
491
+ <Spinner
492
+ className="large-spinner"
493
+ style={{
494
+ width: '48px',
495
+ height: '48px',
496
+ borderWidth: '4px'
497
+ }}
498
+ />
499
+ </div>
500
+
501
+ <div>
502
+ <Text style={{ marginBottom: '8px' }}>Colored Spinner</Text>
503
+ <Spinner
504
+ className="colored-spinner"
505
+ style={{
506
+ borderTopColor: '#007bff',
507
+ borderRightColor: '#007bff'
508
+ }}
509
+ />
510
+ </div>
511
+
512
+ <div>
513
+ <Text style={{ marginBottom: '8px' }}>Small Spinner</Text>
514
+ <Spinner
515
+ className="small-spinner"
516
+ style={{
517
+ width: '16px',
518
+ height: '16px',
519
+ borderWidth: '2px'
520
+ }}
521
+ />
522
+ </div>
523
+ </div>
524
+ );
525
+ }
526
+ ```
527
+
528
+ ### Multi-step Loading
529
+
530
+ ```tsx
531
+ import { Spinner, Text, Button } from '@delightui/components';
532
+
533
+ function MultiStepLoadingExample() {
534
+ const [currentStep, setCurrentStep] = useState(0);
535
+ const [loading, setLoading] = useState(false);
536
+
537
+ const steps = [
538
+ 'Initializing...',
539
+ 'Processing data...',
540
+ 'Validating results...',
541
+ 'Finalizing...',
542
+ 'Complete!'
543
+ ];
544
+
545
+ const startProcess = async () => {
546
+ setLoading(true);
547
+ setCurrentStep(0);
548
+
549
+ for (let i = 0; i < steps.length - 1; i++) {
550
+ setCurrentStep(i);
551
+ await new Promise(resolve => setTimeout(resolve, 1000));
552
+ }
553
+
554
+ setCurrentStep(steps.length - 1);
555
+ setLoading(false);
556
+ };
557
+
558
+ return (
559
+ <div style={{
560
+ padding: '24px',
561
+ border: '1px solid #ccc',
562
+ borderRadius: '8px',
563
+ textAlign: 'center',
564
+ maxWidth: '300px'
565
+ }}>
566
+ <Text weight="bold" style={{ marginBottom: '24px' }}>
567
+ Multi-step Process
568
+ </Text>
569
+
570
+ {!loading && currentStep < steps.length - 1 && (
571
+ <Button onClick={startProcess}>
572
+ Start Process
573
+ </Button>
574
+ )}
575
+
576
+ {(loading || currentStep === steps.length - 1) && (
577
+ <div style={{
578
+ display: 'flex',
579
+ flexDirection: 'column',
580
+ alignItems: 'center',
581
+ gap: '16px'
582
+ }}>
583
+ {loading && <Spinner />}
584
+ <Text
585
+ color={currentStep === steps.length - 1 ? 'success' : 'default'}
586
+ weight="medium"
587
+ >
588
+ {steps[currentStep]}
589
+ </Text>
590
+
591
+ {currentStep === steps.length - 1 && (
592
+ <Button
593
+ size="Small"
594
+ type="Outlined"
595
+ onClick={() => setCurrentStep(0)}
596
+ >
597
+ Reset
598
+ </Button>
599
+ )}
600
+ </div>
601
+ )}
602
+ </div>
603
+ );
604
+ }
605
+ ```