@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.
- package/README.md +104 -1
- package/dist/cjs/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/cjs/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/cjs/components/molecules/Modal/index.d.ts +2 -0
- package/dist/cjs/components/molecules/Popover/Popover.presenter.d.ts +26 -0
- package/dist/cjs/components/molecules/Select/Option/Option.types.d.ts +6 -0
- package/dist/cjs/components/molecules/Select/Select.Context.d.ts +1 -1
- package/dist/cjs/components/molecules/Select/Select.d.ts +5 -5
- package/dist/cjs/components/molecules/Select/Select.presenter.d.ts +1 -0
- package/dist/cjs/components/molecules/Select/Select.types.d.ts +5 -0
- package/dist/cjs/components/molecules/Select/index.d.ts +2 -9
- package/dist/cjs/components/molecules/index.d.ts +2 -0
- package/dist/cjs/components/utils/accessibilityUtils.d.ts +41 -0
- package/dist/cjs/components/utils/index.d.ts +2 -0
- package/dist/cjs/library.css +13 -0
- package/dist/cjs/library.js +2 -2
- package/dist/cjs/library.js.map +1 -1
- package/dist/esm/components/molecules/Modal/DemoModal.d.ts +8 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.d.ts +41 -0
- package/dist/esm/components/molecules/Modal/ModalContext/ModalContext.types.d.ts +87 -0
- package/dist/esm/components/molecules/Modal/ModalContext/index.d.ts +3 -0
- package/dist/esm/components/molecules/Modal/ModalContext/useModal.d.ts +34 -0
- package/dist/esm/components/molecules/Modal/index.d.ts +2 -0
- package/dist/esm/components/molecules/Popover/Popover.presenter.d.ts +26 -0
- package/dist/esm/components/molecules/Select/Option/Option.types.d.ts +6 -0
- package/dist/esm/components/molecules/Select/Select.Context.d.ts +1 -1
- package/dist/esm/components/molecules/Select/Select.d.ts +5 -5
- package/dist/esm/components/molecules/Select/Select.presenter.d.ts +1 -0
- package/dist/esm/components/molecules/Select/Select.types.d.ts +5 -0
- package/dist/esm/components/molecules/Select/index.d.ts +2 -9
- package/dist/esm/components/molecules/index.d.ts +2 -0
- package/dist/esm/components/utils/accessibilityUtils.d.ts +41 -0
- package/dist/esm/components/utils/index.d.ts +2 -0
- package/dist/esm/library.css +13 -0
- package/dist/esm/library.js +3 -3
- package/dist/esm/library.js.map +1 -1
- package/dist/index.d.ts +156 -12
- package/docs/README.md +264 -0
- package/docs/components/atoms/ActionImage.md +119 -0
- package/docs/components/atoms/Button.md +197 -0
- package/docs/components/atoms/Checkbox.md +299 -0
- package/docs/components/atoms/CheckboxItem.md +314 -0
- package/docs/components/atoms/Chip.md +380 -0
- package/docs/components/atoms/CustomToggle.md +270 -0
- package/docs/components/atoms/Icon.md +365 -0
- package/docs/components/atoms/IconButton.md +407 -0
- package/docs/components/atoms/Image.md +448 -0
- package/docs/components/atoms/Input.md +430 -0
- package/docs/components/atoms/ListItem.md +502 -0
- package/docs/components/atoms/Password.md +472 -0
- package/docs/components/atoms/RadioButton.md +614 -0
- package/docs/components/atoms/RadioButtonItem.md +588 -0
- package/docs/components/atoms/ResponsiveComponent.md +612 -0
- package/docs/components/atoms/SelectListItem.md +609 -0
- package/docs/components/atoms/Slider.md +605 -0
- package/docs/components/atoms/Spinner.md +605 -0
- package/docs/components/atoms/Text.md +463 -0
- package/docs/components/atoms/TextArea.md +670 -0
- package/docs/components/atoms/ToastNotification.md +668 -0
- package/docs/components/atoms/Toggle.md +737 -0
- package/docs/components/atoms/ToggleButton.md +751 -0
- package/docs/components/atoms/Tooltip.md +391 -0
- package/docs/components/molecules/Accordion.md +440 -0
- package/docs/components/molecules/AccordionGroup.md +547 -0
- package/docs/components/molecules/ActionCard.md +546 -0
- package/docs/components/molecules/Breadcrumb.md +403 -0
- package/docs/components/molecules/Breadcrumbs.md +485 -0
- package/docs/components/molecules/ButtonGroup.md +383 -0
- package/docs/components/molecules/Card.md +298 -0
- package/docs/components/molecules/ChipInput.md +646 -0
- package/docs/components/molecules/ContextMenu.md +768 -0
- package/docs/components/molecules/CustomTimeSelector.md +116 -0
- package/docs/components/molecules/DatePicker.md +516 -0
- package/docs/components/molecules/DateTimeSelector.md +166 -0
- package/docs/components/molecules/FormField.md +312 -0
- package/docs/components/molecules/Grid.md +577 -0
- package/docs/components/molecules/GridItem.md +834 -0
- package/docs/components/molecules/GridList.md +244 -0
- package/docs/components/molecules/List.md +485 -0
- package/docs/components/molecules/Modal.md +470 -0
- package/docs/components/molecules/ModalFooter.md +702 -0
- package/docs/components/molecules/ModalHeader.md +756 -0
- package/docs/components/molecules/ModalProvider.md +205 -0
- package/docs/components/molecules/Nav.md +530 -0
- package/docs/components/molecules/NavItem.md +572 -0
- package/docs/components/molecules/NavLink.md +499 -0
- package/docs/components/molecules/Option.md +521 -0
- package/docs/components/molecules/Pagination.md +592 -0
- package/docs/components/molecules/PaginationNumberField.md +722 -0
- package/docs/components/molecules/Popover.md +516 -0
- package/docs/components/molecules/ProgressBar.md +624 -0
- package/docs/components/molecules/RadioGroup.md +831 -0
- package/docs/components/molecules/RepeaterList.md +185 -0
- package/docs/components/molecules/Select.md +402 -0
- package/docs/components/molecules/SortableTrigger.md +82 -0
- package/docs/components/molecules/useModal.md +379 -0
- package/docs/components/organisms/Dropzone.md +346 -0
- package/docs/components/organisms/DropzoneClear.md +135 -0
- package/docs/components/organisms/DropzoneContent.md +216 -0
- package/docs/components/organisms/DropzoneFilename.md +191 -0
- package/docs/components/organisms/DropzoneSupportedFormats.md +184 -0
- package/docs/components/organisms/DropzoneTrigger.md +209 -0
- package/docs/components/organisms/Form.md +533 -0
- package/docs/components/organisms/SlideOutPanel.md +662 -0
- package/docs/components/organisms/TabContent.md +902 -0
- package/docs/components/organisms/TabItem.md +1091 -0
- package/docs/components/organisms/Table.md +611 -0
- package/docs/components/organisms/TableBody.md +679 -0
- package/docs/components/organisms/TableCell.md +482 -0
- package/docs/components/organisms/TableHeader.md +513 -0
- package/docs/components/organisms/TableHeaderCell.md +661 -0
- package/docs/components/organisms/TableRow.md +715 -0
- package/docs/components/organisms/Tabs.md +1330 -0
- package/docs/components/utils/ConditionalView.md +568 -0
- package/docs/components/utils/RenderStateView.md +726 -0
- package/docs/components/utils/WrapTextNodes.md +614 -0
- 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
|
+
```
|