@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,533 @@
1
+ # Form
2
+
3
+ ## Description
4
+
5
+ A comprehensive form management component that provides state management, validation, error handling, and submission workflows. Built with TypeScript for type safety and supports both controlled and uncontrolled form patterns with extensive validation capabilities.
6
+
7
+ ## Aliases
8
+
9
+ - Form
10
+ - FormProvider
11
+ - FormContainer
12
+ - FormWrapper
13
+
14
+ ## Props Breakdown
15
+
16
+ **Extends:** `FormHTMLAttributes<HTMLFormElement>` (excluding `onSubmit`)
17
+
18
+ | Prop | Type | Default | Required | Description |
19
+ |------|------|---------|----------|-------------|
20
+ | `formRef` | `Ref<HTMLFormElement>` | - | No | Reference to the form element |
21
+ | `children` | `ReactNode` | - | No | Form fields and content |
22
+ | `formState` | `FormState` | - | No | Initial form state values |
23
+ | `onFormStateChange` | `FormStateChangeHandler` | - | No | Callback when form state changes |
24
+ | `formValidator` | `FormValidator` | - | No | Function to validate entire form |
25
+ | `onSubmit` | `FormSubmitHandler` | - | No | Form submission handler |
26
+ | `validateOnChange` | `boolean` | - | No | Whether to validate on field changes |
27
+
28
+ Plus all standard HTML form attributes (method, action, encType, target, etc.) except `onSubmit`.
29
+
30
+ ## Examples
31
+
32
+ ### Basic Form
33
+ ```tsx
34
+ import { Form, FormField, Input, Button } from '@delightui/components';
35
+
36
+ function BasicFormExample() {
37
+ const handleSubmit = (values, setError) => {
38
+ console.log('Form submitted:', values);
39
+
40
+ // Example validation
41
+ if (!values.email || !values.email.includes('@')) {
42
+ setError('email', 'Please enter a valid email address');
43
+ return;
44
+ }
45
+
46
+ // Process form submission
47
+ alert('Form submitted successfully!');
48
+ };
49
+
50
+ return (
51
+ <Form onSubmit={handleSubmit}>
52
+ <FormField name="name" label="Full Name" required>
53
+ <Input placeholder="Enter your name" />
54
+ </FormField>
55
+
56
+ <FormField name="email" label="Email Address" required>
57
+ <Input inputType="Email" placeholder="Enter your email" />
58
+ </FormField>
59
+
60
+ <FormField name="message" label="Message">
61
+ <TextArea placeholder="Your message..." rows={4} />
62
+ </FormField>
63
+
64
+ <Button actionType="submit">Submit Form</Button>
65
+ </Form>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ### Form with Validation
71
+ ```tsx
72
+ function ValidationFormExample() {
73
+ const handleSubmit = (values, setError) => {
74
+ // Custom validation logic
75
+ let hasErrors = false;
76
+
77
+ if (!values.password || values.password.length < 8) {
78
+ setError('password', 'Password must be at least 8 characters');
79
+ hasErrors = true;
80
+ }
81
+
82
+ if (values.password !== values.confirmPassword) {
83
+ setError('confirmPassword', 'Passwords do not match');
84
+ hasErrors = true;
85
+ }
86
+
87
+ if (!hasErrors) {
88
+ console.log('Creating account:', values);
89
+ }
90
+ };
91
+
92
+ const formValidator = (values, setError) => {
93
+ let isValid = true;
94
+
95
+ // Username validation
96
+ if (!values.username || values.username.length < 3) {
97
+ setError('username', 'Username must be at least 3 characters');
98
+ isValid = false;
99
+ }
100
+
101
+ // Email validation
102
+ if (!values.email || !/\S+@\S+\.\S+/.test(values.email)) {
103
+ setError('email', 'Please enter a valid email');
104
+ isValid = false;
105
+ }
106
+
107
+ return isValid;
108
+ };
109
+
110
+ return (
111
+ <Form
112
+ onSubmit={handleSubmit}
113
+ formValidator={formValidator}
114
+ validateOnChange={true}
115
+ >
116
+ <FormField name="username" label="Username" required>
117
+ <Input placeholder="Choose a username" />
118
+ </FormField>
119
+
120
+ <FormField name="email" label="Email" required>
121
+ <Input inputType="Email" placeholder="your@email.com" />
122
+ </FormField>
123
+
124
+ <FormField name="password" label="Password" required>
125
+ <Input inputType="Password" placeholder="Create password" />
126
+ </FormField>
127
+
128
+ <FormField name="confirmPassword" label="Confirm Password" required>
129
+ <Input inputType="Password" placeholder="Confirm password" />
130
+ </FormField>
131
+
132
+ <div className="form-actions">
133
+ <Button actionType="submit">Create Account</Button>
134
+ <Button type="Outlined" actionType="reset">Clear Form</Button>
135
+ </div>
136
+ </Form>
137
+ );
138
+ }
139
+ ```
140
+
141
+ ### Form with Initial State
142
+ ```tsx
143
+ function InitialStateFormExample() {
144
+ const initialFormState = {
145
+ firstName: 'John',
146
+ lastName: 'Doe',
147
+ email: 'john.doe@example.com',
148
+ role: 'developer',
149
+ notifications: true
150
+ };
151
+
152
+ const handleSubmit = (values, setError) => {
153
+ console.log('Updated profile:', values);
154
+ };
155
+
156
+ const handleStateChange = (state, setError) => {
157
+ // Validate on state change
158
+ if (state.email && !state.email.includes('@')) {
159
+ setError('email', 'Invalid email format');
160
+ }
161
+ };
162
+
163
+ return (
164
+ <Form
165
+ formState={initialFormState}
166
+ onSubmit={handleSubmit}
167
+ onFormStateChange={handleStateChange}
168
+ >
169
+ <FormField name="firstName" label="First Name" required>
170
+ <Input />
171
+ </FormField>
172
+
173
+ <FormField name="lastName" label="Last Name" required>
174
+ <Input />
175
+ </FormField>
176
+
177
+ <FormField name="email" label="Email" required>
178
+ <Input inputType="Email" />
179
+ </FormField>
180
+
181
+ <FormField name="role" label="Role">
182
+ <Select>
183
+ <Option value="developer">Developer</Option>
184
+ <Option value="designer">Designer</Option>
185
+ <Option value="manager">Manager</Option>
186
+ </Select>
187
+ </FormField>
188
+
189
+ <FormField name="notifications" label="Email Notifications">
190
+ <Checkbox>Send me email notifications</Checkbox>
191
+ </FormField>
192
+
193
+ <Button actionType="submit">Update Profile</Button>
194
+ </Form>
195
+ );
196
+ }
197
+ ```
198
+
199
+ ### Multi-Step Form
200
+ ```tsx
201
+ function MultiStepFormExample() {
202
+ const [currentStep, setCurrentStep] = useState(1);
203
+ const [formData, setFormData] = useState({});
204
+
205
+ const handleStepSubmit = (values, setError) => {
206
+ setFormData(prev => ({ ...prev, ...values }));
207
+
208
+ if (currentStep < 3) {
209
+ setCurrentStep(prev => prev + 1);
210
+ } else {
211
+ // Final submission
212
+ console.log('Complete form data:', { ...formData, ...values });
213
+ alert('Form completed successfully!');
214
+ }
215
+ };
216
+
217
+ return (
218
+ <div className="multi-step-form">
219
+ <div className="step-indicator">
220
+ <Text>Step {currentStep} of 3</Text>
221
+ </div>
222
+
223
+ {currentStep === 1 && (
224
+ <Form onSubmit={handleStepSubmit}>
225
+ <Text type="Heading4">Personal Information</Text>
226
+
227
+ <FormField name="firstName" label="First Name" required>
228
+ <Input />
229
+ </FormField>
230
+
231
+ <FormField name="lastName" label="Last Name" required>
232
+ <Input />
233
+ </FormField>
234
+
235
+ <FormField name="birthDate" label="Date of Birth">
236
+ <DatePicker />
237
+ </FormField>
238
+
239
+ <Button actionType="submit">Next Step</Button>
240
+ </Form>
241
+ )}
242
+
243
+ {currentStep === 2 && (
244
+ <Form onSubmit={handleStepSubmit}>
245
+ <Text type="Heading4">Contact Information</Text>
246
+
247
+ <FormField name="email" label="Email" required>
248
+ <Input inputType="Email" />
249
+ </FormField>
250
+
251
+ <FormField name="phone" label="Phone Number">
252
+ <Input inputType="Tel" />
253
+ </FormField>
254
+
255
+ <FormField name="address" label="Address">
256
+ <TextArea rows={3} />
257
+ </FormField>
258
+
259
+ <div className="step-actions">
260
+ <Button
261
+ type="Outlined"
262
+ onClick={() => setCurrentStep(1)}
263
+ >
264
+ Previous
265
+ </Button>
266
+ <Button actionType="submit">Next Step</Button>
267
+ </div>
268
+ </Form>
269
+ )}
270
+
271
+ {currentStep === 3 && (
272
+ <Form onSubmit={handleStepSubmit}>
273
+ <Text type="Heading4">Preferences</Text>
274
+
275
+ <FormField name="newsletter" label="Newsletter">
276
+ <Checkbox>Subscribe to our newsletter</Checkbox>
277
+ </FormField>
278
+
279
+ <FormField name="theme" label="Preferred Theme">
280
+ <RadioGroup>
281
+ <RadioButton value="light">Light Theme</RadioButton>
282
+ <RadioButton value="dark">Dark Theme</RadioButton>
283
+ <RadioButton value="auto">Auto (System)</RadioButton>
284
+ </RadioGroup>
285
+ </FormField>
286
+
287
+ <div className="step-actions">
288
+ <Button
289
+ type="Outlined"
290
+ onClick={() => setCurrentStep(2)}
291
+ >
292
+ Previous
293
+ </Button>
294
+ <Button actionType="submit">Complete</Button>
295
+ </div>
296
+ </Form>
297
+ )}
298
+ </div>
299
+ );
300
+ }
301
+ ```
302
+
303
+ ### Dynamic Form Fields
304
+ ```tsx
305
+ function DynamicFormExample() {
306
+ const [fieldCount, setFieldCount] = useState(1);
307
+
308
+ const handleSubmit = (values, setError) => {
309
+ const skills = [];
310
+ for (let i = 1; i <= fieldCount; i++) {
311
+ if (values[`skill${i}`]) {
312
+ skills.push(values[`skill${i}`]);
313
+ }
314
+ }
315
+
316
+ console.log('Skills:', skills);
317
+ };
318
+
319
+ const addField = () => setFieldCount(prev => prev + 1);
320
+ const removeField = () => setFieldCount(prev => Math.max(1, prev - 1));
321
+
322
+ return (
323
+ <Form onSubmit={handleSubmit}>
324
+ <Text type="Heading4">Skills</Text>
325
+
326
+ {Array.from({ length: fieldCount }, (_, index) => (
327
+ <FormField
328
+ key={index + 1}
329
+ name={`skill${index + 1}`}
330
+ label={`Skill ${index + 1}`}
331
+ required={index === 0}
332
+ >
333
+ <Input placeholder="Enter a skill" />
334
+ </FormField>
335
+ ))}
336
+
337
+ <div className="dynamic-field-controls">
338
+ <Button
339
+ type="Ghost"
340
+ onClick={addField}
341
+ leadingIcon={<Icon icon="Add" />}
342
+ >
343
+ Add Skill
344
+ </Button>
345
+
346
+ {fieldCount > 1 && (
347
+ <Button
348
+ type="Ghost"
349
+ onClick={removeField}
350
+ leadingIcon={<Icon icon="Remove" />}
351
+ >
352
+ Remove Skill
353
+ </Button>
354
+ )}
355
+ </div>
356
+
357
+ <Button actionType="submit">Save Skills</Button>
358
+ </Form>
359
+ );
360
+ }
361
+ ```
362
+
363
+ ### File Upload Form
364
+ ```tsx
365
+ function FileUploadFormExample() {
366
+ const handleSubmit = (values, setError) => {
367
+ if (!values.file) {
368
+ setError('file', 'Please select a file to upload');
369
+ return;
370
+ }
371
+
372
+ console.log('Uploading file:', values.file);
373
+ };
374
+
375
+ return (
376
+ <Form onSubmit={handleSubmit}>
377
+ <FormField name="title" label="Document Title" required>
378
+ <Input placeholder="Enter document title" />
379
+ </FormField>
380
+
381
+ <FormField name="description" label="Description">
382
+ <TextArea placeholder="Document description..." rows={3} />
383
+ </FormField>
384
+
385
+ <FormField name="category" label="Category" required>
386
+ <Select>
387
+ <Option value="report">Report</Option>
388
+ <Option value="presentation">Presentation</Option>
389
+ <Option value="document">Document</Option>
390
+ </Select>
391
+ </FormField>
392
+
393
+ <FormField name="file" label="File" required>
394
+ <Dropzone
395
+ accept=".pdf,.doc,.docx,.ppt,.pptx"
396
+ maxSize={10485760} // 10MB
397
+ >
398
+ <Text>Drag and drop a file here, or click to select</Text>
399
+ <Text type="BodySmall">Supports PDF, DOC, DOCX, PPT, PPTX (max 10MB)</Text>
400
+ </Dropzone>
401
+ </FormField>
402
+
403
+ <FormField name="public" label="Visibility">
404
+ <Checkbox>Make this document public</Checkbox>
405
+ </FormField>
406
+
407
+ <Button actionType="submit">Upload Document</Button>
408
+ </Form>
409
+ );
410
+ }
411
+ ```
412
+
413
+ ### Form with Custom Validation
414
+ ```tsx
415
+ function CustomValidationExample() {
416
+ const validatePassword = (setError, value) => {
417
+ if (!value) {
418
+ setError('Password is required');
419
+ return false;
420
+ }
421
+
422
+ if (value.length < 8) {
423
+ setError('Password must be at least 8 characters');
424
+ return false;
425
+ }
426
+
427
+ if (!/(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/.test(value)) {
428
+ setError('Password must contain uppercase, lowercase, and numbers');
429
+ return false;
430
+ }
431
+
432
+ return true;
433
+ };
434
+
435
+ const handleSubmit = (values, setError) => {
436
+ // Additional cross-field validation
437
+ if (values.password !== values.confirmPassword) {
438
+ setError('confirmPassword', 'Passwords do not match');
439
+ return;
440
+ }
441
+
442
+ console.log('Account created:', values);
443
+ };
444
+
445
+ return (
446
+ <Form onSubmit={handleSubmit}>
447
+ <FormField name="email" label="Email" required>
448
+ <Input inputType="Email" />
449
+ </FormField>
450
+
451
+ <FormField
452
+ name="password"
453
+ label="Password"
454
+ required
455
+ validate={validatePassword}
456
+ >
457
+ <Input inputType="Password" />
458
+ </FormField>
459
+
460
+ <FormField name="confirmPassword" label="Confirm Password" required>
461
+ <Input inputType="Password" />
462
+ </FormField>
463
+
464
+ <FormField name="terms" label="Agreement" required>
465
+ <Checkbox>I agree to the terms and conditions</Checkbox>
466
+ </FormField>
467
+
468
+ <Button actionType="submit">Create Account</Button>
469
+ </Form>
470
+ );
471
+ }
472
+ ```
473
+
474
+ ### Async Form Submission
475
+ ```tsx
476
+ function AsyncFormExample() {
477
+ const [isSubmitting, setIsSubmitting] = useState(false);
478
+
479
+ const handleSubmit = async (values, setError) => {
480
+ setIsSubmitting(true);
481
+
482
+ try {
483
+ // Simulate API call
484
+ const response = await fetch('/api/contact', {
485
+ method: 'POST',
486
+ headers: { 'Content-Type': 'application/json' },
487
+ body: JSON.stringify(values)
488
+ });
489
+
490
+ if (!response.ok) {
491
+ throw new Error('Submission failed');
492
+ }
493
+
494
+ const result = await response.json();
495
+ console.log('Success:', result);
496
+ alert('Message sent successfully!');
497
+
498
+ } catch (error) {
499
+ setError('general', 'Failed to send message. Please try again.');
500
+ } finally {
501
+ setIsSubmitting(false);
502
+ }
503
+ };
504
+
505
+ return (
506
+ <Form onSubmit={handleSubmit}>
507
+ <FormField name="name" label="Name" required>
508
+ <Input disabled={isSubmitting} />
509
+ </FormField>
510
+
511
+ <FormField name="email" label="Email" required>
512
+ <Input inputType="Email" disabled={isSubmitting} />
513
+ </FormField>
514
+
515
+ <FormField name="subject" label="Subject" required>
516
+ <Input disabled={isSubmitting} />
517
+ </FormField>
518
+
519
+ <FormField name="message" label="Message" required>
520
+ <TextArea rows={5} disabled={isSubmitting} />
521
+ </FormField>
522
+
523
+ <Button
524
+ actionType="submit"
525
+ loading={isSubmitting}
526
+ disabled={isSubmitting}
527
+ >
528
+ Send Message
529
+ </Button>
530
+ </Form>
531
+ );
532
+ }
533
+ ```