srcdev-nuxt-forms 2.0.3 → 2.0.5

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 (35) hide show
  1. package/composables/useZodValidation.ts +1 -1
  2. package/package.json +21 -3
  3. package/.editorconfig +0 -12
  4. package/.eslintignore +0 -7
  5. package/.eslintrc.cjs +0 -12
  6. package/.nmprc +0 -2
  7. package/.nuxtrc +0 -1
  8. package/.playground/components/scaffolding/footer/NavFooter.vue +0 -62
  9. package/.playground/components/ui/content-grid/ContentGrid.vue +0 -85
  10. package/.playground/composables/useApiRequest.ts +0 -25
  11. package/.playground/composables/useErrorMessages.ts +0 -59
  12. package/.playground/composables/useFormControl.ts +0 -248
  13. package/.playground/composables/useSleep.ts +0 -5
  14. package/.playground/composables/useStyleClassPassthrough.ts +0 -30
  15. package/.playground/composables/useZodValidation.ts +0 -120
  16. package/.playground/layouts/default.vue +0 -72
  17. package/.playground/nuxt.config.ts +0 -27
  18. package/.playground/pages/forms/examples/buttons/index.vue +0 -155
  19. package/.playground/pages/forms/examples/material/cssbattle.vue +0 -60
  20. package/.playground/pages/forms/examples/material/text-fields.vue +0 -594
  21. package/.playground/pages/index.vue +0 -33
  22. package/.playground/pages/limit-text.vue +0 -43
  23. package/.playground/pages/typography.vue +0 -83
  24. package/.playground/server/api/places/list.get.ts +0 -23
  25. package/.playground/server/api/textFields.post.ts +0 -37
  26. package/.playground/server/api/utils/index.get.ts +0 -20
  27. package/.playground/server/data/places/cities.json +0 -43
  28. package/.playground/server/data/places/countries.json +0 -55
  29. package/.playground/server/data/utils/title.json +0 -49
  30. package/.playground/types/types.forms.ts +0 -216
  31. package/.playground/types/types.places.ts +0 -8
  32. package/.playground/types/types.zodFormControl.ts +0 -21
  33. package/.prettierrc +0 -5
  34. package/.release-it.json +0 -6
  35. package/tsconfig.json +0 -3
