@sio-group/form-react 0.1.0

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 (45) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +783 -0
  3. package/ROADMAP.md +21 -0
  4. package/dist/index.cjs +1919 -0
  5. package/dist/index.d.cts +284 -0
  6. package/dist/index.d.ts +284 -0
  7. package/dist/index.js +1878 -0
  8. package/dist/styles/components/button.css +244 -0
  9. package/dist/styles/components/button.css.map +1 -0
  10. package/dist/styles/components/checkbox.css +90 -0
  11. package/dist/styles/components/checkbox.css.map +1 -0
  12. package/dist/styles/components/color.css +31 -0
  13. package/dist/styles/components/color.css.map +1 -0
  14. package/dist/styles/components/form-field.css +36 -0
  15. package/dist/styles/components/form-field.css.map +1 -0
  16. package/dist/styles/components/form-states.css +80 -0
  17. package/dist/styles/components/form-states.css.map +1 -0
  18. package/dist/styles/components/grid.css +818 -0
  19. package/dist/styles/components/grid.css.map +1 -0
  20. package/dist/styles/components/input.css +112 -0
  21. package/dist/styles/components/input.css.map +1 -0
  22. package/dist/styles/components/link.css +113 -0
  23. package/dist/styles/components/link.css.map +1 -0
  24. package/dist/styles/components/radio.css +104 -0
  25. package/dist/styles/components/radio.css.map +1 -0
  26. package/dist/styles/components/range.css +54 -0
  27. package/dist/styles/components/range.css.map +1 -0
  28. package/dist/styles/components/select.css +37 -0
  29. package/dist/styles/components/select.css.map +1 -0
  30. package/dist/styles/components/upload.css +54 -0
  31. package/dist/styles/components/upload.css.map +1 -0
  32. package/dist/styles/index.css +1733 -0
  33. package/dist/styles/index.css.map +1 -0
  34. package/package.json +42 -0
  35. package/screenshots/contact-form.png +0 -0
  36. package/screenshots/file-input.png +0 -0
  37. package/screenshots/invalid-username.png +0 -0
  38. package/screenshots/number-field.png +0 -0
  39. package/screenshots/radio-field.png +0 -0
  40. package/screenshots/range-field.png +0 -0
  41. package/screenshots/registration-form.png +0 -0
  42. package/screenshots/select-field.png +0 -0
  43. package/screenshots/textarea-field.png +0 -0
  44. package/tsconfig.tsbuildinfo +1 -0
  45. package/tsup.config.ts +8 -0
