srcdev-nuxt-forms 2.0.2 → 2.0.4
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/composables/useZodValidation.ts +1 -0
- package/package.json +19 -2
- package/.editorconfig +0 -12
- package/.eslintignore +0 -7
- package/.eslintrc.cjs +0 -12
- package/.nmprc +0 -2
- package/.nuxtrc +0 -1
- package/.playground/components/scaffolding/footer/NavFooter.vue +0 -62
- package/.playground/components/ui/content-grid/ContentGrid.vue +0 -85
- package/.playground/composables/useApiRequest.ts +0 -25
- package/.playground/composables/useErrorMessages.ts +0 -59
- package/.playground/composables/useFormControl.ts +0 -248
- package/.playground/composables/useSleep.ts +0 -5
- package/.playground/composables/useStyleClassPassthrough.ts +0 -30
- package/.playground/composables/useZodValidation.ts +0 -120
- package/.playground/layouts/default.vue +0 -72
- package/.playground/nuxt.config.ts +0 -27
- package/.playground/pages/forms/examples/buttons/index.vue +0 -155
- package/.playground/pages/forms/examples/material/cssbattle.vue +0 -60
- package/.playground/pages/forms/examples/material/text-fields.vue +0 -594
- package/.playground/pages/index.vue +0 -33
- package/.playground/pages/limit-text.vue +0 -43
- package/.playground/pages/typography.vue +0 -83
- package/.playground/server/api/places/list.get.ts +0 -23
- package/.playground/server/api/textFields.post.ts +0 -37
- package/.playground/server/api/utils/index.get.ts +0 -20
- package/.playground/server/data/places/cities.json +0 -43
- package/.playground/server/data/places/countries.json +0 -55
- package/.playground/server/data/utils/title.json +0 -49
- package/.playground/types/types.places.ts +0 -8
- package/.prettierrc +0 -5
- package/.release-it.json +0 -6
- package/tsconfig.json +0 -3
- /package/{.playground/types → types}/types.forms.ts +0 -0
- /package/{.playground/types → types}/types.zodFormControl.ts +0 -0
|
@@ -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>
|