@@ -1,594 +0,0 @@
1
- <template>
2
- <div>
3
- <NuxtLayout name="default">
4
- <template #layout-content>
5
- <div>
6
- <h1 class="header-1">Material UI text fields ({{ compact ? 'compact' : 'default' }})</h1>
7
- <p class="body-normal">Use 'test@test.com' to trigger server errors</p>
8
- </div>
9
- <ContentGrid>
10
- <template #slot1>
11
- <FormWrapper width="medium">
12
- <template #default>
13
- <ClientOnly>
14
- <form class="form-wrapper" @submit.stop.prevent="submitForm()">
15
- <div aria-live="assertive" id="aria-live-message"></div>
16
- <FormField width="wide" :has-gutter="false">
17
- <template #default>
18
- <InputTextWithLabel
19
- v-model="state.emailAddress"
20
- type="email"
21
- :maxlength="fieldMaxLength('email')"
22
- id="emailAddress"
23
- name="emailAddress"
24
- placeholder="eg. name@domain.com"
25
- label="Email address"
26
- :errorMessage="formErrors?.emailAddress?._errors[0] ?? ''"
27
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.emailAddress)"
28
- :required="true"
29
- :styleClassPassthrough="['style-1', 'style-2']"
30
- theme="primary"
31
- >
32
- <template #left>
33
- <Icon name="radix-icons:envelope-closed" class="icon" />
34
- </template>
35
- </InputTextWithLabel>
36
- </template>
37
- </FormField>
38
-
39
- <FormField width="wide" :has-gutter="false">
40
- <template #default>
41
- <InputTextWithLabel
42
- v-model="state.username"
43
- type="text"
44
- :maxlength="fieldMaxLength('username')"
45
- id="username"
46
- name="username"
47
- placeholder="eg. name@domain.com"
48
- label="Username"
49
- :errorMessage="formErrors?.username?._errors[0] ?? ''"
50
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.username)"
51
- :required="true"
52
- :styleClassPassthrough="['style-1', 'style-2']"
53
- theme="primary"
54
- >
55
- <template #left>
56
- <Icon name="radix-icons:person" class="icon" />
57
- </template>
58
- </InputTextWithLabel>
59
- </template>
60
- </FormField>
61
-
62
- <FormField width="wide" :has-gutter="false">
63
- <template #default>
64
- <InputPasswordWithLabel
65
- v-model="state.password"
66
- :maxlength="fieldMaxLength('password')"
67
- id="password"
68
- name="password"
69
- placeholder="eg. a mixure of numbers and letters"
70
- label="Password"
71
- :errorMessage="formErrors?.password?._errors[0] ?? ''"
72
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.password)"
73
- :required="true"
74
- :styleClassPassthrough="['style-1', 'style-2']"
75
- theme="primary"
76
- >
77
- <template #right>
78
- <Icon name="radix-icons:eye-open" class="icon" />
79
- </template>
80
- </InputPasswordWithLabel>
81
- </template>
82
- </FormField>
83
-
84
- <FormField width="wide" :has-gutter="false">
85
- <template #default>
86
- <InputTextareaWithLabel
87
- v-model="state.message"
88
- :maxlength="fieldMaxLength('message')"
89
- id="message"
90
- name="message"
91
- placeholder="Type your message here"
92
- label="Your mesage"
93
- :errorMessage="formErrors?.message?._errors[0] ?? ''"
94
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.message)"
95
- :required="true"
96
- :styleClassPassthrough="['style-1', 'style-2']"
97
- >
98
- </InputTextareaWithLabel>
99
- </template>
100
- </FormField>
101
-
102
- <FormField width="wide" :has-gutter="false">
103
- <template #default>
104
- <InputTextAsNumberWithLabel
105
- v-model.number="state.count2"
106
- :maxlength="fieldMaxLength('count2')"
107
- :min="25"
108
- :max="75"
109
- :step="5"
110
- id="count2"
111
- name="count2"
112
- placeholder="eg. 10"
113
- label="How many things? Between 25 & 75"
114
- :errorMessage="formErrors?.count2?._errors[0] ?? ''"
115
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.count2)"
116
- :required="true"
117
- :styleClassPassthrough="['style-1', 'style-2']"
118
- theme="primary"
119
- >
120
- <template #description>
121
- <p class="label-description">Input type="text" inputmode="numeric"</p>
122
- </template>
123
- <template #left>
124
- <Icon name="gridicons:minus-small" class="icon" />
125
- </template>
126
- <template #right>
127
- <Icon name="gridicons:plus-small" class="icon" />
128
- </template>
129
- </InputTextAsNumberWithLabel>
130
- </template>
131
- </FormField>
132
-
133
- <FormField width="wide" :has-gutter="false">
134
- <template #default>
135
- <InputNumberDefault
136
- id="count"
137
- name="count"
138
- label="How many things? Between 25 & 75 , step 5"
139
- :min="25"
140
- :max="75"
141
- :step="5"
142
- placeholder="eg. What\'s your count?"
143
- :errorMessage="formErrors?.count?._errors[0] ?? ''"
144
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.count)"
145
- :required="true"
146
- :styleClassPassthrough="['count-1', 'count-2']"
147
- v-model.number="state.count"
148
- theme="primary"
149
- >
150
- <template #description>
151
- <p class="label-description">Input type="number" inputmode="numeric"</p>
152
- </template>
153
- <template #left>
154
- <Icon name="gridicons:minus-small" class="icon" />
155
- </template>
156
- <template #right>
157
- <Icon name="gridicons:plus-small" class="icon" />
158
- </template>
159
- </InputNumberDefault>
160
- </template>
161
- </FormField>
162
-
163
- <FormField width="wide" :has-gutter="false">
164
- <template #default>
165
- <InputRangeDefault
166
- id="score"
167
- name="score"
168
- label="Score between 0 & 100"
169
- :min="0"
170
- :max="100"
171
- :step="10"
172
- placeholder="eg. What\'s your score?"
173
- :errorMessage="formErrors?.score?._errors[0] ?? ''"
174
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.score)"
175
- :required="true"
176
- :styleClassPassthrough="['style-1', 'style-2']"
177
- v-model.number="state.score"
178
- theme="primary"
179
- >
180
- <template #description>
181
- <p class="label-description">This is a description of what the user is required to do</p>
182
- </template>
183
- <template #datalist>
184
- <datalist class="input-range-datalist" id="score-datalist">
185
- <option value="0" label="Rubbish!"></option>
186
- <option value="25" label="Below par"></option>
187
- <option value="50" label="Average"></option>
188
- <option value="75" label="Quite good"></option>
189
- <option value="100" label="Excellent"></option>
190
- </datalist>
191
- </template>
192
- <template #left>
193
- <Icon name="gridicons:minus-small" class="icon" />
194
- </template>
195
- <template #right>
196
- <Icon name="gridicons:plus-small" class="icon" />
197
- </template>
198
- </InputRangeDefault>
199
- </template>
200
- </FormField>
201
-
202
- <FormField v-if="titleData !== null" width="wide" :has-gutter="false">
203
- <template #default>
204
- <MultipleRadiobuttons
205
- id="title"
206
- name="title"
207
- legend="What is your title"
208
- :required="true"
209
- label="Check one"
210
- placeholder="eg. Type something here"
211
- :errorMessage="formErrors?.title?._errors[0] ?? ''"
212
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.title)"
213
- v-model="state.title"
214
- v-model:fieldData="titleData"
215
- size="normal"
216
- checkbox-style="cross"
217
- checkbox-appearance="with-decorator"
218
- optionsLayout="equal-widths"
219
- theme="primary"
220
- >
221
- <template #description>
222
- <p class="label-description">This is description: optionsLayout = 'equal-widths/inline'</p>
223
- </template>
224
- </MultipleRadiobuttons>
225
- </template>
226
- </FormField>
227
-
228
- <FormField v-if="citiesData !== null" width="wide" :has-gutter="false">
229
- <template #default>
230
- <MultipleCheckboxes
231
- id="cities"
232
- name="cities"
233
- legend="Choose a location"
234
- :required="true"
235
- label="Check all Cities you like"
236
- placeholder="eg. Type something here"
237
- :errorMessage="formErrors?.cities?._errors[0] ?? ''"
238
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.cities)"
239
- v-model="state.cities"
240
- v-model:fieldData="citiesData"
241
- size="normal"
242
- checkbox-style="cross"
243
- checkbox-appearance="with-decorator"
244
- optionsLayout="inline"
245
- theme="primary"
246
- >
247
- <template #description>
248
- <p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
249
- </template>
250
- </MultipleCheckboxes>
251
- </template>
252
- </FormField>
253
-
254
- <FormField v-if="countriesData !== null" width="wide" :has-gutter="false">
255
- <template #default>
256
- <MultipleCheckboxes
257
- id="countries"
258
- name="countries"
259
- legend="Choose a country"
260
- :required="true"
261
- label="Check all Countries you like"
262
- placeholder="eg. Type something here"
263
- :errorMessage="formErrors?.countries?._errors[0] ?? ''"
264
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.countries)"
265
- v-model="state.countries"
266
- v-model:fieldData="countriesData"
267
- size="normal"
268
- checkbox-style="check"
269
- checkbox-appearance="with-decorator"
270
- optionsLayout="equal-widths"
271
- theme="primary"
272
- >
273
- <template #description>
274
- <p class="label-description">This is description: optionsLayout = 'inline'</p>
275
- </template>
276
- </MultipleCheckboxes>
277
- </template>
278
- </FormField>
279
-
280
- <FormField width="wide" :has-gutter="false">
281
- <template #default>
282
- <SingleCheckbox
283
- id="agreed"
284
- name="agreed"
285
- legend="I agree (label with description)"
286
- label="Click to agree to something"
287
- :required="true"
288
- :errorMessage="formErrors?.agreed?._errors[0] ?? ''"
289
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.agreed)"
290
- v-model="state.agreed"
291
- size="normal"
292
- checkbox-style="check"
293
- checkbox-appearance="with-decorator"
294
- theme="primary"
295
- >
296
- <template #description>
297
- <p class="label-description">You must <strong>agree</strong> to continue</p>
298
- </template>
299
- </SingleCheckbox>
300
- </template>
301
- </FormField>
302
-
303
- <FormField width="wide" :has-gutter="false">
304
- <template #default>
305
- <SingleCheckbox
306
- id="agree"
307
- name="agree"
308
- legend="I agree (label no description)"
309
- label="Click to agree to something"
310
- :required="true"
311
- :errorMessage="formErrors?.agree?._errors[0] ?? ''"
312
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.agree)"
313
- v-model="state.agree"
314
- size="normal"
315
- checkbox-style="check"
316
- checkbox-appearance="with-decorator"
317
- theme="primary"
318
- >
319
- </SingleCheckbox>
320
- </template>
321
- </FormField>
322
-
323
- <FormField width="wide" :has-gutter="false">
324
- <template #default>
325
- <SingleCheckbox
326
- id="terms"
327
- name="terms"
328
- legend="Terms and conditions"
329
- :required="true"
330
- :errorMessage="formErrors?.terms?._errors[0] ?? ''"
331
- :fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.terms)"
332
- v-model="state.terms"
333
- size="normal"
334
- checkbox-style="check"
335
- checkbox-appearance="with-decorator"
336
- theme="primary"
337
- >
338
- <template #labelContent>
339
- <span class="body-normal">You must agree to our <NuxtLink to="/typography" class="link-normal">terms and conditions</NuxtLink> to continue</span>
340
- </template>
341
- </SingleCheckbox>
342
- </template>
343
- </FormField>
344
-
345
- <FormField width="wide" :has-gutter="false">
346
- <template #default>
347
- <InputButtonSubmit
348
- type="button"
349
- @click.stop.prevent="submitForm()"
350
- :is-pending="false"
351
- :readonly="zodFormControl.submitDisabled"
352
- button-text="Submit"
353
- theme="primary"
354
- size="medium"
355
- />
356
- </template>
357
- </FormField>
358
- </form>
359
- </ClientOnly>
360
- </template>
361
- </FormWrapper>
362
- </template>
363
- <template #slot2>
364
- <ClientOnly>
365
- <p>Client only state</p>
366
- <pre>
367
- {{ state }}
368
- </pre>
369
- <p>Client only zodFormControl</p>
370
- <pre>
371
- {{ zodFormControl }}
372
- </pre>
373
- <p>Client only formErrors</p>
374
-
375
- <pre>
376
- {{ formErrors }}
377
- </pre>
378
- </ClientOnly>
379
- </template>
380
- </ContentGrid>
381
- </template>
382
- </NuxtLayout>
383
- </div>
384
- </template>
385
-
386
- <script setup lang="ts">
387
- import { z, ZodError } from 'zod';
388
- import type { IFieldsInitialState, TFieldsInitialState, IOptionsConfig, IFormMultipleOptions } from '@/types/types.forms';
389
-
390
- definePageMeta({
391
- layout: false,
392
- });
393
-
394
- useHead({
395
- title: 'Text Field Example',
396
- meta: [{ name: 'description', content: 'Homepage' }],
397
- bodyAttrs: {
398
- class: '',
399
- },
400
- });
401
-
402
- const compact = ref(false);
403
- const swapCompact = (newStyle: boolean) => {
404
- compact.value = newStyle;
405
- };
406
-
407
- /*
408
- * Fetch some sample data
409
- **/
410
- const { data: citiesData } = await useFetch<IFormMultipleOptions>('/api/places/list?category=cities');
411
- const { data: countriesData } = await useFetch<IFormMultipleOptions>('/api/places/list?category=countries');
412
- const { data: titleData } = await useFetch<IFormMultipleOptions>('/api/utils?category=title');
413
-
414
- /*
415
- * Setup forms
416
- */
417
- const formSchema = reactive(
418
- z
419
- .object({
420
- emailAddress: z
421
- .string({
422
- required_error: 'Email address is required',
423
- })
424
- .email({ message: 'Invalid email address' })
425
- .refine((email) => email !== zodFormControl.previousState.emailAddress.value, {
426
- message: 'This email address has already been used',
427
- }),
428
- username: z
429
- .string({
430
- required_error: 'Username is required',
431
- })
432
- .trim()
433
- .min(2, 'Username is too short')
434
- .max(25, 'Username is too long')
435
- .refine((email) => email !== zodFormControl.previousState.username.value, {
436
- message: 'This username has already been used',
437
- }),
438
- password: z
439
- .string()
440
- .trim()
441
- .min(8, 'Password is too short')
442
- .max(25, 'Password is too long')
443
- .refine((email) => email !== zodFormControl.previousState.password.value, {
444
- message: "You've already used this password",
445
- }),
446
- message: z.string().trim().min(2, 'Message is too short').max(255, 'Message is too long'),
447
- count: z
448
- .number({
449
- required_error: 'Count is required',
450
- invalid_type_error: 'Count must be a number',
451
- })
452
- .int({ message: 'Count must be a whole number' })
453
- .gte(25, 'Count must be between 25 and 75')
454
- .lte(75, 'Count must be between 25 and 75')
455
- .multipleOf(5, 'Count must be a multiple of 5'),
456
- count2: z
457
- .number({
458
- required_error: 'Count is required',
459
- invalid_type_error: 'Count must be a number',
460
- })
461
- .int({ message: 'Count must be a whole number' })
462
- .gte(25, 'Count must be between 25 and 75')
463
- .lte(75, 'Count must be between 25 and 75'),
464
- score: z
465
- .number({
466
- required_error: 'Score is required',
467
- invalid_type_error: 'Score must be a number',
468
- })
469
- .gte(0)
470
- .lte(100),
471
- cities: z.array(z.string()).min(1, 'Please select at least one city'),
472
- countries: z.array(z.string()).min(2, 'Please select at least 2 countries').max(5, 'Please select no more than 5 countries'),
473
- title: z.string().min(1, { message: 'Title is required' }),
474
- agreed: z.boolean().refine((val) => val === true, { message: 'You must tick this box' }),
475
- agree: z.boolean().refine((val) => val === true, { message: 'You must tick this box' }),
476
- terms: z.boolean().refine((val) => val === true, { message: 'You must accept our terms' }),
477
- })
478
- .required({
479
- emailAddress: true,
480
- username: true,
481
- password: true,
482
- message: true,
483
- count: true,
484
- count2: true,
485
- score: true,
486
- cities: true,
487
- countries: true,
488
- title: true,
489
- agreed: true,
490
- agree: true,
491
- terms: true,
492
- })
493
- );
494
-
495
- type formSchema = z.infer<typeof formSchema>;
496
- const formErrors = computed<z.ZodFormattedError<formSchema> | null>(() => zodErrorObj.value);
497
-
498
- const state = reactive({
499
- emailAddress: '',
500
- username: '',
501
- password: '',
502
- message: '',
503
- count: 25,
504
- count2: 25,
505
- score: 50,
506
- cities: [],
507
- countries: [],
508
- title: '',
509
- agreed: false,
510
- agree: false,
511
- terms: false,
512
- });
513
-
514
- const {
515
- initZodForm,
516
- zodFormControl,
517
- zodErrorObj,
518
- // formErrors,
519
- pushCustomErrors,
520
- doZodValidate,
521
- fieldMaxLength,
522
- } = useZodValidation(formSchema);
523
-
524
- initZodForm();
525
-
526
- const submitForm = async () => {
527
- zodFormControl.submitAttempted = true;
528
- if (!(await doZodValidate(state))) return;
529
- zodFormControl.displayLoader = true;
530
- try {
531
- console.log('Form valid - post it');
532
- const data = await $fetch('/api/textFields', {
533
- method: 'post',
534
- body: state,
535
- async onResponse({ response }) {
536
- if (response.status === 400) {
537
- console.log('onResponse', response);
538
- console.log(response.status);
539
-
540
- // useApiErrors(response._data.data.errors);
541
- // for (const [key, message] of Object.entries(response._data.data.errors)) {
542
- // console.log(`${key}: ${message}`);
543
- // updateErrorMessages(key, message);
544
- // }
545
-
546
- // if (error instanceof Error) {
547
- await pushCustomErrors(response._data, state);
548
- // zodFormControl.formIsValid = false;
549
- // }
550
- // zodFormControl.submitAttempted = false;
551
- }
552
- if (response.status === 200) {
553
- zodFormControl.submitSuccessful = true;
554
- }
555
- },
556
- });
557
- console.log('3: Finished data', data);
558
- // return data;
559
- } catch (error) {
560
- console.warn('2: An error occured posting form data', error);
561
- } finally {
562
- zodFormControl.displayLoader = false;
563
- }
564
- };
565
-
566
- watch(
567
- () => state,
568
- () => {
569
- // console.log('Watching state');
570
- doZodValidate(state);
571
- },
572
- { deep: true }
573
- );
574
- </script>
575
-
576
- <style lang="css">
577
- .flex-group {
578
- align-items: flex-start;
579
- display: flex;
580
- flex-wrap: wrap;
581
- gap: 24px;
582
- margin-bottom: 32px;
583
- }
584
-
585
- ul.flex-group {
586
- list-style-type: none;
587
- padding: 0;
588
- }
589
-
590
- .header-1 {
591
- font-family: var(--font-family);
592
- color: var(--brand-success-text-text);
593
- }
594
- </style>
@@ -1,33 +0,0 @@
1
- <template>
2
- <div>
3
- <NuxtLayout name="default">
4
- <template #layout-content>
5
- <div>
6
- <h1>Sample form page pages</h1>
7
-
8
- <p>Example test fields in default material UI</p>
9
- </div>
10
- </template>
11
- </NuxtLayout>
12
- </div>
13
- </template>
14
-
15
- <script setup lang="ts">
16
- definePageMeta({
17
- layout: false,
18
- });
19
-
20
- useHead({
21
- title: 'Homepage',
22
- meta: [{ name: 'description', content: 'Homepage' }],
23
- bodyAttrs: {
24
- class: '',
25
- },
26
- });
27
- </script>
28
-
29
- <style lang="css">
30
- /* p {
31
- color: initial;
32
- } */
33
- </style>
@@ -1,43 +0,0 @@
1
- <template>
2
- <div class="wrapper">
3
- <div class="text-wrapper">
4
- <p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
5
- </div>
6
- <div class="text-wrapper">
7
- <p>Nisi harum impedit, expedita eius doloremque dicta obcaecati tempora dolorem eum fuga deserunt minus facere error mollitia pariatur cum tempore, reiciendis molestiae?</p>
8
- </div>
9
- <div class="text-wrapper">
10
- <p>
11
- Lorem ipsum dolor sit amet consectetur adipisicing elit. Nisi harum impedit, expedita eius doloremque dicta obcaecati tempora dolorem eum fuga deserunt minus facere error mollitia pariatur cum
12
- tempore, reiciendis molestiae?
13
- </p>
14
- </div>
15
- </div>
16
- </template>
17
- <script setup lang="ts">
18
- definePageMeta({
19
- layout: false,
20
- });
21
- </script>
22
- <style lang="css">
23
- .wrapper {
24
- display: grid;
25
- grid-template-columns: 1fr 1fr 1fr;
26
- gap: 20px;
27
- }
28
-
29
- .text-wrapper {
30
- max-height: 100px;
31
- width: 200px;
32
- padding: 20px;
33
- outline: 1px solid black;
34
-
35
- p {
36
- display: -webkit-box;
37
- -webkit-box-orient: vertical;
38
- line-clamp: 3;
39
- -webkit-line-clamp: 3;
40
- overflow: hidden;
41
- }
42
- }
43
- </style>