@app-studio/web 0.9.31 → 0.9.32
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/docs/components/Accordion.mdx +158 -0
- package/docs/components/Alert.mdx +123 -0
- package/docs/components/AspectRatio.mdx +55 -0
- package/docs/components/Avatar.mdx +85 -0
- package/docs/components/Background.mdx +522 -0
- package/docs/components/Badge.mdx +220 -0
- package/docs/components/Button.mdx +272 -0
- package/docs/components/Calendar.mdx +274 -0
- package/docs/components/Card.mdx +341 -0
- package/docs/components/Carousel.mdx +411 -0
- package/docs/components/Center.mdx +474 -0
- package/docs/components/Chart.mdx +232 -0
- package/docs/components/ChatInput.mdx +373 -0
- package/docs/components/Checkbox.mdx +66 -0
- package/docs/components/ColorInput.mdx +209 -0
- package/docs/components/ComboBox.mdx +364 -0
- package/docs/components/Command.mdx +252 -0
- package/docs/components/ContextMenu.mdx +219 -0
- package/docs/components/CountryPicker.mdx +123 -0
- package/docs/components/DatePicker.mdx +77 -0
- package/docs/components/DragAndDrop.mdx +539 -0
- package/docs/components/DropdownMenu.mdx +205 -0
- package/docs/components/File.mdx +8 -0
- package/docs/components/Flow.mdx +257 -0
- package/docs/components/Form.mdx +681 -0
- package/docs/components/Formik.mdx +621 -0
- package/docs/components/Gradient.mdx +271 -0
- package/docs/components/Horizontal.mdx +40 -0
- package/docs/components/HoverCard.mdx +140 -0
- package/docs/components/Icon.mdx +438 -0
- package/docs/components/Label.mdx +438 -0
- package/docs/components/Link.mdx +83 -0
- package/docs/components/Loader.mdx +527 -0
- package/docs/components/Menubar.mdx +124 -0
- package/docs/components/Message.mdx +571 -0
- package/docs/components/Modal.mdx +533 -0
- package/docs/components/NavigationMenu.mdx +165 -0
- package/docs/components/Pagination.mdx +150 -0
- package/docs/components/Password.mdx +121 -0
- package/docs/components/Resizable.mdx +148 -0
- package/docs/components/Select.mdx +126 -0
- package/docs/components/Separator.mdx +121 -0
- package/docs/components/Sidebar.mdx +147 -0
- package/docs/components/Slider.mdx +232 -0
- package/docs/components/Switch.mdx +62 -0
- package/docs/components/Table.mdx +409 -0
- package/docs/components/Tabs.mdx +215 -0
- package/docs/components/TagInput.mdx +528 -0
- package/docs/components/Text.mdx +163 -0
- package/docs/components/TextArea.mdx +136 -0
- package/docs/components/TextField.mdx +225 -0
- package/docs/components/Title.mdx +535 -0
- package/docs/components/Toast.mdx +165 -0
- package/docs/components/Toggle.mdx +141 -0
- package/docs/components/ToggleGroup.mdx +165 -0
- package/docs/components/Tooltip.mdx +191 -0
- package/docs/components/Tree.mdx +340 -0
- package/docs/components/Uploader.mdx +426 -0
- package/docs/components/Vertical.mdx +566 -0
- package/package.json +1 -1
|
@@ -0,0 +1,681 @@
|
|
|
1
|
+
# Form
|
|
2
|
+
|
|
3
|
+
A comprehensive form system with Formik integration, providing powerful form state management, validation, and a complete set of form components. Includes support for complex forms, real-time validation, and seamless user experience.
|
|
4
|
+
|
|
5
|
+
### **Import**
|
|
6
|
+
```tsx
|
|
7
|
+
// Form components
|
|
8
|
+
import {
|
|
9
|
+
FormikForm,
|
|
10
|
+
FormikTextField,
|
|
11
|
+
FormikTextArea,
|
|
12
|
+
FormikCheckbox,
|
|
13
|
+
FormikSwitch,
|
|
14
|
+
FormikSelect,
|
|
15
|
+
FormikDatePicker,
|
|
16
|
+
FormikCountryPicker,
|
|
17
|
+
FormikColorInput,
|
|
18
|
+
FormikPassword,
|
|
19
|
+
FormikComboBox,
|
|
20
|
+
FormikSlider,
|
|
21
|
+
FormikChatInput,
|
|
22
|
+
FormikTagInput
|
|
23
|
+
} from '@app-studio/web';
|
|
24
|
+
|
|
25
|
+
// Individual form components
|
|
26
|
+
import {
|
|
27
|
+
TextField,
|
|
28
|
+
TextArea,
|
|
29
|
+
Checkbox,
|
|
30
|
+
Switch,
|
|
31
|
+
Select,
|
|
32
|
+
DatePicker,
|
|
33
|
+
CountryPicker,
|
|
34
|
+
ColorInput,
|
|
35
|
+
Password,
|
|
36
|
+
ComboBox,
|
|
37
|
+
Slider,
|
|
38
|
+
Label
|
|
39
|
+
} from '@app-studio/web';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### **Basic Form with Formik**
|
|
43
|
+
```tsx
|
|
44
|
+
import React from 'react';
|
|
45
|
+
import { Formik } from 'formik';
|
|
46
|
+
import * as Yup from 'yup';
|
|
47
|
+
import { FormikForm, FormikTextField, FormikCheckbox } from '@app-studio/web';
|
|
48
|
+
import { Button } from '@app-studio/web';
|
|
49
|
+
import { Vertical } from 'app-studio';
|
|
50
|
+
|
|
51
|
+
export const BasicForm = () => {
|
|
52
|
+
const initialValues = {
|
|
53
|
+
firstName: '',
|
|
54
|
+
lastName: '',
|
|
55
|
+
email: '',
|
|
56
|
+
agreeToTerms: false,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const validationSchema = Yup.object().shape({
|
|
60
|
+
firstName: Yup.string().required('First name is required'),
|
|
61
|
+
lastName: Yup.string().required('Last name is required'),
|
|
62
|
+
email: Yup.string().email('Invalid email').required('Email is required'),
|
|
63
|
+
agreeToTerms: Yup.boolean().oneOf([true], 'You must agree to the terms'),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const handleSubmit = (values: any, { setSubmitting }: any) => {
|
|
67
|
+
console.log('Form values:', values);
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
alert(JSON.stringify(values, null, 2));
|
|
70
|
+
setSubmitting(false);
|
|
71
|
+
}, 1000);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Formik
|
|
76
|
+
initialValues={initialValues}
|
|
77
|
+
validationSchema={validationSchema}
|
|
78
|
+
onSubmit={handleSubmit}
|
|
79
|
+
>
|
|
80
|
+
{({ handleSubmit, isSubmitting }) => (
|
|
81
|
+
<FormikForm>
|
|
82
|
+
<Vertical gap={16} width="100%" maxWidth={400}>
|
|
83
|
+
<FormikTextField
|
|
84
|
+
name="firstName"
|
|
85
|
+
label="First Name"
|
|
86
|
+
placeholder="Enter your first name"
|
|
87
|
+
/>
|
|
88
|
+
<FormikTextField
|
|
89
|
+
name="lastName"
|
|
90
|
+
label="Last Name"
|
|
91
|
+
placeholder="Enter your last name"
|
|
92
|
+
/>
|
|
93
|
+
<FormikTextField
|
|
94
|
+
name="email"
|
|
95
|
+
label="Email"
|
|
96
|
+
placeholder="Enter your email"
|
|
97
|
+
type="email"
|
|
98
|
+
/>
|
|
99
|
+
<FormikCheckbox
|
|
100
|
+
name="agreeToTerms"
|
|
101
|
+
label="I agree to the terms and conditions"
|
|
102
|
+
/>
|
|
103
|
+
<Button
|
|
104
|
+
type="submit"
|
|
105
|
+
onClick={handleSubmit}
|
|
106
|
+
isLoading={isSubmitting}
|
|
107
|
+
disabled={isSubmitting}
|
|
108
|
+
>
|
|
109
|
+
Submit
|
|
110
|
+
</Button>
|
|
111
|
+
</Vertical>
|
|
112
|
+
</FormikForm>
|
|
113
|
+
)}
|
|
114
|
+
</Formik>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### **Advanced Form with Multiple Field Types**
|
|
120
|
+
```tsx
|
|
121
|
+
import React from 'react';
|
|
122
|
+
import { Formik } from 'formik';
|
|
123
|
+
import * as Yup from 'yup';
|
|
124
|
+
import {
|
|
125
|
+
FormikForm,
|
|
126
|
+
FormikTextField,
|
|
127
|
+
FormikTextArea,
|
|
128
|
+
FormikSelect,
|
|
129
|
+
FormikDatePicker,
|
|
130
|
+
FormikCountryPicker,
|
|
131
|
+
FormikColorInput,
|
|
132
|
+
FormikSlider,
|
|
133
|
+
FormikSwitch,
|
|
134
|
+
FormikTagInput
|
|
135
|
+
} from '@app-studio/web';
|
|
136
|
+
import { Button } from '@app-studio/web';
|
|
137
|
+
import { Vertical } from 'app-studio';
|
|
138
|
+
|
|
139
|
+
export const AdvancedForm = () => {
|
|
140
|
+
const initialValues = {
|
|
141
|
+
title: '',
|
|
142
|
+
description: '',
|
|
143
|
+
category: '',
|
|
144
|
+
publishDate: null,
|
|
145
|
+
country: '',
|
|
146
|
+
themeColor: '#3B82F6',
|
|
147
|
+
priority: 5,
|
|
148
|
+
isPublished: false,
|
|
149
|
+
tags: ['react', 'typescript'],
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const validationSchema = Yup.object().shape({
|
|
153
|
+
title: Yup.string().required('Title is required'),
|
|
154
|
+
description: Yup.string().min(10, 'Description must be at least 10 characters'),
|
|
155
|
+
category: Yup.string().required('Category is required'),
|
|
156
|
+
publishDate: Yup.date().required('Publish date is required'),
|
|
157
|
+
country: Yup.string().required('Country is required'),
|
|
158
|
+
priority: Yup.number().min(1).max(10),
|
|
159
|
+
tags: Yup.array().min(1, 'At least one tag is required'),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const categoryOptions = [
|
|
163
|
+
{ label: 'Technology', value: 'tech' },
|
|
164
|
+
{ label: 'Design', value: 'design' },
|
|
165
|
+
{ label: 'Business', value: 'business' },
|
|
166
|
+
{ label: 'Marketing', value: 'marketing' },
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const handleSubmit = (values: any) => {
|
|
170
|
+
console.log('Advanced form values:', values);
|
|
171
|
+
alert(JSON.stringify(values, null, 2));
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<Formik
|
|
176
|
+
initialValues={initialValues}
|
|
177
|
+
validationSchema={validationSchema}
|
|
178
|
+
onSubmit={handleSubmit}
|
|
179
|
+
>
|
|
180
|
+
{({ handleSubmit }) => (
|
|
181
|
+
<FormikForm>
|
|
182
|
+
<Vertical gap={20} width="100%" maxWidth={500}>
|
|
183
|
+
<FormikTextField
|
|
184
|
+
name="title"
|
|
185
|
+
label="Title"
|
|
186
|
+
placeholder="Enter article title"
|
|
187
|
+
/>
|
|
188
|
+
|
|
189
|
+
<FormikTextArea
|
|
190
|
+
name="description"
|
|
191
|
+
label="Description"
|
|
192
|
+
placeholder="Enter article description"
|
|
193
|
+
maxRows={4}
|
|
194
|
+
/>
|
|
195
|
+
|
|
196
|
+
<FormikSelect
|
|
197
|
+
name="category"
|
|
198
|
+
label="Category"
|
|
199
|
+
placeholder="Select a category"
|
|
200
|
+
options={categoryOptions}
|
|
201
|
+
/>
|
|
202
|
+
|
|
203
|
+
<FormikDatePicker
|
|
204
|
+
name="publishDate"
|
|
205
|
+
label="Publish Date"
|
|
206
|
+
placeholder="Select publish date"
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
<FormikCountryPicker
|
|
210
|
+
name="country"
|
|
211
|
+
label="Target Country"
|
|
212
|
+
placeholder="Select target country"
|
|
213
|
+
/>
|
|
214
|
+
|
|
215
|
+
<FormikColorInput
|
|
216
|
+
name="themeColor"
|
|
217
|
+
label="Theme Color"
|
|
218
|
+
/>
|
|
219
|
+
|
|
220
|
+
<FormikSlider
|
|
221
|
+
name="priority"
|
|
222
|
+
label="Priority (1-10)"
|
|
223
|
+
min={1}
|
|
224
|
+
max={10}
|
|
225
|
+
step={1}
|
|
226
|
+
/>
|
|
227
|
+
|
|
228
|
+
<FormikTagInput
|
|
229
|
+
name="tags"
|
|
230
|
+
label="Tags"
|
|
231
|
+
placeholder="Add tags..."
|
|
232
|
+
/>
|
|
233
|
+
|
|
234
|
+
<FormikSwitch
|
|
235
|
+
name="isPublished"
|
|
236
|
+
label="Publish immediately"
|
|
237
|
+
/>
|
|
238
|
+
|
|
239
|
+
<Button type="submit" onClick={handleSubmit}>
|
|
240
|
+
Create Article
|
|
241
|
+
</Button>
|
|
242
|
+
</Vertical>
|
|
243
|
+
</FormikForm>
|
|
244
|
+
)}
|
|
245
|
+
</Formik>
|
|
246
|
+
);
|
|
247
|
+
};
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### **Form Validation Examples**
|
|
251
|
+
```tsx
|
|
252
|
+
import React from 'react';
|
|
253
|
+
import { Formik } from 'formik';
|
|
254
|
+
import * as Yup from 'yup';
|
|
255
|
+
import { FormikForm, FormikTextField, FormikPassword } from '@app-studio/web';
|
|
256
|
+
import { Button } from '@app-studio/web';
|
|
257
|
+
import { Vertical } from 'app-studio';
|
|
258
|
+
|
|
259
|
+
export const ValidationForm = () => {
|
|
260
|
+
const initialValues = {
|
|
261
|
+
username: '',
|
|
262
|
+
email: '',
|
|
263
|
+
password: '',
|
|
264
|
+
confirmPassword: '',
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const validationSchema = Yup.object().shape({
|
|
268
|
+
username: Yup.string()
|
|
269
|
+
.min(3, 'Username must be at least 3 characters')
|
|
270
|
+
.max(20, 'Username must be less than 20 characters')
|
|
271
|
+
.matches(/^[a-zA-Z0-9_]+$/, 'Username can only contain letters, numbers, and underscores')
|
|
272
|
+
.required('Username is required'),
|
|
273
|
+
email: Yup.string()
|
|
274
|
+
.email('Invalid email format')
|
|
275
|
+
.required('Email is required'),
|
|
276
|
+
password: Yup.string()
|
|
277
|
+
.min(8, 'Password must be at least 8 characters')
|
|
278
|
+
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain uppercase, lowercase, and number')
|
|
279
|
+
.required('Password is required'),
|
|
280
|
+
confirmPassword: Yup.string()
|
|
281
|
+
.oneOf([Yup.ref('password')], 'Passwords must match')
|
|
282
|
+
.required('Please confirm your password'),
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
const handleSubmit = (values: any) => {
|
|
286
|
+
console.log('Registration values:', values);
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
return (
|
|
290
|
+
<Formik
|
|
291
|
+
initialValues={initialValues}
|
|
292
|
+
validationSchema={validationSchema}
|
|
293
|
+
onSubmit={handleSubmit}
|
|
294
|
+
>
|
|
295
|
+
{({ handleSubmit, errors, touched }) => (
|
|
296
|
+
<FormikForm>
|
|
297
|
+
<Vertical gap={16} width="100%" maxWidth={400}>
|
|
298
|
+
<FormikTextField
|
|
299
|
+
name="username"
|
|
300
|
+
label="Username"
|
|
301
|
+
placeholder="Enter username"
|
|
302
|
+
error={touched.username && errors.username}
|
|
303
|
+
/>
|
|
304
|
+
|
|
305
|
+
<FormikTextField
|
|
306
|
+
name="email"
|
|
307
|
+
label="Email"
|
|
308
|
+
type="email"
|
|
309
|
+
placeholder="Enter email"
|
|
310
|
+
error={touched.email && errors.email}
|
|
311
|
+
/>
|
|
312
|
+
|
|
313
|
+
<FormikPassword
|
|
314
|
+
name="password"
|
|
315
|
+
label="Password"
|
|
316
|
+
placeholder="Enter password"
|
|
317
|
+
error={touched.password && errors.password}
|
|
318
|
+
/>
|
|
319
|
+
|
|
320
|
+
<FormikPassword
|
|
321
|
+
name="confirmPassword"
|
|
322
|
+
label="Confirm Password"
|
|
323
|
+
placeholder="Confirm password"
|
|
324
|
+
error={touched.confirmPassword && errors.confirmPassword}
|
|
325
|
+
/>
|
|
326
|
+
|
|
327
|
+
<Button type="submit" onClick={handleSubmit}>
|
|
328
|
+
Register
|
|
329
|
+
</Button>
|
|
330
|
+
</Vertical>
|
|
331
|
+
</FormikForm>
|
|
332
|
+
)}
|
|
333
|
+
</Formik>
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### **Dynamic Form Fields**
|
|
339
|
+
```tsx
|
|
340
|
+
import React from 'react';
|
|
341
|
+
import { Formik, FieldArray } from 'formik';
|
|
342
|
+
import * as Yup from 'yup';
|
|
343
|
+
import { FormikForm, FormikTextField } from '@app-studio/web';
|
|
344
|
+
import { Button } from '@app-studio/web';
|
|
345
|
+
import { Vertical, Horizontal } from 'app-studio';
|
|
346
|
+
import { PlusIcon, MinusIcon } from '@app-studio/web';
|
|
347
|
+
|
|
348
|
+
export const DynamicForm = () => {
|
|
349
|
+
const initialValues = {
|
|
350
|
+
projectName: '',
|
|
351
|
+
tasks: [{ name: '', description: '' }],
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const validationSchema = Yup.object().shape({
|
|
355
|
+
projectName: Yup.string().required('Project name is required'),
|
|
356
|
+
tasks: Yup.array().of(
|
|
357
|
+
Yup.object().shape({
|
|
358
|
+
name: Yup.string().required('Task name is required'),
|
|
359
|
+
description: Yup.string().required('Task description is required'),
|
|
360
|
+
})
|
|
361
|
+
).min(1, 'At least one task is required'),
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const handleSubmit = (values: any) => {
|
|
365
|
+
console.log('Project values:', values);
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
return (
|
|
369
|
+
<Formik
|
|
370
|
+
initialValues={initialValues}
|
|
371
|
+
validationSchema={validationSchema}
|
|
372
|
+
onSubmit={handleSubmit}
|
|
373
|
+
>
|
|
374
|
+
{({ handleSubmit, values }) => (
|
|
375
|
+
<FormikForm>
|
|
376
|
+
<Vertical gap={20} width="100%" maxWidth={600}>
|
|
377
|
+
<FormikTextField
|
|
378
|
+
name="projectName"
|
|
379
|
+
label="Project Name"
|
|
380
|
+
placeholder="Enter project name"
|
|
381
|
+
/>
|
|
382
|
+
|
|
383
|
+
<FieldArray name="tasks">
|
|
384
|
+
{({ push, remove }) => (
|
|
385
|
+
<Vertical gap={16}>
|
|
386
|
+
<Horizontal justifyContent="space-between" alignItems="center">
|
|
387
|
+
<h3>Tasks</h3>
|
|
388
|
+
<Button
|
|
389
|
+
type="button"
|
|
390
|
+
icon={<PlusIcon widthHeight={16} />}
|
|
391
|
+
onClick={() => push({ name: '', description: '' })}
|
|
392
|
+
variant="outline"
|
|
393
|
+
size="sm"
|
|
394
|
+
>
|
|
395
|
+
Add Task
|
|
396
|
+
</Button>
|
|
397
|
+
</Horizontal>
|
|
398
|
+
|
|
399
|
+
{values.tasks.map((task, index) => (
|
|
400
|
+
<Vertical
|
|
401
|
+
key={index}
|
|
402
|
+
gap={12}
|
|
403
|
+
padding={16}
|
|
404
|
+
border="1px solid"
|
|
405
|
+
borderColor="color.gray.200"
|
|
406
|
+
borderRadius={8}
|
|
407
|
+
>
|
|
408
|
+
<Horizontal justifyContent="space-between" alignItems="center">
|
|
409
|
+
<h4>Task {index + 1}</h4>
|
|
410
|
+
{values.tasks.length > 1 && (
|
|
411
|
+
<Button
|
|
412
|
+
type="button"
|
|
413
|
+
icon={<MinusIcon widthHeight={16} />}
|
|
414
|
+
onClick={() => remove(index)}
|
|
415
|
+
variant="ghost"
|
|
416
|
+
size="sm"
|
|
417
|
+
colorScheme="theme.error"
|
|
418
|
+
>
|
|
419
|
+
Remove
|
|
420
|
+
</Button>
|
|
421
|
+
)}
|
|
422
|
+
</Horizontal>
|
|
423
|
+
|
|
424
|
+
<FormikTextField
|
|
425
|
+
name={`tasks.${index}.name`}
|
|
426
|
+
label="Task Name"
|
|
427
|
+
placeholder="Enter task name"
|
|
428
|
+
/>
|
|
429
|
+
|
|
430
|
+
<FormikTextField
|
|
431
|
+
name={`tasks.${index}.description`}
|
|
432
|
+
label="Task Description"
|
|
433
|
+
placeholder="Enter task description"
|
|
434
|
+
/>
|
|
435
|
+
</Vertical>
|
|
436
|
+
))}
|
|
437
|
+
</Vertical>
|
|
438
|
+
)}
|
|
439
|
+
</FieldArray>
|
|
440
|
+
|
|
441
|
+
<Button type="submit" onClick={handleSubmit}>
|
|
442
|
+
Create Project
|
|
443
|
+
</Button>
|
|
444
|
+
</Vertical>
|
|
445
|
+
</FormikForm>
|
|
446
|
+
)}
|
|
447
|
+
</Formik>
|
|
448
|
+
);
|
|
449
|
+
};
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### **Form Components**
|
|
453
|
+
|
|
454
|
+
**FormikForm**
|
|
455
|
+
- Main form wrapper with Formik integration
|
|
456
|
+
- Provides form context and state management
|
|
457
|
+
- Supports auto-focus and form navigation
|
|
458
|
+
|
|
459
|
+
**FormikTextField**
|
|
460
|
+
- Single-line text input with validation
|
|
461
|
+
- Supports various input types (text, email, password, etc.)
|
|
462
|
+
- Built-in error display and styling
|
|
463
|
+
|
|
464
|
+
**FormikTextArea**
|
|
465
|
+
- Multi-line text input
|
|
466
|
+
- Configurable rows and columns
|
|
467
|
+
- Auto-resize functionality
|
|
468
|
+
|
|
469
|
+
**FormikCheckbox**
|
|
470
|
+
- Boolean input for yes/no choices
|
|
471
|
+
- Custom styling and label positioning
|
|
472
|
+
- Indeterminate state support
|
|
473
|
+
|
|
474
|
+
**FormikSwitch**
|
|
475
|
+
- Toggle switch for boolean values
|
|
476
|
+
- Smooth animations and transitions
|
|
477
|
+
- Customizable colors and sizes
|
|
478
|
+
|
|
479
|
+
**FormikSelect**
|
|
480
|
+
- Dropdown selection component
|
|
481
|
+
- Single and multi-select support
|
|
482
|
+
- Search and filter capabilities
|
|
483
|
+
|
|
484
|
+
**FormikDatePicker**
|
|
485
|
+
- Date selection with calendar popup
|
|
486
|
+
- Date range selection
|
|
487
|
+
- Customizable date formats
|
|
488
|
+
|
|
489
|
+
**FormikCountryPicker**
|
|
490
|
+
- Country selection with flags
|
|
491
|
+
- Search functionality
|
|
492
|
+
- Localized country names
|
|
493
|
+
|
|
494
|
+
**FormikColorInput**
|
|
495
|
+
- Color picker with preview
|
|
496
|
+
- Hex, RGB, and HSL support
|
|
497
|
+
- Predefined color palettes
|
|
498
|
+
|
|
499
|
+
**FormikPassword**
|
|
500
|
+
- Password input with visibility toggle
|
|
501
|
+
- Strength indicator
|
|
502
|
+
- Custom validation rules
|
|
503
|
+
|
|
504
|
+
**FormikComboBox**
|
|
505
|
+
- Searchable dropdown with custom options
|
|
506
|
+
- Multi-select capabilities
|
|
507
|
+
- Tag-style selection display
|
|
508
|
+
|
|
509
|
+
**FormikSlider**
|
|
510
|
+
- Range input with visual feedback
|
|
511
|
+
- Step configuration
|
|
512
|
+
- Min/max value constraints
|
|
513
|
+
|
|
514
|
+
**FormikTagInput**
|
|
515
|
+
- Tag-based input for multiple values
|
|
516
|
+
- Auto-completion support
|
|
517
|
+
- Custom tag validation
|
|
518
|
+
|
|
519
|
+
### **Props Reference**
|
|
520
|
+
|
|
521
|
+
**Common Formik Props (inherited by all Formik components):**
|
|
522
|
+
|
|
523
|
+
| Prop | Type | Description |
|
|
524
|
+
| ---- | ---- | ----------- |
|
|
525
|
+
| name | string | Field name for Formik state management |
|
|
526
|
+
| label | string | Field label text |
|
|
527
|
+
| placeholder | string | Placeholder text |
|
|
528
|
+
| error | string \| boolean | Error message or error state |
|
|
529
|
+
| disabled | boolean | Whether the field is disabled |
|
|
530
|
+
| required | boolean | Whether the field is required |
|
|
531
|
+
|
|
532
|
+
**FormikForm Props:**
|
|
533
|
+
|
|
534
|
+
| Prop | Type | Default | Description |
|
|
535
|
+
| ---- | ---- | ------- | ----------- |
|
|
536
|
+
| autoFocus | boolean | false | Auto-focus first field |
|
|
537
|
+
| initFocus | string | undefined | Specific field to focus initially |
|
|
538
|
+
| onChange | function | undefined | Callback when form values change |
|
|
539
|
+
|
|
540
|
+
### **Validation Patterns**
|
|
541
|
+
|
|
542
|
+
**Email Validation:**
|
|
543
|
+
```tsx
|
|
544
|
+
email: Yup.string()
|
|
545
|
+
.email('Invalid email format')
|
|
546
|
+
.required('Email is required')
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
**Password Validation:**
|
|
550
|
+
```tsx
|
|
551
|
+
password: Yup.string()
|
|
552
|
+
.min(8, 'Password must be at least 8 characters')
|
|
553
|
+
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain uppercase, lowercase, and number')
|
|
554
|
+
.required('Password is required')
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Phone Number Validation:**
|
|
558
|
+
```tsx
|
|
559
|
+
phone: Yup.string()
|
|
560
|
+
.matches(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number')
|
|
561
|
+
.required('Phone number is required')
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**URL Validation:**
|
|
565
|
+
```tsx
|
|
566
|
+
website: Yup.string()
|
|
567
|
+
.url('Invalid URL format')
|
|
568
|
+
.required('Website URL is required')
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### **Form State Management**
|
|
572
|
+
|
|
573
|
+
**Accessing Form State:**
|
|
574
|
+
```tsx
|
|
575
|
+
import { useFormikContext } from 'formik';
|
|
576
|
+
|
|
577
|
+
const FormStatus = () => {
|
|
578
|
+
const { values, errors, touched, isSubmitting, isValid } = useFormikContext();
|
|
579
|
+
|
|
580
|
+
return (
|
|
581
|
+
<div>
|
|
582
|
+
<p>Form Valid: {isValid ? 'Yes' : 'No'}</p>
|
|
583
|
+
<p>Submitting: {isSubmitting ? 'Yes' : 'No'}</p>
|
|
584
|
+
<p>Values: {JSON.stringify(values)}</p>
|
|
585
|
+
</div>
|
|
586
|
+
);
|
|
587
|
+
};
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**Custom Field Component:**
|
|
591
|
+
```tsx
|
|
592
|
+
import { useFormikInput } from '@app-studio/web';
|
|
593
|
+
|
|
594
|
+
const CustomFormikField = (props) => {
|
|
595
|
+
const formProps = useFormikInput(props);
|
|
596
|
+
|
|
597
|
+
return (
|
|
598
|
+
<input
|
|
599
|
+
{...formProps}
|
|
600
|
+
style={{
|
|
601
|
+
border: formProps.error ? '1px solid red' : '1px solid gray',
|
|
602
|
+
}}
|
|
603
|
+
/>
|
|
604
|
+
);
|
|
605
|
+
};
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### **Best Practices**
|
|
609
|
+
|
|
610
|
+
**Form Structure:**
|
|
611
|
+
- Use semantic HTML structure
|
|
612
|
+
- Group related fields logically
|
|
613
|
+
- Provide clear labels and instructions
|
|
614
|
+
- Use appropriate field types for data
|
|
615
|
+
|
|
616
|
+
**Validation:**
|
|
617
|
+
- Validate on both client and server side
|
|
618
|
+
- Provide real-time feedback
|
|
619
|
+
- Use clear, actionable error messages
|
|
620
|
+
- Validate on blur for better UX
|
|
621
|
+
|
|
622
|
+
**Accessibility:**
|
|
623
|
+
- Use proper labels and ARIA attributes
|
|
624
|
+
- Ensure keyboard navigation works
|
|
625
|
+
- Provide error announcements
|
|
626
|
+
- Maintain focus management
|
|
627
|
+
|
|
628
|
+
**Performance:**
|
|
629
|
+
- Use field-level validation for complex forms
|
|
630
|
+
- Debounce validation for expensive operations
|
|
631
|
+
- Minimize re-renders with proper state management
|
|
632
|
+
- Use lazy validation when appropriate
|
|
633
|
+
|
|
634
|
+
### **Integration Examples**
|
|
635
|
+
|
|
636
|
+
**With API Calls:**
|
|
637
|
+
```tsx
|
|
638
|
+
const handleSubmit = async (values, { setSubmitting, setFieldError }) => {
|
|
639
|
+
try {
|
|
640
|
+
setSubmitting(true);
|
|
641
|
+
const response = await api.createUser(values);
|
|
642
|
+
console.log('User created:', response);
|
|
643
|
+
// Handle success
|
|
644
|
+
} catch (error) {
|
|
645
|
+
if (error.field) {
|
|
646
|
+
setFieldError(error.field, error.message);
|
|
647
|
+
}
|
|
648
|
+
// Handle error
|
|
649
|
+
} finally {
|
|
650
|
+
setSubmitting(false);
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
**With File Uploads:**
|
|
656
|
+
```tsx
|
|
657
|
+
import { FormikForm, FormikTextField } from '@app-studio/web';
|
|
658
|
+
import { Uploader } from '@app-studio/web';
|
|
659
|
+
|
|
660
|
+
const FormWithUpload = () => {
|
|
661
|
+
const [uploadedFile, setUploadedFile] = useState(null);
|
|
662
|
+
|
|
663
|
+
return (
|
|
664
|
+
<Formik
|
|
665
|
+
initialValues={{ name: '', file: null }}
|
|
666
|
+
onSubmit={(values) => {
|
|
667
|
+
const formData = new FormData();
|
|
668
|
+
formData.append('name', values.name);
|
|
669
|
+
formData.append('file', uploadedFile);
|
|
670
|
+
// Submit form data
|
|
671
|
+
}}
|
|
672
|
+
>
|
|
673
|
+
<FormikForm>
|
|
674
|
+
<FormikTextField name="name" label="Name" />
|
|
675
|
+
<Uploader onFileSelect={setUploadedFile} />
|
|
676
|
+
<Button type="submit">Submit</Button>
|
|
677
|
+
</FormikForm>
|
|
678
|
+
</Formik>
|
|
679
|
+
);
|
|
680
|
+
};
|
|
681
|
+
```
|