@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,379 @@
1
+ # useModal
2
+
3
+ ## Description
4
+
5
+ A React hook that provides programmatic modal management with automatic ID generation and simplified modal state handling. The useModal hook takes a modal component as a parameter and returns functions to open and close that specific modal, along with automatic unique identifier generation for each modal instance.
6
+
7
+ ## Aliases
8
+
9
+ - useModal
10
+ - Modal Hook
11
+ - Modal Manager
12
+
13
+ ## Hook Signature
14
+
15
+ ```tsx
16
+ function useModal<T extends ModalComponentProps>(
17
+ Component: React.ComponentType<T>
18
+ ): UseModalReturn<T>
19
+ ```
20
+
21
+ ## Parameters
22
+
23
+ | Parameter | Type | Required | Description |
24
+ |-----------|------|----------|-------------|
25
+ | `Component` | `React.ComponentType<T>` | Yes | Modal component that extends ModalComponentProps |
26
+
27
+ ## Return Value
28
+
29
+ Returns an object with the following properties:
30
+
31
+ | Property | Type | Description |
32
+ |----------|------|-------------|
33
+ | `openModal` | `(props: T) => void` | Function to open the modal with specified props |
34
+ | `closeModal` | `() => void` | Function to close the modal instance |
35
+ | `modalId` | `string` | Unique identifier for this modal instance |
36
+
37
+ ## Requirements
38
+
39
+ ### ModalComponentProps Interface
40
+
41
+ Modal components used with `useModal` must extend the `ModalComponentProps` interface:
42
+
43
+ ```tsx
44
+ interface ModalComponentProps {
45
+ show?: boolean;
46
+ onCancel?: () => void;
47
+ }
48
+ ```
49
+
50
+ The hook automatically provides these props:
51
+ - `show`: Set to `true` when modal is opened
52
+ - `onCancel`: Function that closes the modal and calls the original `onCancel` if provided
53
+
54
+ ## Examples
55
+
56
+ ### Basic Usage
57
+
58
+ ```tsx
59
+ import React from 'react';
60
+ import { Modal, Button, Text, useModal } from '@delightui/components';
61
+
62
+ // Define your modal component
63
+ const AlertModal = ({ show, onCancel, title, message }) => (
64
+ <Modal show={show} onHide={onCancel}>
65
+ <Text type="Heading4">{title}</Text>
66
+ <Text>{message}</Text>
67
+ </Modal>
68
+ );
69
+
70
+ function MyComponent() {
71
+ const alertModal = useModal(AlertModal);
72
+
73
+ const showAlert = () => {
74
+ alertModal.openModal({
75
+ title: 'Success!',
76
+ message: 'Your action was completed successfully.'
77
+ });
78
+ };
79
+
80
+ return (
81
+ <Button onClick={showAlert}>
82
+ Show Alert
83
+ </Button>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ### Confirmation Modal
89
+
90
+ ```tsx
91
+ import { Modal, Button, Text, useModal } from '@delightui/components';
92
+
93
+ const ConfirmationModal = ({ show, onCancel, title, message, onConfirm }) => (
94
+ <Modal
95
+ show={show}
96
+ onHide={onCancel}
97
+ footer={
98
+ <div style={{ display: 'flex', gap: '8px' }}>
99
+ <Button type="Outlined" onClick={onCancel}>Cancel</Button>
100
+ <Button style="Primary" onClick={onConfirm}>Confirm</Button>
101
+ </div>
102
+ }
103
+ >
104
+ <Text type="Heading4">{title}</Text>
105
+ <Text>{message}</Text>
106
+ </Modal>
107
+ );
108
+
109
+ function DeleteButton() {
110
+ const confirmModal = useModal(ConfirmationModal);
111
+
112
+ const handleDelete = () => {
113
+ confirmModal.openModal({
114
+ title: 'Delete Item',
115
+ message: 'Are you sure you want to delete this item? This action cannot be undone.',
116
+ onConfirm: () => {
117
+ // Perform delete action
118
+ console.log('Item deleted');
119
+ confirmModal.closeModal();
120
+ }
121
+ });
122
+ };
123
+
124
+ return (
125
+ <Button style="Destructive" onClick={handleDelete}>
126
+ Delete Item
127
+ </Button>
128
+ );
129
+ }
130
+ ```
131
+
132
+ ### Form Modal
133
+
134
+ ```tsx
135
+ import { Modal, Form, FormField, Input, Button, useModal } from '@delightui/components';
136
+
137
+ const UserFormModal = ({ show, onCancel, onSubmit, initialData }) => {
138
+ const handleSubmit = (formData) => {
139
+ onSubmit(formData);
140
+ onCancel(); // Close modal after submission
141
+ };
142
+
143
+ return (
144
+ <Modal
145
+ show={show}
146
+ onHide={onCancel}
147
+ size="Medium"
148
+ header={<Text type="Heading4">Edit User</Text>}
149
+ >
150
+ <Form onSubmit={handleSubmit} initialValues={initialData}>
151
+ <FormField name="name" label="Name" required>
152
+ <Input placeholder="Enter name" />
153
+ </FormField>
154
+
155
+ <FormField name="email" label="Email" required>
156
+ <Input type="email" placeholder="Enter email" />
157
+ </FormField>
158
+
159
+ <div style={{ display: 'flex', gap: '8px', marginTop: '16px' }}>
160
+ <Button type="Outlined" onClick={onCancel}>
161
+ Cancel
162
+ </Button>
163
+ <Button actionType="submit">
164
+ Save Changes
165
+ </Button>
166
+ </div>
167
+ </Form>
168
+ </Modal>
169
+ );
170
+ };
171
+
172
+ function UserList() {
173
+ const userModal = useModal(UserFormModal);
174
+
175
+ const editUser = (user) => {
176
+ userModal.openModal({
177
+ initialData: user,
178
+ onSubmit: (formData) => {
179
+ console.log('User updated:', formData);
180
+ // Handle form submission
181
+ }
182
+ });
183
+ };
184
+
185
+ return (
186
+ <Button onClick={() => editUser({ name: 'John', email: 'john@example.com' })}>
187
+ Edit User
188
+ </Button>
189
+ );
190
+ }
191
+ ```
192
+
193
+ ### Multiple Modal Types
194
+
195
+ ```tsx
196
+ import { useModal } from '@delightui/components';
197
+
198
+ function Dashboard() {
199
+ const alertModal = useModal(AlertModal);
200
+ const confirmModal = useModal(ConfirmationModal);
201
+ const formModal = useModal(UserFormModal);
202
+
203
+ return (
204
+ <div>
205
+ <Button onClick={() => alertModal.openModal({
206
+ title: 'Info',
207
+ message: 'This is an information message.'
208
+ })}>
209
+ Show Info
210
+ </Button>
211
+
212
+ <Button onClick={() => confirmModal.openModal({
213
+ title: 'Confirm Action',
214
+ message: 'Are you sure?',
215
+ onConfirm: () => console.log('Confirmed')
216
+ })}>
217
+ Confirm Action
218
+ </Button>
219
+
220
+ <Button onClick={() => formModal.openModal({
221
+ onSubmit: (data) => console.log('Form data:', data)
222
+ })}>
223
+ Open Form
224
+ </Button>
225
+ </div>
226
+ );
227
+ }
228
+ ```
229
+
230
+ ### Custom Modal with Complex State
231
+
232
+ ```tsx
233
+ const SettingsModal = ({ show, onCancel, settings, onSave }) => {
234
+ const [localSettings, setLocalSettings] = useState(settings);
235
+
236
+ useEffect(() => {
237
+ setLocalSettings(settings);
238
+ }, [settings]);
239
+
240
+ const handleSave = () => {
241
+ onSave(localSettings);
242
+ onCancel();
243
+ };
244
+
245
+ return (
246
+ <Modal
247
+ show={show}
248
+ onHide={onCancel}
249
+ size="Large"
250
+ header={<Text type="Heading3">Settings</Text>}
251
+ footer={
252
+ <div>
253
+ <Button type="Outlined" onClick={onCancel}>Cancel</Button>
254
+ <Button onClick={handleSave}>Save Settings</Button>
255
+ </div>
256
+ }
257
+ >
258
+ {/* Settings form content */}
259
+ <div>
260
+ <h4>Notification Settings</h4>
261
+ <label>
262
+ <input
263
+ type="checkbox"
264
+ checked={localSettings.notifications}
265
+ onChange={(e) => setLocalSettings(prev => ({
266
+ ...prev,
267
+ notifications: e.target.checked
268
+ }))}
269
+ />
270
+ Enable notifications
271
+ </label>
272
+ </div>
273
+ </Modal>
274
+ );
275
+ };
276
+
277
+ function SettingsPage() {
278
+ const settingsModal = useModal(SettingsModal);
279
+ const [userSettings, setUserSettings] = useState({
280
+ notifications: true,
281
+ theme: 'light'
282
+ });
283
+
284
+ const openSettings = () => {
285
+ settingsModal.openModal({
286
+ settings: userSettings,
287
+ onSave: (newSettings) => {
288
+ setUserSettings(newSettings);
289
+ console.log('Settings saved:', newSettings);
290
+ }
291
+ });
292
+ };
293
+
294
+ return (
295
+ <Button onClick={openSettings}>
296
+ Open Settings
297
+ </Button>
298
+ );
299
+ }
300
+ ```
301
+
302
+ ## TypeScript Support
303
+
304
+ The hook is fully typed and provides excellent TypeScript support:
305
+
306
+ ```tsx
307
+ interface MyModalProps extends ModalComponentProps {
308
+ title: string;
309
+ count: number;
310
+ onAction: (value: string) => void;
311
+ }
312
+
313
+ const MyModal: React.FC<MyModalProps> = ({ show, onCancel, title, count, onAction }) => {
314
+ // Modal implementation
315
+ };
316
+
317
+ function MyComponent() {
318
+ const modal = useModal(MyModal);
319
+
320
+ // TypeScript will enforce correct prop types
321
+ modal.openModal({
322
+ title: "Required string", // ✅ Required
323
+ count: 42, // ✅ Required number
324
+ onAction: (val) => {...} // ✅ Required function
325
+ // Missing any required prop will cause TypeScript error
326
+ });
327
+ }
328
+ ```
329
+
330
+ ## Best Practices
331
+
332
+ 1. **Create reusable modal components** that extend `ModalComponentProps`
333
+ 2. **Use one hook per modal type** for better organization
334
+ 3. **Handle async operations** within modal components or callbacks
335
+ 4. **Always provide meaningful prop types** for better TypeScript support
336
+ 5. **Keep modal logic separate** from business logic for better testability
337
+
338
+ ## Common Patterns
339
+
340
+ ### Loading States
341
+
342
+ ```tsx
343
+ const LoadingModal = ({ show, onCancel, isLoading, message }) => (
344
+ <Modal show={show} onHide={!isLoading ? onCancel : undefined}>
345
+ {isLoading ? (
346
+ <div>
347
+ <Spinner />
348
+ <Text>Loading...</Text>
349
+ </div>
350
+ ) : (
351
+ <Text>{message}</Text>
352
+ )}
353
+ </Modal>
354
+ );
355
+ ```
356
+
357
+ ### Conditional Modal Content
358
+
359
+ ```tsx
360
+ const DynamicModal = ({ show, onCancel, mode, data }) => (
361
+ <Modal show={show} onHide={onCancel}>
362
+ {mode === 'view' && <ViewContent data={data} />}
363
+ {mode === 'edit' && <EditContent data={data} />}
364
+ {mode === 'delete' && <DeleteConfirmation data={data} />}
365
+ </Modal>
366
+ );
367
+ ```
368
+
369
+ ## Requirements
370
+
371
+ - Must be used within a `ModalProvider`
372
+ - Modal components must extend `ModalComponentProps`
373
+ - Requires React 18+ for `useId` hook support
374
+
375
+ ## Related
376
+
377
+ - **[ModalProvider](./ModalProvider.md)** - Context provider for modal state
378
+ - **[Modal](./Modal.md)** - Base modal component
379
+ - **[ModalComponentProps](./Modal.md#modalcomponentprops)** - Required interface for modal components
@@ -0,0 +1,346 @@
1
+ # Dropzone
2
+
3
+ ## Description
4
+
5
+ A comprehensive file upload component with drag-and-drop functionality. The Dropzone component provides an intuitive interface for users to upload files either by dragging and dropping them onto the designated area or by clicking to open a file dialog. It supports file type restrictions, size limits, and multiple file uploads with customizable states for empty, loading, and uploaded scenarios.
6
+
7
+ ## Aliases
8
+
9
+ - Dropzone
10
+ - File Upload
11
+ - File Drop
12
+ - Upload Area
13
+
14
+ ## Props Breakdown
15
+
16
+ **Extends:** `ControlledFormComponentProps<File[]>`
17
+
18
+ | Prop | Type | Default | Required | Description |
19
+ |------|------|---------|----------|-------------|
20
+ | `empty` | `ReactNode` | - | No | Content to display when the dropzone is empty |
21
+ | `loading` | `ReactNode` | - | No | Content to display during file upload/processing |
22
+ | `uploaded` | `ReactNode` | - | No | Content to display when files are uploaded |
23
+ | `accept` | `{ [key: string]: readonly string[] }` | - | No | Accepted file types based on mime type |
24
+ | `maxSize` | `number` | - | No | Maximum file size in bytes |
25
+ | `maxFiles` | `number` | `1` | No | Maximum number of files to upload |
26
+ | `onFilesReset` | `() => void` | - | No | Callback when files are reset |
27
+ | `className` | `string` | - | No | Additional CSS class names |
28
+ | `initialValue` | `File[]` | - | No | Initial files value |
29
+ | `value` | `File[]` | - | No | Current files value |
30
+ | `onValueChange` | `(files: File[]) => void` | - | No | Callback when files change |
31
+ | `disabled` | `boolean` | `false` | No | Whether the dropzone is disabled |
32
+ | `required` | `boolean` | `false` | No | Whether file selection is required |
33
+ | `invalid` | `boolean` | `false` | No | Whether the current state is invalid |
34
+ | `id` | `string` | - | No | ID for the dropzone |
35
+
36
+ Plus all standard HTML div attributes (aria-*, data-*, etc.).
37
+
38
+ ## Examples
39
+
40
+ ### Basic Dropzone
41
+
42
+ ```tsx
43
+ import { Dropzone } from '@delightui/components';
44
+
45
+ function BasicDropzoneExample() {
46
+ const [files, setFiles] = useState<File[]>([]);
47
+
48
+ return (
49
+ <Dropzone
50
+ value={files}
51
+ onValueChange={setFiles}
52
+ maxFiles={1}
53
+ accept={{
54
+ 'image/*': ['.jpg', '.jpeg', '.png', '.gif']
55
+ }}
56
+ />
57
+ );
58
+ }
59
+ ```
60
+
61
+ ### Custom States
62
+
63
+ ```tsx
64
+ import { Dropzone, Text, Spinner, Button } from '@delightui/components';
65
+
66
+ function CustomStatesExample() {
67
+ const [files, setFiles] = useState<File[]>([]);
68
+ const [isUploading, setIsUploading] = useState(false);
69
+
70
+ const handleUpload = async () => {
71
+ setIsUploading(true);
72
+ // Simulate upload
73
+ await new Promise(resolve => setTimeout(resolve, 2000));
74
+ setIsUploading(false);
75
+ };
76
+
77
+ return (
78
+ <Dropzone
79
+ value={files}
80
+ onValueChange={setFiles}
81
+ empty={
82
+ <div style={{ textAlign: 'center', padding: '40px' }}>
83
+ <Text size="large">Drop files here or click to upload</Text>
84
+ <Text size="small" color="secondary">
85
+ Supports JPG, PNG, GIF up to 10MB
86
+ </Text>
87
+ </div>
88
+ }
89
+ loading={
90
+ <div style={{ textAlign: 'center', padding: '40px' }}>
91
+ <Spinner />
92
+ <Text>Uploading files...</Text>
93
+ </div>
94
+ }
95
+ uploaded={
96
+ <div style={{ textAlign: 'center', padding: '40px' }}>
97
+ <Text color="success">✓ Files uploaded successfully</Text>
98
+ <Button onClick={() => setFiles([])}>Upload More</Button>
99
+ </div>
100
+ }
101
+ accept={{
102
+ 'image/*': ['.jpg', '.jpeg', '.png', '.gif']
103
+ }}
104
+ maxSize={10 * 1024 * 1024} // 10MB
105
+ maxFiles={5}
106
+ />
107
+ );
108
+ }
109
+ ```
110
+
111
+ ### Multiple File Upload
112
+
113
+ ```tsx
114
+ import { Dropzone, Text } from '@delightui/components';
115
+
116
+ function MultipleFileExample() {
117
+ const [files, setFiles] = useState<File[]>([]);
118
+
119
+ const handleFilesReset = () => {
120
+ setFiles([]);
121
+ console.log('Files reset');
122
+ };
123
+
124
+ return (
125
+ <div>
126
+ <Dropzone
127
+ value={files}
128
+ onValueChange={setFiles}
129
+ onFilesReset={handleFilesReset}
130
+ maxFiles={10}
131
+ accept={{
132
+ 'image/*': ['.jpg', '.jpeg', '.png'],
133
+ 'application/pdf': ['.pdf'],
134
+ 'text/*': ['.txt', '.csv']
135
+ }}
136
+ maxSize={5 * 1024 * 1024} // 5MB per file
137
+ />
138
+
139
+ {files.length > 0 && (
140
+ <div style={{ marginTop: '16px' }}>
141
+ <Text>Selected files: {files.length}</Text>
142
+ {files.map((file, index) => (
143
+ <Text key={index} size="small">
144
+ {file.name} ({(file.size / 1024).toFixed(1)} KB)
145
+ </Text>
146
+ ))}
147
+ </div>
148
+ )}
149
+ </div>
150
+ );
151
+ }
152
+ ```
153
+
154
+ ### Form Integration
155
+
156
+ ```tsx
157
+ import { Form, FormField, Dropzone, Button } from '@delightui/components';
158
+
159
+ function FormDropzoneExample() {
160
+ const handleSubmit = (data: any) => {
161
+ console.log('Form submitted with files:', data.documents);
162
+ };
163
+
164
+ return (
165
+ <Form onSubmit={handleSubmit}>
166
+ <FormField
167
+ name="documents"
168
+ label="Upload Documents"
169
+ required
170
+ message="Please upload at least one document"
171
+ >
172
+ <Dropzone
173
+ accept={{
174
+ 'application/pdf': ['.pdf'],
175
+ 'application/msword': ['.doc'],
176
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': ['.docx']
177
+ }}
178
+ maxSize={20 * 1024 * 1024} // 20MB
179
+ maxFiles={3}
180
+ />
181
+ </FormField>
182
+
183
+ <Button actionType="submit">Submit Documents</Button>
184
+ </Form>
185
+ );
186
+ }
187
+ ```
188
+
189
+ ### Image Upload with Preview
190
+
191
+ ```tsx
192
+ import { Dropzone, Text, Image } from '@delightui/components';
193
+
194
+ function ImageUploadExample() {
195
+ const [files, setFiles] = useState<File[]>([]);
196
+ const [previews, setPreviews] = useState<string[]>([]);
197
+
198
+ useEffect(() => {
199
+ // Create preview URLs for images
200
+ const urls = files.map(file => {
201
+ if (file.type.startsWith('image/')) {
202
+ return URL.createObjectURL(file);
203
+ }
204
+ return null;
205
+ }).filter(Boolean) as string[];
206
+
207
+ setPreviews(urls);
208
+
209
+ // Cleanup URLs on unmount
210
+ return () => {
211
+ urls.forEach(url => URL.revokeObjectURL(url));
212
+ };
213
+ }, [files]);
214
+
215
+ return (
216
+ <div>
217
+ <Dropzone
218
+ value={files}
219
+ onValueChange={setFiles}
220
+ accept={{
221
+ 'image/*': ['.jpg', '.jpeg', '.png', '.gif', '.webp']
222
+ }}
223
+ maxSize={5 * 1024 * 1024}
224
+ maxFiles={1}
225
+ uploaded={
226
+ previews.length > 0 ? (
227
+ <div style={{ textAlign: 'center', padding: '20px' }}>
228
+ <Image
229
+ src={previews[0]}
230
+ alt="Preview"
231
+ width={200}
232
+ height={200}
233
+ fit="Crop"
234
+ style={{ borderRadius: '8px' }}
235
+ />
236
+ <Text>Image uploaded successfully</Text>
237
+ </div>
238
+ ) : undefined
239
+ }
240
+ />
241
+ </div>
242
+ );
243
+ }
244
+ ```
245
+
246
+ ### Disabled State
247
+
248
+ ```tsx
249
+ import { Dropzone, Text } from '@delightui/components';
250
+
251
+ function DisabledDropzoneExample() {
252
+ return (
253
+ <Dropzone
254
+ disabled
255
+ empty={
256
+ <div style={{ textAlign: 'center', padding: '40px' }}>
257
+ <Text color="disabled">File upload is currently disabled</Text>
258
+ </div>
259
+ }
260
+ />
261
+ );
262
+ }
263
+ ```
264
+
265
+ ### Custom Styling
266
+
267
+ ```tsx
268
+ import { Dropzone, Text } from '@delightui/components';
269
+
270
+ function CustomStyledDropzoneExample() {
271
+ const [files, setFiles] = useState<File[]>([]);
272
+
273
+ return (
274
+ <Dropzone
275
+ value={files}
276
+ onValueChange={setFiles}
277
+ className="custom-dropzone"
278
+ style={{
279
+ border: '2px dashed #007bff',
280
+ borderRadius: '12px',
281
+ backgroundColor: '#f8f9fa'
282
+ }}
283
+ empty={
284
+ <div style={{
285
+ textAlign: 'center',
286
+ padding: '60px 20px',
287
+ color: '#007bff'
288
+ }}>
289
+ <Text size="large">📁 Drop your files here</Text>
290
+ <Text size="small">or click to browse</Text>
291
+ </div>
292
+ }
293
+ />
294
+ );
295
+ }
296
+ ```
297
+
298
+ ### Error Handling
299
+
300
+ ```tsx
301
+ import { Dropzone, Text } from '@delightui/components';
302
+
303
+ function ErrorHandlingExample() {
304
+ const [files, setFiles] = useState<File[]>([]);
305
+ const [error, setError] = useState<string>('');
306
+
307
+ const handleFileChange = (newFiles: File[]) => {
308
+ setError('');
309
+
310
+ // Validate files
311
+ const invalidFiles = newFiles.filter(file => {
312
+ if (file.size > 10 * 1024 * 1024) {
313
+ setError(`File "${file.name}" is too large. Maximum size is 10MB.`);
314
+ return true;
315
+ }
316
+ return false;
317
+ });
318
+
319
+ if (invalidFiles.length === 0) {
320
+ setFiles(newFiles);
321
+ }
322
+ };
323
+
324
+ return (
325
+ <div>
326
+ <Dropzone
327
+ value={files}
328
+ onValueChange={handleFileChange}
329
+ invalid={!!error}
330
+ accept={{
331
+ 'image/*': ['.jpg', '.jpeg', '.png'],
332
+ 'application/pdf': ['.pdf']
333
+ }}
334
+ maxSize={10 * 1024 * 1024}
335
+ maxFiles={3}
336
+ />
337
+
338
+ {error && (
339
+ <Text color="error" size="small" style={{ marginTop: '8px' }}>
340
+ {error}
341
+ </Text>
342
+ )}
343
+ </div>
344
+ );
345
+ }
346
+ ```