@uniquedj95/vform 3.5.2 → 3.6.1
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 +433 -38
- package/dist/components/inputs/BaseInput.vue.d.ts.map +1 -1
- package/dist/components/inputs/CheckboxInput.vue.d.ts.map +1 -1
- package/dist/components/inputs/RadioInput.vue.d.ts.map +1 -1
- package/dist/components/inputs/RepeatInput.vue.d.ts.map +1 -1
- package/dist/components/inputs/SelectInput.vue.d.ts.map +1 -1
- package/dist/components/inputs/TextAreaInput.vue.d.ts.map +1 -1
- package/dist/components/vForm.vue.d.ts +1 -0
- package/dist/components/vForm.vue.d.ts.map +1 -1
- package/dist/composables/useMultiStepForm.d.ts +1 -2
- package/dist/composables/useMultiStepForm.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +874 -825
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/types/index.d.ts +57 -46
- package/dist/types/index.d.ts.map +1 -1
- package/dist/vform.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
A dynamic form builder for Vue.js with Ionic components
|
|
8
8
|
|
|
9
|
-
[](https://github.com/uniquedj95/vform/releases)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
[](https://vuejs.org/)
|
|
12
12
|
[](https://www.typescriptlang.org/)
|
|
@@ -31,6 +31,7 @@ A dynamic form builder for Vue.js with Ionic components
|
|
|
31
31
|
- [Basic Multi-Step Setup](#basic-multi-step-setup)
|
|
32
32
|
- [Step Configuration](#step-configuration)
|
|
33
33
|
- [Step Indicator Positioning](#step-indicator-positioning)
|
|
34
|
+
- [Custom Components in Steps](#custom-components-in-steps)
|
|
34
35
|
- [Step Validation](#step-validation)
|
|
35
36
|
- [Form Sections](#form-sections)
|
|
36
37
|
- [Basic Section Usage](#basic-section-usage)
|
|
@@ -71,6 +72,7 @@ The demo showcases:
|
|
|
71
72
|
- **Basic Forms**: All input types and basic functionality
|
|
72
73
|
- **Form Sections**: Organized forms with section headers and titles
|
|
73
74
|
- **Multi-Step Forms**: Step indicators, validation, and smart navigation
|
|
75
|
+
- **Custom Components**: Integration of custom Vue components within multi-step workflows
|
|
74
76
|
- **Advanced Features**: Masking, computed fields, custom buttons
|
|
75
77
|
- **Validation Examples**: Custom validators and error handling
|
|
76
78
|
- **Dependent Fields**: Dynamic field behavior and cascading options
|
|
@@ -90,6 +92,7 @@ npm run demo:update
|
|
|
90
92
|
## Features
|
|
91
93
|
|
|
92
94
|
- **Multi-Step Forms**: Create guided, step-by-step forms with configurable step indicators, validation, and smart navigation.
|
|
95
|
+
- **Custom Components**: Integrate custom Vue components directly into multi-step forms for advanced visualizations and workflows.
|
|
93
96
|
- **Form Sections**: Organize forms into logical sections with titles and subtitles for better user experience.
|
|
94
97
|
- **Dynamic Form Generation**: Create forms dynamically based on a schema definition.
|
|
95
98
|
- **Conditional Field Rendering**: Fields can be shown or hidden based on other form values.
|
|
@@ -100,7 +103,7 @@ npm run demo:update
|
|
|
100
103
|
- **Repeatable Field Groups**: Create dynamic, repeatable sets of form fields.
|
|
101
104
|
- **Advanced Validation**: Built-in validation with support for custom validation functions and step-by-step validation.
|
|
102
105
|
- **Computed Values**: Generate and transform values based on other form fields.
|
|
103
|
-
- **Customizable Styling**:
|
|
106
|
+
- **Customizable Styling**: Complete control over appearance with `className` property support across all input components and sections.
|
|
104
107
|
- **Form Actions**: Customizable buttons with support for additional custom actions.
|
|
105
108
|
- **Rich Text Areas**: Textarea inputs with auto-grow capability and character counting.
|
|
106
109
|
- **Form Field Dependencies**: Create relationships between fields that react to changes.
|
|
@@ -255,18 +258,18 @@ const formSchema: FormSchema = {
|
|
|
255
258
|
|
|
256
259
|
The following input types are supported:
|
|
257
260
|
|
|
258
|
-
| Type | Description
|
|
259
|
-
| --------------- |
|
|
260
|
-
| `TextInput` | Standard text input field
|
|
261
|
-
| `DateInput` | Date picker with customizable format
|
|
262
|
-
| `NumberInput` | Numeric input field
|
|
263
|
-
| `EmailInput` | Input field with email validation
|
|
264
|
-
| `PasswordInput` | Secure password input with toggle visibility
|
|
265
|
-
| `TextAreaInput` | Multi-line text input
|
|
266
|
-
| `SelectInput` | Dropdown selection
|
|
267
|
-
| `CheckboxInput` | Toggle on/off input
|
|
268
|
-
| `RepeatInput` | Repeatable group of fields
|
|
269
|
-
| `FormSection` | Section header with title and subtitle
|
|
261
|
+
| Type | Description |
|
|
262
|
+
| --------------- | --------------------------------------------------------------- |
|
|
263
|
+
| `TextInput` | Standard text input field |
|
|
264
|
+
| `DateInput` | Date picker with customizable format |
|
|
265
|
+
| `NumberInput` | Numeric input field |
|
|
266
|
+
| `EmailInput` | Input field with email validation |
|
|
267
|
+
| `PasswordInput` | Secure password input with toggle visibility |
|
|
268
|
+
| `TextAreaInput` | Multi-line text input |
|
|
269
|
+
| `SelectInput` | Dropdown selection |
|
|
270
|
+
| `CheckboxInput` | Toggle on/off input |
|
|
271
|
+
| `RepeatInput` | Repeatable group of fields |
|
|
272
|
+
| `FormSection` | Section header with title and subtitle (unified with FormField) |
|
|
270
273
|
|
|
271
274
|
#### Common Properties
|
|
272
275
|
|
|
@@ -284,12 +287,13 @@ The following input types are supported:
|
|
|
284
287
|
|
|
285
288
|
#### Layout Properties
|
|
286
289
|
|
|
287
|
-
| Property
|
|
288
|
-
|
|
|
289
|
-
| `grid`
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
290
|
+
| Property | Type | Description |
|
|
291
|
+
| ----------- | ---------- | ------------------------------------------------------------- |
|
|
292
|
+
| `grid` | `GridSize` | Specifies responsive grid sizes: `xs`, `sm`, `md`, `lg`, `xl` |
|
|
293
|
+
| `className` | `string` | Custom CSS class for styling input fields and sections |
|
|
294
|
+
| `icon` | `string` | Icon to display within the input field |
|
|
295
|
+
| `prefix` | `string` | Text to display before the input value |
|
|
296
|
+
| `suffix` | `string` | Text to display after the input value |
|
|
293
297
|
|
|
294
298
|
#### Validation and Dynamic Behavior
|
|
295
299
|
|
|
@@ -346,6 +350,84 @@ The following input types are supported:
|
|
|
346
350
|
| ---------- | ------------ | ------------------------------------- |
|
|
347
351
|
| `children` | `FormSchema` | Schema for the repeatable field group |
|
|
348
352
|
|
|
353
|
+
### Custom Styling with className
|
|
354
|
+
|
|
355
|
+
All form input components now support the `className` property for custom styling. This allows you to apply CSS classes to individual input fields and form sections for complete visual customization.
|
|
356
|
+
|
|
357
|
+
#### Usage Examples
|
|
358
|
+
|
|
359
|
+
```typescript
|
|
360
|
+
const formSchema: FormSchema = {
|
|
361
|
+
// Custom styled text input
|
|
362
|
+
customInput: {
|
|
363
|
+
type: 'TextInput',
|
|
364
|
+
label: 'Styled Input',
|
|
365
|
+
className: 'my-custom-input',
|
|
366
|
+
placeholder: 'Enter text here',
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
// Custom styled section
|
|
370
|
+
styledSection: {
|
|
371
|
+
type: 'FormSection',
|
|
372
|
+
title: 'Custom Section',
|
|
373
|
+
subtitle: 'This section has custom styling',
|
|
374
|
+
className: 'my-custom-section',
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
// Custom styled select input
|
|
378
|
+
styledSelect: {
|
|
379
|
+
type: 'SelectInput',
|
|
380
|
+
label: 'Styled Select',
|
|
381
|
+
className: 'my-custom-select',
|
|
382
|
+
options: [
|
|
383
|
+
{ label: 'Option 1', value: '1' },
|
|
384
|
+
{ label: 'Option 2', value: '2' },
|
|
385
|
+
],
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### CSS Implementation
|
|
391
|
+
|
|
392
|
+
```css
|
|
393
|
+
/* Custom input styling */
|
|
394
|
+
.my-custom-input {
|
|
395
|
+
--background: #f8f9fa;
|
|
396
|
+
--border-color: #007bff;
|
|
397
|
+
--color: #333;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Custom section styling */
|
|
401
|
+
.my-custom-section .form-section-title {
|
|
402
|
+
color: #007bff;
|
|
403
|
+
font-size: 1.5rem;
|
|
404
|
+
font-weight: 600;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.my-custom-section .form-section-subtitle {
|
|
408
|
+
color: #6c757d;
|
|
409
|
+
font-style: italic;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* Custom select styling */
|
|
413
|
+
.my-custom-select {
|
|
414
|
+
--background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
415
|
+
--color: white;
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
#### Component Support
|
|
420
|
+
|
|
421
|
+
The `className` property is supported across all input components:
|
|
422
|
+
|
|
423
|
+
- **BaseInput**: Applied to `ion-input` element (covers TextInput, EmailInput, NumberInput, PasswordInput, DateInput)
|
|
424
|
+
- **TextAreaInput**: Applied to `ion-textarea` element
|
|
425
|
+
- **SelectInput**: Applied to the wrapper container
|
|
426
|
+
- **CheckboxInput**: Applied to `ion-checkbox` element
|
|
427
|
+
- **RadioInput**: Applied to `ion-radio-group` element
|
|
428
|
+
- **RepeatInput**: Applied to each repeat group wrapper
|
|
429
|
+
- **FormSection**: Applied to the section container
|
|
430
|
+
|
|
349
431
|
## Multi-Step Forms
|
|
350
432
|
|
|
351
433
|
vForm supports multi-step forms with configurable step indicators, validation, and smart navigation. Multi-step forms break complex forms into manageable sections, improving user experience and data collection.
|
|
@@ -433,13 +515,79 @@ function handleStepChange(stepIndex: number, stepId: string) {
|
|
|
433
515
|
|
|
434
516
|
Each step in the multi-step configuration supports the following properties:
|
|
435
517
|
|
|
436
|
-
| Property
|
|
437
|
-
|
|
|
438
|
-
| `id`
|
|
439
|
-
| `title`
|
|
440
|
-
| `subtitle`
|
|
441
|
-
| `schema`
|
|
442
|
-
| `
|
|
518
|
+
| Property | Type | Description | Required |
|
|
519
|
+
| ---------------- | ------------ | ------------------------------------------------------------------------ | -------- |
|
|
520
|
+
| `id` | `string` | Unique identifier for the step | Yes |
|
|
521
|
+
| `title` | `string` | Display title for the step | Yes |
|
|
522
|
+
| `subtitle` | `string` | Optional subtitle/description for the step | No |
|
|
523
|
+
| `schema` | `FormSchema` | Schema object containing fields for this step | No |
|
|
524
|
+
| `component` | `Component` | Custom Vue component to render instead of a schema | No |
|
|
525
|
+
| `componentProps` | `Object` | Props to pass to the custom component | No |
|
|
526
|
+
| `condition` | `function` | Function that determines if the step should be shown, based on form data | No |
|
|
527
|
+
| `validation` | `function` | Custom validation function for the step | No |
|
|
528
|
+
|
|
529
|
+
\*Either `schema` or `component` must be provided.
|
|
530
|
+
|
|
531
|
+
### Custom Components in Steps
|
|
532
|
+
|
|
533
|
+
vForm allows you to use custom Vue components in multi-step forms instead of schema-defined fields. This is useful for complex steps that require custom layouts, visualizations, or integration with other components.
|
|
534
|
+
|
|
535
|
+
```vue
|
|
536
|
+
<template>
|
|
537
|
+
<v-form :multi-step-config="multiStepConfig" @multi-step-submit="handleSubmit" />
|
|
538
|
+
</template>
|
|
539
|
+
|
|
540
|
+
<script setup lang="ts">
|
|
541
|
+
import { MultiStepConfig } from '@uniquedj95/vform';
|
|
542
|
+
import PreviousResultsTable from './components/PreviousResultsTable.vue';
|
|
543
|
+
|
|
544
|
+
const multiStepConfig: MultiStepConfig = {
|
|
545
|
+
steps: [
|
|
546
|
+
{
|
|
547
|
+
id: 'patient-info',
|
|
548
|
+
title: 'Patient Information',
|
|
549
|
+
schema: {
|
|
550
|
+
// Regular form schema for step 1
|
|
551
|
+
patientId: {
|
|
552
|
+
type: 'TextInput',
|
|
553
|
+
label: 'Patient ID',
|
|
554
|
+
required: true,
|
|
555
|
+
},
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
id: 'previous-results',
|
|
560
|
+
title: 'Previous ANC Results',
|
|
561
|
+
// Use a custom component instead of a schema
|
|
562
|
+
component: PreviousResultsTable,
|
|
563
|
+
componentProps: {
|
|
564
|
+
// Props to pass to your component
|
|
565
|
+
clinicId: 123,
|
|
566
|
+
showDetails: true,
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
{
|
|
570
|
+
id: 'new-visit',
|
|
571
|
+
title: 'New ANC Visit',
|
|
572
|
+
schema: {
|
|
573
|
+
// Back to regular schema for step 3
|
|
574
|
+
visitDate: {
|
|
575
|
+
type: 'DateInput',
|
|
576
|
+
label: 'Visit Date',
|
|
577
|
+
required: true,
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
],
|
|
582
|
+
};
|
|
583
|
+
</script>
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
Custom components need to implement a `validate()` method that returns a boolean to integrate with the form validation workflow, and emit an `update:data` event to pass data back to the form.
|
|
587
|
+
|
|
588
|
+
For detailed implementation examples and best practices, see the [Custom Components Guide](./docs/CUSTOM_COMPONENTS.md).
|
|
589
|
+
|
|
590
|
+
A complete working example is available in the demo app under `demo/src/examples/CustomComponentExample.vue` that demonstrates a real-world ANC (Antenatal Care) workflow using a custom component to display previous visit history.
|
|
443
591
|
|
|
444
592
|
### Step Indicator Positioning
|
|
445
593
|
|
|
@@ -461,6 +609,254 @@ const multiStepConfig: MultiStepConfig = {
|
|
|
461
609
|
- **Left**: Step indicators display vertically with titles to the right of numbered markers
|
|
462
610
|
- **Right**: Step indicators display vertically with titles to the left of numbered markers
|
|
463
611
|
|
|
612
|
+
### Conditional Steps
|
|
613
|
+
|
|
614
|
+
vForm allows you to conditionally show or hide steps based on the values entered in previous steps. This is useful for creating dynamic workflows that adapt to user input.
|
|
615
|
+
|
|
616
|
+
```vue
|
|
617
|
+
<script setup lang="ts">
|
|
618
|
+
import { reactive } from 'vue';
|
|
619
|
+
import { MultiStepConfig } from '@uniquedj95/vform';
|
|
620
|
+
|
|
621
|
+
const multiStepConfig = reactive<MultiStepConfig>({
|
|
622
|
+
steps: [
|
|
623
|
+
{
|
|
624
|
+
id: 'account-type',
|
|
625
|
+
title: 'Account Type',
|
|
626
|
+
schema: {
|
|
627
|
+
accountType: {
|
|
628
|
+
type: 'SelectInput',
|
|
629
|
+
label: 'Account Type',
|
|
630
|
+
options: [
|
|
631
|
+
{ label: 'Personal', value: 'personal' },
|
|
632
|
+
{ label: 'Business', value: 'business' },
|
|
633
|
+
],
|
|
634
|
+
value: 'personal',
|
|
635
|
+
required: true,
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
id: 'business-details',
|
|
641
|
+
title: 'Business Details',
|
|
642
|
+
schema: {
|
|
643
|
+
businessName: {
|
|
644
|
+
type: 'TextInput',
|
|
645
|
+
label: 'Business Name',
|
|
646
|
+
required: true,
|
|
647
|
+
},
|
|
648
|
+
},
|
|
649
|
+
// Only show this step if accountType is 'business'
|
|
650
|
+
// Using stepData with step ID to avoid field name conflicts
|
|
651
|
+
condition: (stepData, stepComputedData) => {
|
|
652
|
+
return /business/i.test(stepData['account-type'].accountType.label);
|
|
653
|
+
},
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
id: 'review',
|
|
657
|
+
title: 'Review',
|
|
658
|
+
schema: {
|
|
659
|
+
// Review fields
|
|
660
|
+
},
|
|
661
|
+
},
|
|
662
|
+
],
|
|
663
|
+
});
|
|
664
|
+
</script>
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
The `condition` function receives two arguments:
|
|
668
|
+
|
|
669
|
+
- `stepData`: Form data organized by step ID to avoid key conflicts
|
|
670
|
+
- `stepComputedData`: Computed data organized by step ID
|
|
671
|
+
|
|
672
|
+
```typescript
|
|
673
|
+
condition: (stepData, stepComputedData) => {
|
|
674
|
+
const firstStepData = stepData['first-step-id'];
|
|
675
|
+
return firstStepData.someField === 'expectedValue';
|
|
676
|
+
};
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
When a step is hidden:
|
|
680
|
+
|
|
681
|
+
- It won't be visible in the step indicator
|
|
682
|
+
- Navigation will skip over it automatically
|
|
683
|
+
- The step count and progress indicators will update accordingly
|
|
684
|
+
- **Data behavior**: Form data from hidden steps is automatically cleared
|
|
685
|
+
- Hidden step data is not included in the final submission
|
|
686
|
+
- If a step becomes visible again, it starts with empty/default values
|
|
687
|
+
- This prevents processing of data that was meant to be skipped
|
|
688
|
+
|
|
689
|
+
> **Note:** The data clearing happens whenever the visibility of steps changes. If you need
|
|
690
|
+
> to preserve data from conditionally hidden steps for some specific use case, you can
|
|
691
|
+
> store a backup of the data separately before the condition changes:
|
|
692
|
+
>
|
|
693
|
+
> ```typescript
|
|
694
|
+
> // Save data before hiding a step
|
|
695
|
+
> const backupData = { ...stepData.value['step-to-be-hidden'] };
|
|
696
|
+
>
|
|
697
|
+
> // Later, if you need to restore the data when the step becomes visible again
|
|
698
|
+
> updateStepData('step-to-be-hidden', backupData);
|
|
699
|
+
> ```
|
|
700
|
+
|
|
701
|
+
### Custom Components in Steps
|
|
702
|
+
|
|
703
|
+
vForm allows you to use custom Vue components in multi-step forms instead of schema-defined fields. This is useful for complex steps that require custom layouts, visualizations, or integration with other components.
|
|
704
|
+
|
|
705
|
+
```vue
|
|
706
|
+
<template>
|
|
707
|
+
<v-form
|
|
708
|
+
:multi-step-config="multiStepConfig"
|
|
709
|
+
@multi-step-submit="handleSubmit"
|
|
710
|
+
@step-change="handleStepChange"
|
|
711
|
+
/>
|
|
712
|
+
</template>
|
|
713
|
+
|
|
714
|
+
<script setup lang="ts">
|
|
715
|
+
import { defineComponent, ref } from 'vue';
|
|
716
|
+
import { MultiStepConfig } from '@uniquedj95/vform';
|
|
717
|
+
import PreviousResultsTable from './PreviousResultsTable.vue';
|
|
718
|
+
|
|
719
|
+
// Define your custom component
|
|
720
|
+
const PreviousResultsTable = defineComponent({
|
|
721
|
+
props: {
|
|
722
|
+
data: Object,
|
|
723
|
+
},
|
|
724
|
+
setup(props, { emit }) {
|
|
725
|
+
// Implement your component logic
|
|
726
|
+
const tableData = ref([
|
|
727
|
+
/* your data */
|
|
728
|
+
]);
|
|
729
|
+
|
|
730
|
+
// Custom validation function - will be called when clicking "Next"
|
|
731
|
+
function validate() {
|
|
732
|
+
// Add your validation logic here
|
|
733
|
+
return true; // Return true if valid, false if not
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Function to update data in the parent form
|
|
737
|
+
function updateData() {
|
|
738
|
+
emit('update:data', {
|
|
739
|
+
/* your component data */
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return { tableData, validate, updateData };
|
|
744
|
+
},
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
const multiStepConfig: MultiStepConfig = {
|
|
748
|
+
steps: [
|
|
749
|
+
{
|
|
750
|
+
id: 'patient-info',
|
|
751
|
+
title: 'Patient Information',
|
|
752
|
+
schema: {
|
|
753
|
+
// Standard form schema
|
|
754
|
+
patientId: {
|
|
755
|
+
type: 'TextInput',
|
|
756
|
+
label: 'Patient ID',
|
|
757
|
+
required: true,
|
|
758
|
+
},
|
|
759
|
+
// More fields...
|
|
760
|
+
},
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: 'previous-results',
|
|
764
|
+
title: 'Previous ANC Results',
|
|
765
|
+
// Use a custom component instead of a schema
|
|
766
|
+
component: PreviousResultsTable,
|
|
767
|
+
componentProps: {
|
|
768
|
+
// Props to pass to your component
|
|
769
|
+
clinicId: 123,
|
|
770
|
+
showDetails: true,
|
|
771
|
+
},
|
|
772
|
+
},
|
|
773
|
+
{
|
|
774
|
+
id: 'new-visit',
|
|
775
|
+
title: 'New ANC Visit',
|
|
776
|
+
schema: {
|
|
777
|
+
// Back to standard form schema
|
|
778
|
+
visitDate: {
|
|
779
|
+
type: 'DateInput',
|
|
780
|
+
label: 'Visit Date',
|
|
781
|
+
required: true,
|
|
782
|
+
},
|
|
783
|
+
// More fields...
|
|
784
|
+
},
|
|
785
|
+
},
|
|
786
|
+
],
|
|
787
|
+
stepPosition: 'top',
|
|
788
|
+
showProgress: true,
|
|
789
|
+
allowStepNavigation: true,
|
|
790
|
+
};
|
|
791
|
+
</script>
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
#### Custom Component Requirements
|
|
795
|
+
|
|
796
|
+
To work properly with the multi-step form, your custom component should:
|
|
797
|
+
|
|
798
|
+
1. **Accept Props**: Receive data and configuration through props
|
|
799
|
+
2. **Emit Data Updates**: Use `emit('update:data', yourData)` to send data back to the form
|
|
800
|
+
3. **Implement Validation**: Expose a `validate()` method that returns a boolean or promise resolving to boolean
|
|
801
|
+
|
|
802
|
+
#### Component Interface Example
|
|
803
|
+
|
|
804
|
+
```vue
|
|
805
|
+
<template>
|
|
806
|
+
<div class="custom-step-component">
|
|
807
|
+
<!-- Your custom UI here -->
|
|
808
|
+
<data-table :data="tableData" @row-click="selectRow" />
|
|
809
|
+
|
|
810
|
+
<!-- You can still use Ionic components -->
|
|
811
|
+
<ion-button @click="handleSave">Save Selection</ion-button>
|
|
812
|
+
</div>
|
|
813
|
+
</template>
|
|
814
|
+
|
|
815
|
+
<script setup>
|
|
816
|
+
import { ref, defineEmits, defineExpose } from 'vue';
|
|
817
|
+
|
|
818
|
+
const props = defineProps({
|
|
819
|
+
// Your props here
|
|
820
|
+
initialData: Object,
|
|
821
|
+
});
|
|
822
|
+
|
|
823
|
+
const emits = defineEmits(['update:data']);
|
|
824
|
+
|
|
825
|
+
const tableData = ref([]);
|
|
826
|
+
const selectedRow = ref(null);
|
|
827
|
+
|
|
828
|
+
function selectRow(row) {
|
|
829
|
+
selectedRow.value = row;
|
|
830
|
+
emitData();
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function handleSave() {
|
|
834
|
+
// Your save logic
|
|
835
|
+
emitData();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
function emitData() {
|
|
839
|
+
// Send data back to parent form
|
|
840
|
+
emits('update:data', {
|
|
841
|
+
selected: selectedRow.value,
|
|
842
|
+
// other data...
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// This method will be called for validation
|
|
847
|
+
function validate() {
|
|
848
|
+
// Return false if validation fails
|
|
849
|
+
if (!selectedRow.value) {
|
|
850
|
+
return false;
|
|
851
|
+
}
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Expose the validate method to the parent
|
|
856
|
+
defineExpose({ validate });
|
|
857
|
+
</script>
|
|
858
|
+
```
|
|
859
|
+
|
|
464
860
|
### Step Validation
|
|
465
861
|
|
|
466
862
|
Multi-step forms include built-in validation that prevents users from proceeding to the next step until the current step is valid:
|
|
@@ -517,30 +913,24 @@ The `submit` event provides both the combined data from all steps and the per-st
|
|
|
517
913
|
```typescript
|
|
518
914
|
// multi-step data structure
|
|
519
915
|
multiStepData: MultiStepFormData = {
|
|
520
|
-
|
|
916
|
+
formData: {
|
|
521
917
|
personal: { firstName: 'John', lastName: 'Doe' },
|
|
522
918
|
contact: { email: 'john@example.com', phone: '...' },
|
|
523
919
|
review: { comments: '...' },
|
|
524
920
|
},
|
|
525
|
-
|
|
921
|
+
computedData: {
|
|
526
922
|
/* computed values per step */
|
|
527
923
|
},
|
|
528
|
-
allFormData: {
|
|
529
|
-
/* all form Data raw values */
|
|
530
|
-
},
|
|
531
|
-
allComputedData: {
|
|
532
|
-
/* all form data computed values */
|
|
533
|
-
},
|
|
534
924
|
};
|
|
535
925
|
```
|
|
536
926
|
|
|
537
927
|
## Form Sections
|
|
538
928
|
|
|
539
|
-
Form sections allow you to organize your forms into logical groups with titles and subtitles, making complex forms more readable and user-friendly. Sections are
|
|
929
|
+
Form sections allow you to organize your forms into logical groups with titles and subtitles, making complex forms more readable and user-friendly. Sections are now fully integrated into the FormField interface, providing a unified approach to form building.
|
|
540
930
|
|
|
541
931
|
### Basic Section Usage
|
|
542
932
|
|
|
543
|
-
To create sections in your form, add `FormSection`
|
|
933
|
+
To create sections in your form, add FormField items with `type: 'FormSection'` to your schema alongside regular form fields:
|
|
544
934
|
|
|
545
935
|
```vue
|
|
546
936
|
<template>
|
|
@@ -621,7 +1011,7 @@ function handleSubmit(formData: FormData, computedData: ComputedData) {
|
|
|
621
1011
|
|
|
622
1012
|
### Section Configuration
|
|
623
1013
|
|
|
624
|
-
Form sections support the following configuration options:
|
|
1014
|
+
Form sections are FormField objects with `type: 'FormSection'` and support the following configuration options:
|
|
625
1015
|
|
|
626
1016
|
| Property | Type | Description | Required |
|
|
627
1017
|
| ----------- | --------------- | ------------------------------------------ | -------- |
|
|
@@ -630,6 +1020,9 @@ Form sections support the following configuration options:
|
|
|
630
1020
|
| `subtitle` | `string` | Optional subtitle for additional context | |
|
|
631
1021
|
| `className` | `string` | Optional CSS class for custom styling | |
|
|
632
1022
|
| `grid` | `GridSize` | Grid layout configuration for the section | |
|
|
1023
|
+
| `label` | `string` | Alternative to `title` for section header | |
|
|
1024
|
+
|
|
1025
|
+
> **Note**: For sections, you can use either `title` or `label` for the section header. The `title` property is recommended for clarity, but `label` is supported for consistency with other form fields.
|
|
633
1026
|
|
|
634
1027
|
#### Grid Configuration
|
|
635
1028
|
|
|
@@ -676,11 +1069,13 @@ You can customize section appearance using the `className` property and your own
|
|
|
676
1069
|
|
|
677
1070
|
#### Important Notes
|
|
678
1071
|
|
|
1072
|
+
- **Unified Interface**: Form sections are now part of the FormField interface, providing a consistent API for all form elements
|
|
679
1073
|
- **Data Handling**: Form sections are display-only components and do not contribute to form data
|
|
680
1074
|
- **Validation**: Sections cannot have validation rules as they don't hold values
|
|
681
1075
|
- **Order**: Sections will appear in the form in the order they're defined in your schema
|
|
682
1076
|
- **Multi-Step Compatibility**: Sections work seamlessly within multi-step forms
|
|
683
1077
|
- **Responsive**: Sections automatically adapt to different screen sizes using Ionic's grid system
|
|
1078
|
+
- **Custom Styling**: Use the `className` property to apply custom CSS classes to sections
|
|
684
1079
|
|
|
685
1080
|
## Form Events
|
|
686
1081
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/BaseInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BaseInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/BaseInput.vue"],"names":[],"mappings":"AAgCA;AA2EA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAMhE,KAAK,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,IAAI,CAAC,EAAE,cAAc,CAAA;CAAE,CAAC;AAElE,QAAA,MAAM,KAAK,iEAAoE,CAAC;AAwChF,KAAK,iBAAiB,GAAG;IACzB,UAAU,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;CAClC,GAAG,WAAW,CAAC;;;;;;;;;;;;;;;;;;;;AAkKhB,wBAUG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckboxInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/CheckboxInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CheckboxInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/CheckboxInput.vue"],"names":[],"mappings":"AAgBA;AAyDA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKhD,KAAK,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3C,QAAA,MAAM,KAAK,iEAAoE,CAAC;AAYhF,iBAAS,OAAO,SAIf;AAsBD,KAAK,iBAAiB,GAAG;IACzB,UAAU,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;CAClC,GAAG,WAAW,CAAC;;;;;;;;;;;;;;;;;;;AAuFhB,wBAUG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RadioInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/RadioInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RadioInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/RadioInput.vue"],"names":[],"mappings":"AA2BA;AAmFA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAU,MAAM,SAAS,CAAC;AAKxD,KAAK,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3C,QAAA,MAAM,KAAK,iEAAoE,CAAC;AAYhF,iBAAS,OAAO,SAIf;AAqCD,KAAK,iBAAiB,GAAG;IACzB,UAAU,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;CAClC,GAAG,WAAW,CAAC;;;;;;;;;;;;;;;;;;;AAiIhB,wBAUG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RepeatInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/RepeatInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RepeatInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/RepeatInput.vue"],"names":[],"mappings":"AAwDA;AAgLA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAU,MAAM,SAAS,CAAC;AAOhF,UAAU,MAAM;IACd,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,KAAK,WAAW,GAAG,MAAM,CAAC;AAE1B,QAAA,MAAM,KAAK,iEAAoE,CAAC;AA2ChF,iBAAS,OAAO,SAEf;AAED,iBAAS,SAAS,aAEjB;AAED,iBAAe,aAAa,kBAE3B;AAiBD,KAAK,iBAAiB,GAAG;IACzB,UAAU,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;CAClC,GAAG,WAAW,CAAC;;;;;;;;;;;;AA0OhB,wBASG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/SelectInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SelectInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/SelectInput.vue"],"names":[],"mappings":"AA6DA;AAqeA,OAAO,EAAiB,QAAQ,EAA6C,MAAM,KAAK,CAAC;AAEzF,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAU,MAAM,SAAS,CAAC;AAwFxE,iBAAS,OAAO,SAMf;AAkJD,iBAAe,aAAa,CAAC,GAAG,CAAC,EAAE,GAAG,iBAgBrC;;YAwamB,QAAQ,CAAC,UAAU,CAAC;UACtB,QAAQ,CAAC,cAAc,CAAC;;;;;;;;;;;;YADtB,QAAQ,CAAC,UAAU,CAAC;UACtB,QAAQ,CAAC,cAAc,CAAC;;;;;;;;;;;;;;;;;;AAX1C,wBAiBG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TextAreaInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/TextAreaInput.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TextAreaInput.vue.d.ts","sourceRoot":"","sources":["../../../src/components/inputs/TextAreaInput.vue"],"names":[],"mappings":"AA8BA;AAkEA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKhD,KAAK,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3C,QAAA,MAAM,KAAK,iEAAoE,CAAC;AAiChF,KAAK,iBAAiB,GAAG;IACzB,UAAU,CAAC,EAAE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC;CAClC,GAAG,WAAW,CAAC;;;;;;;;;;;;;;;;;;;AA2HhB,wBAUG"}
|
|
@@ -50,6 +50,7 @@ declare const _default: import('vue').DefineComponent<FormProps, {
|
|
|
50
50
|
cancelButtonText: string;
|
|
51
51
|
hideButtons: boolean;
|
|
52
52
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
53
|
+
customComponentRef: unknown;
|
|
53
54
|
dynamicRefs: unknown[];
|
|
54
55
|
}, HTMLDivElement>;
|
|
55
56
|
export default _default;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vForm.vue.d.ts","sourceRoot":"","sources":["../../src/components/vForm.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vForm.vue.d.ts","sourceRoot":"","sources":["../../src/components/vForm.vue"],"names":[],"mappings":"AA6LA;AA2nBA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,eAAe,EACf,iBAAiB,EAClB,MAAM,SAAS,CAAC;AAOjB,UAAU,SAAS;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;CACrC;AAqHD,iBAAS,iBAAiB,SAOzB;AAiBD,iBAAe,cAAc,kBAyB5B;AAED,iBAAe,kBAAkB,kBAOhC;AAED,iBAAe,eAAe,CAAC,SAAS,EAAE,MAAM,iBA2B/C;;;;;;;;;;;;;;;;;;;;;;;;;;gBArNc,OAAO;qBACF,OAAO;sBACN,OAAO;qBACR,OAAO,GAAG,QAAQ,GAAG,KAAK;sBACzB,MAAM;qBACP,MAAM;sBACL,MAAM;iBACX,OAAO;;;;;AAi7BvB,wBAWG"}
|
|
@@ -5,14 +5,13 @@ export declare function useMultiStepForm(config: MultiStepConfig): {
|
|
|
5
5
|
stepData: import('vue').Ref<Record<string, FormData>, Record<string, FormData>>;
|
|
6
6
|
stepComputedData: import('vue').Ref<Record<string, ComputedData>, Record<string, ComputedData>>;
|
|
7
7
|
stepValidationErrors: import('vue').Ref<Record<string, string[]>, Record<string, string[]>>;
|
|
8
|
+
visibleSteps: import('vue').ComputedRef<FormStep[]>;
|
|
8
9
|
isFirstStep: import('vue').ComputedRef<boolean>;
|
|
9
10
|
isLastStep: import('vue').ComputedRef<boolean>;
|
|
10
11
|
canGoNext: import('vue').ComputedRef<boolean>;
|
|
11
12
|
canGoPrevious: import('vue').ComputedRef<boolean>;
|
|
12
13
|
totalSteps: import('vue').ComputedRef<number>;
|
|
13
14
|
progressPercentage: import('vue').ComputedRef<number>;
|
|
14
|
-
allFormData: import('vue').ComputedRef<FormData>;
|
|
15
|
-
allComputedData: import('vue').ComputedRef<ComputedData>;
|
|
16
15
|
updateStepData: (stepId: string, data: FormData) => void;
|
|
17
16
|
updateStepComputedData: (stepId: string, data: ComputedData) => void;
|
|
18
17
|
clearStepData: (stepId: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMultiStepForm.d.ts","sourceRoot":"","sources":["../../src/composables/useMultiStepForm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGpG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe
|
|
1
|
+
{"version":3,"file":"useMultiStepForm.d.ts","sourceRoot":"","sources":["../../src/composables/useMultiStepForm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGpG,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe;;;;;;;;;;;;;6BAoFtB,MAAM,QAAQ,QAAQ;qCAId,MAAM,QAAQ,YAAY;4BAInC,MAAM;+BASC,OAAO,CAAC,OAAO,CAAC;0BAqBnB,MAAM,KAAG,OAAO,CAAC,OAAO,CAAC;oBAiBjC,OAAO,CAAC,OAAO,CAAC;wBAQZ,OAAO,CAAC,OAAO,CAAC;;4BAiBZ,OAAO,CAAC,OAAO,CAAC;gCAoBlB,iBAAiB;EAoCnD"}
|