package/README.md ADDED
@@ -0,0 +1,783 @@
1
+ # @sio-group/form-react
2
+
3
+ [![License: ISC](https://img.shields.io/badge/License-ISC-blue.svg)](https://opensource.org/licenses/ISC)
4
+ ![npm](https://img.shields.io/npm/v/@sio-group/form-react)
5
+ ![TypeScript](https://img.shields.io/badge/types-Yes-brightgreen)
6
+
7
+ <!--
8
+ [![npm version](https://img.shields.io/npm/v/@sio-group/form-validation.svg)](https://www.npmjs.com/package/@sio-group/form-validation)
9
+ [![npm downloads](https://img.shields.io/npm/dm/@sio-group/form-validation.svg)](https://www.npmjs.com/package/@sio-group/form-validation)
10
+ -->
11
+
12
+ A powerful, type-safe React form framework. This package provides ready-to-use form components with built-in validation, layout management, and extensive customization options. This package is designed to work seamlessly with `@sio-group/form-builder` and `@sio-group/form-validation`, but can be used independently.
13
+
14
+ Part of the SIO Form ecosystem, it consumes form definitions from `@sio-group/form-builder` and renders them with full type safety and accessibility in mind.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install @sio-group/form-react
22
+ ```
23
+
24
+ **Peer Dependencies:**
25
+ - `react`: ^18.0.0
26
+ - `react-dom`: ^18.0.0
27
+
28
+ ---
29
+
30
+ ## Quick Example
31
+
32
+ ```tsx
33
+ import { Form } from '@sio-group/form-react';
34
+ import { formBuilder } from '@sio-group/form-builder';
35
+
36
+ function ContactForm() {
37
+ const fields = formBuilder()
38
+ .addText('name', {
39
+ label: 'Full name',
40
+ required: true,
41
+ placeholder: 'John Doe'
42
+ })
43
+ .addEmail('email', {
44
+ label: 'Email address',
45
+ required: true,
46
+ placeholder: 'john@example.com'
47
+ })
48
+ .addTextarea('message', {
49
+ label: 'Message',
50
+ rows: 5,
51
+ placeholder: 'Your message...'
52
+ })
53
+ .getFields();
54
+
55
+ return (
56
+ <Form
57
+ fields={fields}
58
+ submitAction={(values) => console.log('Form submitted:', values)}
59
+ submitLabel="Send Message"
60
+ />
61
+ );
62
+ }
63
+ ```
64
+
65
+ ### Voorbeeld
66
+
67
+ ![Contact form](screenshots/contact-form.png)
68
+ *A simple contact form*
69
+
70
+ ---
71
+
72
+ ## Features
73
+
74
+ - ✅ **Type-safe** - Full TypeScript support with inferred types
75
+ - ✅ **Built-in validation** - Automatic validation based on field configuration
76
+ - ✅ **Responsive layout** - Grid system with breakpoints (sm, md, lg)
77
+ - ✅ **Customizable buttons** - Multiple button variants and colors
78
+ - ✅ **Form state management** - Tracks dirty, touched, focused, and error states
79
+ - ✅ **Accessibility** - ARIA attributes and keyboard navigation
80
+ - ✅ **Offline support** - Disable forms when offline
81
+ - ✅ **File uploads** - Built-in file handling with validation
82
+ - ✅ **Icons** - Support for HTML and component icons
83
+ - ✅ **Flexible containers** - Custom form and button containers
84
+
85
+ ---
86
+
87
+ ## Core Components
88
+
89
+ ### Form Component
90
+
91
+ The main component that renders your form with all fields and buttons.
92
+
93
+ ```tsx
94
+ import { Form } from '@sio-group/form-react';
95
+
96
+ <Form
97
+ fields={fields}
98
+ layout={layoutConfig}
99
+ submitShow={true}
100
+ submitAction={handleSubmit}
101
+ submitLabel="Save"
102
+ cancelShow={true}
103
+ cancelAction={handleCancel}
104
+ cancelLabel="Cancel"
105
+ buttons={buttonConfig}
106
+ extraValidation={customGlobalValidation}
107
+ className="my-form"
108
+ container={CustomContainer}
109
+ buttonContainer={CustomButtonContainer}
110
+ />
111
+ ```
112
+
113
+ ### Individual Field Components
114
+
115
+ You can also use field components independently:
116
+
117
+ ```tsx
118
+ import {
119
+ useForm,
120
+ Input,
121
+ Textarea,
122
+ Select,
123
+ Radio,
124
+ Checkbox,
125
+ NumberInput,
126
+ RangeInput,
127
+ DateInput,
128
+ FileInput,
129
+ TextInput
130
+ } from '@sio-group/form-react';
131
+
132
+ // Use with useForm hook
133
+ const { register } = useForm();
134
+
135
+ return (
136
+ <Input {...register('username', fieldConfig)} />
137
+ );
138
+ ```
139
+
140
+ ---
141
+
142
+ ## API Reference
143
+
144
+ ### Form Props
145
+
146
+ | Prop | Type | Default | Description |
147
+ |----------------------|--------------------------------|--------------------------|------------------------------|
148
+ | `fields` | `FormField[]` | (required) | Array of form fields |
149
+ | `submitAction` | `(values: any) => void` | (required) | Submit handler |
150
+ | `layout` | `FormLayout[]` | `[]` | Custom layout configuration |
151
+ | `submitShow` | `boolean` | `true` | Show submit button |
152
+ | `submitLabel` | `string` | `'Bewaar'` | Submit button text |
153
+ | `cancelShow` | `boolean` | `false` | Show cancel button |
154
+ | `cancelLabel` | `string` | `'Annuleren'` | Cancel button text |
155
+ | `cancelAction` | `() => void` | - | Cancel handler |
156
+ | `buttons` | `(ButtonProps \| LinkProps)[]` | `[]` | Additional buttons |
157
+ | `extraValidation` | `(values: any) => boolean` | `() => true` | Extra validation |
158
+ | `className` | `string` | - | CSS class for form container |
159
+ | `style` | `React.CSSProperties` | - | Inline styles |
160
+ | `disableWhenOffline` | `boolean` | `true` | Disable form when offline |
161
+ | `container` | `React.ComponentType` | `DefaultContainer` | Custom form container |
162
+ | `buttonContainer` | `React.ComponentType` | `DefaultButtonContainer` | Custom button container |
163
+
164
+ ### Layout Configuration
165
+
166
+ The `layout` prop allows you to arrange fields in a responsive grid:
167
+
168
+ ```tsx
169
+ const layout = [
170
+ {
171
+ layout: { sm: 12, md: 6, lg: 4 }, // Responsive column spans
172
+ fields: ['name', 'email'] // Fields in this row
173
+ },
174
+ {
175
+ layout: { sm: 12, md: 12, lg: 8 },
176
+ fields: ['message'],
177
+ className: 'custom-row', // Optional CSS class
178
+ style: { marginBottom: '2rem' } // Optional inline styles
179
+ }
180
+ ];
181
+ ```
182
+
183
+ **Breakpoint options:**
184
+ - `sm`: Small (≥640px)
185
+ - `md`: Medium (≥768px)
186
+ - `lg`: Large (≥1024px)
187
+
188
+ ### Button Configuration
189
+
190
+ Buttons can be configured as an array:
191
+
192
+ ```tsx
193
+ const buttons = [
194
+ {
195
+ type: 'button',
196
+ variant: 'primary',
197
+ color: 'success',
198
+ label: 'Save Draft',
199
+ onClick: () => saveDraft()
200
+ },
201
+ {
202
+ type: 'button',
203
+ variant: 'secondary',
204
+ color: 'warning',
205
+ label: 'Reset',
206
+ onClick: () => reset()
207
+ },
208
+ {
209
+ type: 'link',
210
+ variant: 'link',
211
+ color: 'info',
212
+ label: 'Help',
213
+ href: '/help'
214
+ }
215
+ ];
216
+ ```
217
+
218
+ **Button Props:**
219
+ - `type: 'button' | 'link'`
220
+ - `variant: 'primary' | 'secondary' | 'link'`
221
+ - `color: 'default' | 'success' | 'warning' | 'error' | 'info'`
222
+ - `label: string`
223
+ - `onClick?: () => void` (for buttons)
224
+ - `href?: string` (for links)
225
+ - `loading?: boolean`
226
+ - `disabled?: boolean`
227
+
228
+ ---
229
+
230
+ ## Hooks
231
+
232
+ ### useForm
233
+
234
+ A powerful hook for managing form state independently:
235
+
236
+ ```tsx
237
+ import { useForm } from '@sio-group/form-react';
238
+
239
+ function CustomForm() {
240
+ const { register, getValues, isValid, isBusy, reset, submit } = useForm();
241
+
242
+ const handleSubmit = async () => {
243
+ await submit(async (values) => {
244
+ await api.save(values);
245
+ });
246
+ };
247
+
248
+ return (
249
+ <form onSubmit={handleSubmit}>
250
+ <Input {...register('username', fieldConfig)} />
251
+ <button type="submit" disabled={!isValid() || isBusy()}>
252
+ Submit
253
+ </button>
254
+ </form>
255
+ );
256
+ }
257
+ ```
258
+
259
+ **useForm Return Value:**
260
+
261
+ | Method | Description |
262
+ |--------------------------|--------------------------------|
263
+ | `register(name, config)` | Register a field and get props |
264
+ | `unregister(name)` | Remove a field from form |
265
+ | `setValue(name, value)` | Set field value |
266
+ | `getValues()` | Get all form values |
267
+ | `getValue(name)` | Get single field value |
268
+ | `reset()` | Reset form state |
269
+ | `isValid()` | Check if form is valid |
270
+ | `isDirty()` | Check if form has changes |
271
+ | `isBusy()` | Check if form is submitting |
272
+ | `submit(handler)` | Submit form with handler |
273
+ | `getField(name)` | Get field state |
274
+
275
+ ### Conditional Fields
276
+
277
+ You can dynamically render fields based on other field values.
278
+
279
+ ```javascript
280
+ import { useForm, Input, Checkbox } from '@sio-group/form-react';
281
+
282
+ function Example() {
283
+ const { register, getValue } = useForm();
284
+
285
+ return (
286
+ <>
287
+ <Checkbox
288
+ {...register('subscribe', {
289
+ name: 'subscribe',
290
+ type: 'checkbox',
291
+ config: { label: 'Subscribe to newsletter' }
292
+ })}
293
+ />
294
+
295
+ {getValue('subscribe') && (
296
+ <Input
297
+ {...register('email', {
298
+ name: 'email',
299
+ type: 'email',
300
+ config: {
301
+ label: 'Email address',
302
+ required: true
303
+ }
304
+ })}
305
+ />
306
+ )}
307
+ </>
308
+ );
309
+ }
310
+ ```
311
+
312
+ ### Custom Validation
313
+
314
+ Default validation is automatically derived from the field configuration (`required`, `min`, `max`, `email`, etc.).
315
+ Additional validation rules can be added using the validations array.
316
+
317
+ ```javascript
318
+ import { Input } from '@sio-group/form-react';
319
+
320
+ <Input
321
+ {...register('username', {
322
+ name: 'username',
323
+ type: 'text',
324
+ config: {
325
+ label: 'Username',
326
+ required: true,
327
+ validations: [
328
+ (value) => value.length < 3 ? 'Username must contain at least 3 characters' : null,
329
+ (value) => value.includes('admin') ? 'Username cannot contain admin' : null
330
+ ]
331
+ },
332
+ })}
333
+ />
334
+ ```
335
+
336
+ ![Username](screenshots/invalid-username.png)
337
+ *Custom validation for admin in username*
338
+
339
+ ---
340
+
341
+ ## Field Components
342
+
343
+ ### Input Types
344
+
345
+ All standard HTML input types are supported:
346
+
347
+ - `text`, `search`, `email`, `tel`, `password`, `url`
348
+ - `number` (with spinner options)
349
+ - `range` (with value display)
350
+ - `date`, `time`, `datetime-local`
351
+ - `color`
352
+ - `hidden`
353
+ - `file` (with file validation)
354
+
355
+ ### Specialized Components
356
+
357
+ #### NumberInput
358
+ ```tsx
359
+ <NumberInput
360
+ {...register('age', {
361
+ name: "age",
362
+ type: "number",
363
+ config: {
364
+ label: "Age",
365
+ min: 0,
366
+ max: 120,
367
+ step: 1,
368
+ spinner: 'horizontal' // or "vertical", true, false
369
+ }
370
+ }) as NumberFieldProps}
371
+ />
372
+ ```
373
+
374
+ ![NumberInput](screenshots/number-field.png)
375
+ *Number input with horizontal spinner*
376
+
377
+ #### RangeInput
378
+ ```tsx
379
+ <RangeInput
380
+ {...register('volume', {
381
+ name: "volume",
382
+ type: "range",
383
+ config: {
384
+ label: "Volume",
385
+ min: 0,
386
+ max: 120,
387
+ step: 1,
388
+ showValue: true,
389
+ }
390
+ }) as NumberFieldProps}
391
+ />
392
+ ```
393
+
394
+ ![RangeInput](screenshots/range-field.png)
395
+ *Range input with shown value*
396
+
397
+ #### FileInput
398
+ ```tsx
399
+ <FileInput
400
+ {...register('documents', {
401
+ name: "documents",
402
+ type: "file",
403
+ config: {
404
+ label: "Documenten",
405
+ accept: ".pdf,.doc",
406
+ multiple: true,
407
+ filesize: 5120, // 5MB in KB
408
+ capture: false,
409
+ onFileRemove: (file) => console.log('Removed:', file),
410
+ onRemoveAll: (files) => console.log('All removed:', files)
411
+ }
412
+ }) as FileFieldProps}
413
+ />
414
+ ```
415
+
416
+ ![FileInput](screenshots/file-input.png)
417
+ *Multiple file input*
418
+
419
+ #### Select
420
+ ```tsx
421
+ <Select
422
+ {...register('country', {
423
+ name: 'country',
424
+ type: 'select',
425
+ config: {
426
+ options: [
427
+ { value: 'be', label: 'Belgium' },
428
+ { value: 'nl', label: 'Netherlands' },
429
+ {
430
+ label: 'Europe',
431
+ options: [
432
+ { value: 'fr', label: 'France' }
433
+ ]
434
+ }
435
+ ],
436
+ multiple: false,
437
+ placeholder: "Choose a country"
438
+ }
439
+ }) as SelectFieldProps}
440
+ />
441
+ ```
442
+
443
+ ![Select](screenshots/select-field.png)
444
+ *Single select input*
445
+
446
+ #### Radio
447
+ ```tsx
448
+ <Radio
449
+ {...register('country', {
450
+ name: "country",
451
+ type: "radio",
452
+ config: {
453
+ label: "Country",
454
+ options: ['Red', 'Green', 'Blue'],
455
+ inline: true
456
+ }
457
+ }) as RadioFieldProps}
458
+ />
459
+ ```
460
+
461
+ ![Radio](screenshots/radio-field.png)
462
+ *Inline radio input*
463
+
464
+ #### Textarea
465
+ ```tsx
466
+ <Textarea
467
+ {...register('bio', {
468
+ name: "bio",
469
+ type: "textarea",
470
+ config: {
471
+ label: "Bio",
472
+ placeholder: "Tell us about yourself...",
473
+ rows: 5,
474
+ cols: 40,
475
+ }
476
+ }) as TextareaFieldProps}
477
+ />
478
+ ```
479
+
480
+ ![Textarea](screenshots/textarea-field.png)
481
+ *Textarea input*
482
+
483
+ ---
484
+
485
+ ## Standalone Components
486
+
487
+ ### Controlled Usage (with `useForm`)
488
+
489
+ You can use the `useForm` hook to control how you use the form, centrally managing state, validation, and submission. This also demonstrates conditional rendering and error automation.
490
+
491
+ ```javascript
492
+ import { useForm, Input, Button } from '@sio-group/form-react';
493
+
494
+ function FormWithHook() {
495
+ const { register, getValue, isValid, isBusy, submit } = useForm();
496
+
497
+ const handleSubmit = async (e) => {
498
+ e.preventDefault();
499
+ await submit(values => console.log('Form values:', values));
500
+ };
501
+
502
+ return (
503
+ <form noValidate>
504
+ <Input
505
+ {...register('email', {
506
+ name: 'email',
507
+ type: 'email',
508
+ config: {
509
+ label: 'Email Address',
510
+ required: true,
511
+ validations: [
512
+ val => val.includes('@') ? null : 'Must be a valid email',
513
+ ]
514
+ }
515
+ })}
516
+ />
517
+
518
+ <Button
519
+ type="submit"
520
+ variant="primary"
521
+ disabled={!isValid()}
522
+ onClick={handleSubmit}
523
+ >
524
+ {isBusy() ? 'sending' : 'Submit'}
525
+ </Button>
526
+
527
+ {getValue('email') && <p>Your email: {getValue('email')}</p>}
528
+ </form>
529
+ );
530
+ }
531
+ ```
532
+
533
+ ### Uncontrolled Usage (without `useForm`)
534
+
535
+ All field components and buttons can also be used independently. You can keep and manage state for the form depending on your needs.
536
+
537
+ ```javascript
538
+ import { useState } from 'react';
539
+ import { Input, Button } from '@sio-group/form-react';
540
+
541
+ function SimpleForm() {
542
+ const [value, setValue] = useState('');
543
+ const [error, setError] = useState('');
544
+ const [touched, setTouched] = useState(false);
545
+ const [focused, setFocused] = useState(false);
546
+ const [isValid, setIsValid] = useState(false);
547
+
548
+ const handleChange = (value) => {
549
+ if (!value) {
550
+ setError("This is wrong");
551
+ setIsValid(false);
552
+ } else {
553
+ setError("");
554
+ setIsValid(true);
555
+ }
556
+
557
+ setValue(value);
558
+ }
559
+
560
+ const handleSubmit = (e) => {
561
+ e.preventDefault();
562
+ console.log(value);
563
+ }
564
+
565
+ return (
566
+ <form noValidate>
567
+ <TextInput
568
+ type="email"
569
+ id="email"
570
+ name="email"
571
+ value={value}
572
+ errors={error ? [error] : []}
573
+ touched={touched}
574
+ focused={focused}
575
+ disabled={false}
576
+ onChange={handleChange}
577
+ setFocused={setFocused}
578
+ setTouched={setTouched}
579
+ />
580
+
581
+ <Button
582
+ type="submit"
583
+ variant="primary"
584
+ onClick={handleSubmit}
585
+ disabled={!isValid}
586
+ >
587
+ Submit
588
+ </Button>
589
+ </form>
590
+ );
591
+ }
592
+ ```
593
+
594
+ ### Button Props
595
+ | Prop | Type | Default | Description |
596
+ |------------|------------------------------------------------------------|-------------|-------------------------|
597
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Button type |
598
+ | `label` | `string` | - | Label of the Link |
599
+ | `onClick` | `(e: React.MouseEvent) => void` | - | Custom onClick function |
600
+ | `variant` | `'primary' \| 'secondary' \| 'link'` | `'primary'` | Visual variant |
601
+ | `color` | `'default' \| 'error' \| 'success' \| 'warning' \| 'info'` | `'default'` | Color theme |
602
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
603
+ | `block` | `boolean` | `false` | Full width |
604
+ | `loading` | `boolean` | `false` | Loading state |
605
+ | `disabled` | `boolean` | `false` | Disabled state |
606
+
607
+ ### Link Props
608
+ | Prop | Type | Default | Description |
609
+ |------------|------------------------------------------------------------|-------------|--------------------------|
610
+ | `label` | `string` | - | Label of the Link |
611
+ | `to` | `string` | `'#'` | URL or pad |
612
+ | `onClick` | `(e: React.MouseEvent) => void` | - | Custom onClick function |
613
+ | `color` | `'default' \| 'error' \| 'success' \| 'warning' \| 'info'` | `'default'` | Color theme |
614
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
615
+ | `block` | `boolean` | `false` | Full width |
616
+ | `loading` | `boolean` | `false` | Loading state |
617
+ | `disabled` | `boolean` | `false` | Disabled state |
618
+ | `navigate` | `() => void` | - | Custom navigate function |
619
+ | `external` | `boolean` | `false` | Force external link |
620
+
621
+
622
+ ---
623
+
624
+ ## Styling
625
+
626
+ ### Default Styles
627
+
628
+ Import the default styles:
629
+
630
+ ```tsx
631
+ import '@sio-group/form-react/sio-form-style.css';
632
+ ```
633
+
634
+ ### Custom Styling
635
+
636
+ Each component accepts `className` and `style` props for custom styling:
637
+
638
+ ```tsx
639
+ <Input
640
+ {...register('username', {
641
+ name: 'username',
642
+ type: 'text',
643
+ config: {
644
+ styling: {
645
+ className: 'custom-input',
646
+ style: {
647
+ backgroundColor: '#f0f0f0'
648
+ }
649
+ }
650
+ }
651
+ })}
652
+ />
653
+ ```
654
+
655
+ ### Layout Classes
656
+
657
+ The form uses a responsive grid system. You can target these classes:
658
+
659
+ - `.sio-row` - Grid container
660
+ - `.sio-col-xs-*` - Column classes for breakpoints
661
+ - `.sio-col-sm-*`
662
+ - `.sio-col-md-*`
663
+ - `.sio-col-lg-*`
664
+ - `.sio-col-xl-*`
665
+
666
+ Example with Tailwind CSS:
667
+ ```tsx
668
+ <Form
669
+ fields={fields}
670
+ className="max-w-2xl mx-auto"
671
+ layout={[
672
+ { layout: { md: 6 }, fields: ['firstName'], className: 'pr-2' },
673
+ { layout: { md: 6 }, fields: ['lastName'], className: 'pl-2' }
674
+ ]}
675
+ />
676
+ ```
677
+
678
+ ---
679
+
680
+ ## Complete Example
681
+
682
+ ```tsx
683
+ import { Form } from '@sio-group/form-react';
684
+ import { formBuilder } from '@sio-group/form-builder';
685
+ import '@sio-group/form-react/sio-form-style.css';
686
+
687
+ function RegistrationForm() {
688
+ const fields = formBuilder()
689
+ .addText('firstName', {
690
+ label: 'First name',
691
+ required: true,
692
+ layout: { md: 6 }
693
+ })
694
+ .addText('lastName', {
695
+ label: 'Last name',
696
+ required: true,
697
+ layout: { md: 6 }
698
+ })
699
+ .addEmail('email', {
700
+ label: 'Email',
701
+ required: true,
702
+ layout: { md: 6 }
703
+ })
704
+ .addTelephone('phone', {
705
+ label: 'Phone',
706
+ layout: { md: 6 }
707
+ })
708
+ .addPassword('password', {
709
+ label: 'Password',
710
+ required: true,
711
+ layout: { md: 6 }
712
+ })
713
+ .addPassword('confirmPassword', {
714
+ label: 'Confirm password',
715
+ required: true,
716
+ layout: { md: 6 }
717
+ })
718
+ .addCheckbox('terms', {
719
+ label: 'I accept the terms and conditions',
720
+ required: true
721
+ })
722
+ .getFields();
723
+
724
+ const handleSubmit = (values) => {
725
+ console.log('Registration:', values);
726
+ };
727
+
728
+ const customButtons = [
729
+ {
730
+ type: 'button',
731
+ variant: 'secondary',
732
+ color: 'info',
733
+ label: 'Clear form',
734
+ onClick: () => console.log('Clear')
735
+ }
736
+ ];
737
+
738
+ return (
739
+ <Form
740
+ fields={fields}
741
+ submitAction={handleSubmit}
742
+ submitLabel="Register"
743
+ cancelShow={true}
744
+ cancelAction={() => console.log('Cancelled')}
745
+ buttons={customButtons}
746
+ className="registration-form"
747
+ layout={[
748
+ { layout: { md: 6 }, fields: ['firstName'] },
749
+ { layout: { md: 6 }, fields: ['lastName'] },
750
+ { layout: { md: 6 }, fields: ['email'] },
751
+ { layout: { md: 6 }, fields: ['phone'] },
752
+ { layout: { md: 6 }, fields: ['password'] },
753
+ { layout: { md: 6 }, fields: ['confirmPassword'] },
754
+ { layout: { md: 12 }, fields: ['terms'] }
755
+ ]}
756
+ />
757
+ );
758
+ }
759
+ ```
760
+
761
+ ![RegistrationForm](screenshots/registration-form.png)
762
+ *A simple registration form with simple layout*
763
+
764
+ ---
765
+
766
+ ## Ecosystem
767
+
768
+ `@sio-group/form-react` is part of the SIO Form ecosystem:
769
+
770
+ - **[@sio-group/form-types](../form-types/README.md)** - Shared type definitions
771
+ - **[@sio-group/form-builder](../form-builder/README.md)** - Define your form structure
772
+ - **[@sio-group/form-validation](../form-validation/README.md)** - Validate your data
773
+ - **[@sio-group/form-react](../form-react/README.md)** - This package: React renderer and hooks for the builder (you are here)
774
+
775
+ ---
776
+
777
+ ## Contributing
778
+
779
+ Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.
780
+
781
+ ## License
782
+
783
+ This project is licensed under the ISC License - see the [LICENSE](../../LICENSE) file for details.