@volverjs/form-vue 1.0.0-beta.2 → 1.0.0-beta.21

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  <div align="center">
2
-
2
+
3
3
  [![volverjs](docs/static/volverjs-form.svg)](https://volverjs.github.io/form-vue)
4
4
 
5
5
  ## @volverjs/form-vue
@@ -10,11 +10,11 @@
10
10
 
11
11
  <br>
12
12
 
13
- #### proudly powered by
13
+ maintained with ❤️ by
14
14
 
15
15
  <br>
16
16
 
17
- [![24/Consulting](docs/static/24consulting.svg)](https://24consulting.it)
17
+ [![8 Wave](docs/static/8wave.svg)](https://8wave.it)
18
18
 
19
19
  <br>
20
20
 
@@ -47,17 +47,17 @@ import { createForm } from '@volverjs/form-vue'
47
47
  import { z } from 'zod'
48
48
 
49
49
  const schema = z.object({
50
- firstName: z.string(),
51
- lastName: z.string()
50
+ firstName: z.string(),
51
+ lastName: z.string()
52
52
  })
53
53
 
54
54
  const app = createApp(App)
55
55
  const form = createForm({
56
- schema
57
- // lazyLoad: boolean - default false
58
- // updateThrottle: number - default 500
59
- // continuosValidation: boolean - default false
60
- // sideEffects?: (data: any) => void
56
+ schema
57
+ // lazyLoad: boolean - default false
58
+ // updateThrottle: number - default 500
59
+ // continuousValidation: boolean - default false
60
+ // sideEffects?: (data: any) => void
61
61
  })
62
62
 
63
63
  app.use(form)
@@ -73,19 +73,21 @@ A `valid` or `invalid` event is emitted when the form status changes.
73
73
 
74
74
  ```vue
75
75
  <script lang="ts" setup>
76
- const onSubmit = (formData) => {
76
+ function onSubmit(formData) {
77
77
  // ...
78
- }
79
- const onInvalid = (errors) => {
78
+ }
79
+ function onInvalid(errors) {
80
80
  // ...
81
- }
81
+ }
82
82
  </script>
83
83
 
84
84
  <template>
85
- <VvForm @submit="onSubmit" @invalid="onInvalid">
86
- <!-- ... -->
87
- <button type="submit">Submit</button>
88
- </VvForm>
85
+ <VvForm @submit="onSubmit" @invalid="onInvalid">
86
+ <!-- ... -->
87
+ <button type="submit">
88
+ Submit
89
+ </button>
90
+ </VvForm>
89
91
  </template>
90
92
  ```
91
93
 
@@ -93,23 +95,25 @@ The submit can be triggered programmatically with the `submit()` method.
93
95
 
94
96
  ```vue
95
97
  <script lang="ts" setup>
96
- import { ref } from 'vue'
97
- import type { FormComponent } from '@volverjs/form-vue'
98
+ import { ref } from 'vue'
99
+ import type { FormComponent } from '@volverjs/form-vue'
98
100
 
99
- const formEl = ref<InstanceType<FormComponent>>(null)
100
- const onSubmit = (formData) => {
101
+ const formEl = ref<InstanceType<FormComponent>>(null)
102
+ function onSubmit(formData) {
101
103
  // ...
102
- }
103
- const submitForm = () => {
104
+ }
105
+ function submitForm() {
104
106
  formEl.value.submit()
105
- }
107
+ }
106
108
  </script>
107
109
 
108
110
  <template>
109
- <VvForm @submit="onSubmit" ref="formEl">
111
+ <VvForm ref="formEl" @submit="onSubmit">
110
112
  <!-- ... -->
111
- </VvForm>
112
- <button type="button" @click.stop="submitForm">Submit</button>
113
+ </VvForm>
114
+ <button type="button" @click.stop="submitForm">
115
+ Submit
116
+ </button>
113
117
  </template>
114
118
  ```
115
119
 
@@ -118,22 +122,22 @@ Use the `v-model` directive (or only `:model-value` to set the initial value of
118
122
  The form data two way binding is **throttled** by default (500ms) to avoid performance issues. The throttle can be changed with the `updateThrottle` option or prop.
119
123
 
120
124
  By default form validation **stops** when a **valid state** is reached.
121
- To activate **continuos validation** use the `continuosValidation` option or prop.
125
+ To activate **continuous validation** use the `continuousValidation` option or prop.
122
126
 
123
127
  ```vue
124
128
  <script lang="ts" setup>
125
- import { ref } from 'vue'
129
+ import { ref } from 'vue'
126
130
 
127
- const formData = ref({
131
+ const formData = ref({
128
132
  firstName: '',
129
133
  lastName: ''
130
- })
134
+ })
131
135
  </script>
132
136
 
133
137
  <template>
134
- <VvForm v-model="formData" :update-throttle="1000" continuos-validation>
138
+ <VvForm v-model="formData" :update-throttle="1000" continuous-validation>
135
139
  <!-- ... -->
136
- </VvForm>
140
+ </VvForm>
137
141
  </template>
138
142
  ```
139
143
 
@@ -144,27 +148,27 @@ The **default settings** are **inherited** from the plugin (if it's installed).
144
148
 
145
149
  ```vue
146
150
  <script lang="ts" setup>
147
- import { useForm } from '@volverjs/form-vue'
148
- import { z } from 'zod'
151
+ import { useForm } from '@volverjs/form-vue'
152
+ import { z } from 'zod'
149
153
 
150
- const schema = z.object({
154
+ const schema = z.object({
151
155
  firstName: z.string(),
152
156
  lastName: z.string()
153
- })
157
+ })
154
158
 
155
- const { VvForm, VvFormWrapper, VvFormField } = useForm(schema, {
159
+ const { VvForm, VvFormWrapper, VvFormField } = useForm(schema, {
156
160
  // lazyLoad: boolean - default false
157
161
  // updateThrottle: number - default 500
158
- // continuosValidation: boolean - default false
162
+ // continuousValidation: boolean - default false
159
163
  // sideEffects?: (formData: any) => void
160
- })
164
+ })
161
165
  </script>
162
166
 
163
167
  <template>
164
- <VvForm>
165
- <VvFormField type="text" name="firstName" label="First Name" />
166
- <VvFormField type="text" name="lastName" label="Last Name" />
167
- </VvForm>
168
+ <VvForm>
169
+ <VvFormField type="text" name="firstName" label="First Name" />
170
+ <VvFormField type="text" name="lastName" label="Last Name" />
171
+ </VvForm>
168
172
  </template>
169
173
  ```
170
174
 
@@ -177,30 +181,30 @@ import { useForm } from '@volverjs/form-vue'
177
181
  import { z } from 'zod'
178
182
 
179
183
  const schema = z.object({
180
- name: z.string(),
181
- surname: z.string()
184
+ name: z.string(),
185
+ surname: z.string()
182
186
  })
183
187
 
184
188
  const {
185
- VvForm,
186
- VvFormWrapper,
187
- VvFormField,
188
- VvFormTemplate,
189
- formData,
190
- status,
191
- errors
189
+ VvForm,
190
+ VvFormWrapper,
191
+ VvFormField,
192
+ VvFormTemplate,
193
+ formData,
194
+ status,
195
+ errors
192
196
  } = useForm(schema, {
193
- lazyLoad: true
197
+ lazyLoad: true
194
198
  })
195
199
 
196
200
  export default {
197
- VvForm,
198
- VvFormWrapper,
199
- VvFormField,
200
- VvFormTemplate,
201
- formData,
202
- status,
203
- errors
201
+ VvForm,
202
+ VvFormWrapper,
203
+ VvFormField,
204
+ VvFormTemplate,
205
+ formData,
206
+ status,
207
+ errors
204
208
  }
205
209
  ```
206
210
 
@@ -211,20 +215,20 @@ The wrapper status is invalid if at least one of the fields inside it is invalid
211
215
 
212
216
  ```vue
213
217
  <template>
214
- <VvForm>
215
- <VvFormWrapper v-slot="{ invalid }">
216
- <div class="form-section-1">
217
- <span v-if="invalid">There is a validation error</span>
218
- <!-- form fields of section 1 -->
219
- </div>
220
- </VvFormWrapper>
221
- <VvFormWrapper v-slot="{ invalid }">
222
- <div class="form-section-2">
223
- <span v-if="invalid">There is a validation error</span>
224
- <!-- form fields of the section 2 -->
225
- </div>
226
- </VvFormWrapper>
227
- </VvForm>
218
+ <VvForm>
219
+ <VvFormWrapper v-slot="{ invalid }">
220
+ <div class="form-section-1">
221
+ <span v-if="invalid">There is a validation error</span>
222
+ <!-- form fields of section 1 -->
223
+ </div>
224
+ </VvFormWrapper>
225
+ <VvFormWrapper v-slot="{ invalid }">
226
+ <div class="form-section-2">
227
+ <span v-if="invalid">There is a validation error</span>
228
+ <!-- form fields of the section 2 -->
229
+ </div>
230
+ </VvFormWrapper>
231
+ </VvForm>
228
232
  </template>
229
233
  ```
230
234
 
@@ -232,20 +236,20 @@ The wrapper status is invalid if at least one of the fields inside it is invalid
232
236
 
233
237
  ```vue
234
238
  <template>
235
- <VvForm>
236
- <VvFormWrapper v-slot="{ invalid }">
237
- <div class="form-section">
238
- <span v-if="invalid">There is a validation error</span>
239
- <!-- form fields of section -->
240
- <VvFormWrapper v-slot="{ invalid: groupInvalid }">
241
- <div class="form-section__group">
242
- <span v-if="groupInvalid">There is a validation error</span>
243
- <!-- form fields of the group -->
244
- </div>
239
+ <VvForm>
240
+ <VvFormWrapper v-slot="{ invalid }">
241
+ <div class="form-section">
242
+ <span v-if="invalid">There is a validation error</span>
243
+ <!-- form fields of section -->
244
+ <VvFormWrapper v-slot="{ invalid: groupInvalid }">
245
+ <div class="form-section__group">
246
+ <span v-if="groupInvalid">There is a validation error</span>
247
+ <!-- form fields of the group -->
248
+ </div>
249
+ </VvFormWrapper>
250
+ </div>
245
251
  </VvFormWrapper>
246
- </div>
247
- </VvFormWrapper>
248
- </VvForm>
252
+ </VvForm>
249
253
  </template>
250
254
  ```
251
255
 
@@ -257,26 +261,26 @@ It automatically bind the form data through the `name` attribute. For nested obj
257
261
 
258
262
  ```vue
259
263
  <template>
260
- <VvForm>
261
- <VvFormField
262
- v-slot="{ modelValue, invalid, invalidLabel, onUpdate }"
263
- name="lastName"
264
- >
265
- <label for="lastName">Last Name</label>
266
- <input
267
- id="lastName"
268
- type="text"
269
- name="lastName"
270
- :value="modelValue"
271
- :aria-invalid="invalid"
272
- :aria-errormessage="invalid ? 'last-name-alert' : undefined"
273
- @input="onUpdate"
274
- />
275
- <small v-if="invalid" role="alert" id="last-name-alert">
276
- {{ invalidLabel }}
277
- </small>
278
- </VvFormField>
279
- </VvForm>
264
+ <VvForm>
265
+ <VvFormField
266
+ v-slot="{ modelValue, invalid, invalidLabel, onUpdate }"
267
+ name="lastName"
268
+ >
269
+ <label for="lastName">Last Name</label>
270
+ <input
271
+ id="lastName"
272
+ type="text"
273
+ name="lastName"
274
+ :value="modelValue"
275
+ :aria-invalid="invalid"
276
+ :aria-errormessage="invalid ? 'last-name-alert' : undefined"
277
+ @input="onUpdate"
278
+ >
279
+ <small v-if="invalid" id="last-name-alert" role="alert">
280
+ {{ invalidLabel }}
281
+ </small>
282
+ </VvFormField>
283
+ </VvForm>
280
284
  </template>
281
285
  ```
282
286
 
@@ -285,10 +289,10 @@ By default UI components must be installed globally, they can be lazy-loaded wit
285
289
 
286
290
  ```vue
287
291
  <template>
288
- <VvForm>
289
- <VvFormField type="text" name="username" label="Username" lazy-load />
290
- <VvFormField type="password" name="password" label="Password" lazy-load />
291
- </VvForm>
292
+ <VvForm>
293
+ <VvFormField type="text" name="username" label="Username" lazy-load />
294
+ <VvFormField type="password" name="password" label="Password" lazy-load />
295
+ </VvForm>
292
296
  </template>
293
297
  ```
294
298
 
@@ -300,68 +304,68 @@ Forms can also be created using a template. A template is an **array of objects*
300
304
 
301
305
  ```vue
302
306
  <script lang="ts" setup>
303
- import { useForm } from '@volverjs/form-vue'
304
- import { z } from 'zod'
307
+ import { useForm } from '@volverjs/form-vue'
308
+ import { z } from 'zod'
305
309
 
306
- const schema = z.object({
310
+ const schema = z.object({
307
311
  firstName: z.string(),
308
312
  lastName: z.string(),
309
313
  address: z.object({
310
- street: z.string(),
311
- number: z.string(),
312
- city: z.string(),
313
- zip: z.number()
314
+ street: z.string(),
315
+ number: z.string(),
316
+ city: z.string(),
317
+ zip: z.number()
314
318
  })
315
- })
319
+ })
316
320
 
317
- const templateSchema = [
321
+ const templateSchema = [
318
322
  {
319
- vvName: 'firstName',
320
- vvType: 'text',
321
- label: 'First Name'
323
+ vvName: 'firstName',
324
+ vvType: 'text',
325
+ label: 'First Name'
322
326
  },
323
327
  {
324
- vvName: 'lastName',
325
- vvType: 'text',
326
- label: 'Last Name'
328
+ vvName: 'lastName',
329
+ vvType: 'text',
330
+ label: 'Last Name'
327
331
  },
328
332
  {
329
- vvIs: 'div',
330
- class: 'grid grid-col-3 gap-4',
331
- vvChildren: [
332
- {
333
- vvName: 'address.street',
334
- vvType: 'text',
335
- label: 'Street',
336
- class: 'col-span-2'
337
- },
338
- {
339
- vvName: 'address.number',
340
- vvType: 'text',
341
- label: 'Number'
342
- },
343
- {
344
- vvName: 'address.city',
345
- vvType: 'text',
346
- label: 'City'
347
- class: 'col-span-2',
348
- },
349
- {
350
- vvName: 'address.zip',
351
- vvType: 'number',
352
- label: 'Zip'
353
- }
354
- ]
333
+ vvIs: 'div',
334
+ class: 'grid grid-col-3 gap-4',
335
+ vvChildren: [
336
+ {
337
+ vvName: 'address.street',
338
+ vvType: 'text',
339
+ label: 'Street',
340
+ class: 'col-span-2'
341
+ },
342
+ {
343
+ vvName: 'address.number',
344
+ vvType: 'text',
345
+ label: 'Number'
346
+ },
347
+ {
348
+ vvName: 'address.city',
349
+ vvType: 'text',
350
+ label: 'City',
351
+ class: 'col-span-2',
352
+ },
353
+ {
354
+ vvName: 'address.zip',
355
+ vvType: 'number',
356
+ label: 'Zip'
357
+ }
358
+ ]
355
359
  }
356
- ]
360
+ ]
357
361
 
358
- const { VvForm, VvFormTemplate } = useForm(schema)
362
+ const { VvForm, VvFormTemplate } = useForm(schema)
359
363
  </script>
360
364
 
361
365
  <template>
362
- <VvForm>
363
- <VvFormTemplate :schema="templateSchema" />
364
- </VvForm>
366
+ <VvForm>
367
+ <VvFormTemplate :schema="templateSchema" />
368
+ </VvForm>
365
369
  </template>
366
370
  ```
367
371
 
@@ -378,69 +382,69 @@ Conditional rendering can be achieved using the `vvIf` and `vvElseIf` properties
378
382
 
379
383
  ```vue
380
384
  <script lang="ts" setup>
381
- import { useForm } from '@volverjs/form-vue'
382
- import { z } from 'zod'
385
+ import { useForm } from '@volverjs/form-vue'
386
+ import { z } from 'zod'
383
387
 
384
- const schema = z.object({
388
+ const schema = z.object({
385
389
  firstName: z.string(),
386
390
  lastName: z.string(),
387
391
  hasUsername: z.boolean(),
388
- username: z.string().optional()
392
+ username: z.string().optional(),
389
393
  email: z.string().email().optional()
390
- }).superRefine((value, ctx) => {
394
+ }).superRefine((value, ctx) => {
391
395
  if (value.hasUsername && !value.username) {
392
- ctx.addIssue({
393
- code: z.ZodIssueCode.custom,
394
- message: 'Username is required'
395
- })
396
+ ctx.addIssue({
397
+ code: z.ZodIssueCode.custom,
398
+ message: 'Username is required'
399
+ })
396
400
  }
397
401
  if (!value.hasUsername && !value.email) {
398
- ctx.addIssue({
399
- code: z.ZodIssueCode.custom,
400
- message: 'Email is required'
401
- })
402
+ ctx.addIssue({
403
+ code: z.ZodIssueCode.custom,
404
+ message: 'Email is required'
405
+ })
402
406
  }
403
- })
407
+ })
404
408
 
405
- const templateSchema = [
409
+ const templateSchema = [
406
410
  {
407
- vvName: 'firstName',
408
- vvType: 'text',
409
- label: 'First Name'
411
+ vvName: 'firstName',
412
+ vvType: 'text',
413
+ label: 'First Name'
410
414
  },
411
415
  {
412
- vvName: 'lastName',
413
- vvType: 'text',
414
- label: 'Last Name'
416
+ vvName: 'lastName',
417
+ vvType: 'text',
418
+ label: 'Last Name'
415
419
  },
416
420
  {
417
- vvName: 'hasUsername',
418
- vvType: 'checkbox',
419
- label: 'Has Username'
420
- value: true,
421
- uncheckedValue: false
421
+ vvName: 'hasUsername',
422
+ vvType: 'checkbox',
423
+ label: 'Has Username',
424
+ value: true,
425
+ uncheckedValue: false
422
426
  },
423
427
  {
424
- vvIf: 'hasUsername',
425
- vvName: 'username',
426
- vvType: 'text',
427
- label: 'Username'
428
+ vvIf: 'hasUsername',
429
+ vvName: 'username',
430
+ vvType: 'text',
431
+ label: 'Username'
428
432
  },
429
433
  {
430
- vvElseIf: true,
431
- vvName: 'email',
432
- vvType: 'email',
433
- label: 'Email'
434
+ vvElseIf: true,
435
+ vvName: 'email',
436
+ vvType: 'email',
437
+ label: 'Email'
434
438
  }
435
- ]
439
+ ]
436
440
 
437
- const { VvForm, VvFormTemplate } = useForm(schema)
441
+ const { VvForm, VvFormTemplate } = useForm(schema)
438
442
  </script>
439
443
 
440
444
  <template>
441
- <VvForm>
442
- <VvFormTemplate :schema="templateSchema" />
443
- </VvForm>
445
+ <VvForm>
446
+ <VvFormTemplate :schema="templateSchema" />
447
+ </VvForm>
444
448
  </template>
445
449
  ```
446
450
 
@@ -449,39 +453,43 @@ Conditional rendering can be achieved using the `vvIf` and `vvElseIf` properties
449
453
  `vvIf` and `vvElseIf` can be a string or a function. If it is a string it will be evaluated as a **property** of the form data. If it is a function it will be called with the **form context** as the **first argument** and must return a boolean.
450
454
 
451
455
  ```ts
452
- {
453
- vvIf: (ctx) => ctx.formData.value.hasUsername,
454
- vvName: 'username',
455
- vvType: 'text',
456
- label: 'Username'
457
- }
456
+ const templateSchema = [
457
+ {
458
+ vvIf: ctx => ctx.formData.value.hasUsername,
459
+ vvName: 'username',
460
+ vvType: 'text',
461
+ label: 'Username'
462
+ }
463
+ ]
458
464
  ```
459
465
 
460
466
  Also the template schema and all template items can be a function.
461
467
  The function will be called with the **form context** as the **first argument**.
462
468
 
463
469
  ```ts
464
- const templateSchema = (ctx) => [
465
- {
466
- vvName: 'firstName',
467
- vvType: 'text',
468
- label: `Hi ${ctx.formData.value.firstName}!`
469
- }
470
- ]
470
+ function templateSchema(ctx) {
471
+ return [
472
+ {
473
+ vvName: 'firstName',
474
+ vvType: 'text',
475
+ label: `Hi ${ctx.formData.value.firstName}!`
476
+ }
477
+ ]
478
+ }
471
479
  ```
472
480
 
473
481
  ```ts
474
482
  const templateSchema = [
475
- (ctx) => ({
476
- vvName: 'firstName',
477
- vvType: 'text',
478
- label: `Hi ${ctx.formData.value.firstName}!`
479
- }),
480
- {
481
- vvName: 'username',
482
- type: 'text',
483
- label: 'username'
484
- }
483
+ ctx => ({
484
+ vvName: 'firstName',
485
+ vvType: 'text',
486
+ label: `Hi ${ctx.formData.value.firstName}!`
487
+ }),
488
+ {
489
+ vvName: 'username',
490
+ type: 'text',
491
+ label: 'username'
492
+ }
485
493
  ]
486
494
  ```
487
495
 
@@ -495,8 +503,8 @@ import { z } from 'zod'
495
503
  import { defaultObjectBySchema } from '@volverjs/form-vue'
496
504
 
497
505
  const schema = z.object({
498
- name: z.string().default('John'),
499
- surname: z.string().default('Doe')
506
+ name: z.string().default('John'),
507
+ surname: z.string().default('Doe')
500
508
  })
501
509
 
502
510
  const defaultObject = defaultObjectBySchema(schema)
@@ -513,12 +521,12 @@ import { z } from 'zod'
513
521
  import { defaultObjectBySchema } from '@volverjs/form-vue'
514
522
 
515
523
  const schema = z.object({
516
- name: z.string().default('John'),
517
- surname: z.string().default('Doe'),
518
- address: z.object({
519
- street: z.string().default('Main Street'),
520
- number: z.number().default(1)
521
- })
524
+ name: z.string().default('John'),
525
+ surname: z.string().default('Doe'),
526
+ address: z.object({
527
+ street: z.string().default('Main Street'),
528
+ number: z.number().default(1)
529
+ })
522
530
  })
523
531
 
524
532
  const defaultObject = defaultObjectBySchema(schema)
@@ -532,22 +540,22 @@ import { z } from 'zod'
532
540
  import { defaultObjectBySchema } from '@volverjs/form-vue'
533
541
 
534
542
  const schema = z
535
- .object({
536
- name: z.string().default('John'),
537
- surname: z.string().default('Doe'),
538
- address: z.object({
539
- street: z.string().default('Main Street'),
540
- number: z.number().default(1)
541
- }),
542
- age: z.number().nullable().default(null),
543
- height: z.coerce.number().default(1.8),
544
- weight: z.number().default(80)
545
- })
546
- .passthrough()
543
+ .object({
544
+ name: z.string().default('John'),
545
+ surname: z.string().default('Doe'),
546
+ address: z.object({
547
+ street: z.string().default('Main Street'),
548
+ number: z.number().default(1)
549
+ }),
550
+ age: z.number().nullable().default(null),
551
+ height: z.coerce.number().default(1.8),
552
+ weight: z.number().default(80)
553
+ })
554
+ .passthrough()
547
555
 
548
556
  const defaultObject = defaultObjectBySchema(schema, {
549
- height: '1.9',
550
- email: 'john.doe@test.com'
557
+ height: '1.9',
558
+ email: 'john.doe@test.com'
551
559
  })
552
560
  // defaultObject = { name: 'John', surname: 'Doe', address: { street: 'Main Street', number: 1 }, age: null, height: 1.9, weight: 80, email: 'john.doe@test.com' }
553
561
  ```