srcdev-nuxt-forms 0.2.0 → 1.0.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/assets/styles/brand/_brand.css +150 -0
- package/assets/styles/brand/_brand_dark.css +152 -0
- package/assets/styles/brand/_palette_dark.css +148 -0
- package/assets/styles/brand/_palette_light.css +148 -0
- package/assets/styles/brand/_typography.css +176 -0
- package/assets/styles/brand/index.css +1 -0
- package/assets/styles/forms/index.css +1 -2
- package/assets/styles/forms/themes/_default.css +3 -0
- package/assets/styles/forms/themes/_error.css +45 -11
- package/assets/styles/forms/themes/_ghost.css +42 -10
- package/assets/styles/forms/themes/_primary.css +42 -12
- package/assets/styles/forms/themes/_secondary.css +42 -12
- package/assets/styles/forms/themes/_success.css +42 -11
- package/assets/styles/forms/themes/_tertiary.css +42 -10
- package/assets/styles/forms/themes/_warning.css +42 -10
- package/assets/styles/forms/themes/index.css +1 -0
- package/assets/styles/forms/variables/_palette.css +104 -0
- package/assets/styles/forms/variables/_theme.css +1 -1
- package/assets/styles/forms/variables/index.css +2 -0
- package/assets/styles/main.css +2 -0
- package/assets/styles/scaffolding/_margin-helpers.css +308 -0
- package/assets/styles/scaffolding/_padding-helpers.css +308 -0
- package/assets/styles/scaffolding/_page.css +23 -0
- package/assets/styles/scaffolding/index.css +3 -0
- package/assets/styles/variables/colors/_blue.css +2 -2
- package/assets/styles/variables/colors/_gray.css +1 -1
- package/assets/styles/variables/colors/_green.css +2 -2
- package/assets/styles/variables/colors/_orange.css +2 -2
- package/assets/styles/variables/colors/_red.css +2 -2
- package/assets/styles/variables/colors/_yellow.css +1 -1
- package/components/forms/form-errors/InputError.vue +82 -37
- package/components/forms/input-button/InputButtonCore.vue +25 -104
- package/components/forms/input-checkbox/InputCheckboxCore.vue +37 -181
- package/components/forms/input-checkbox/InputCheckboxWithLabel.vue +42 -51
- package/components/forms/input-checkbox/variants/MultipleCheckboxes.vue +42 -69
- package/components/forms/input-checkbox/variants/SingleCheckbox.vue +126 -111
- package/components/forms/input-number/InputNumberCore.vue +184 -0
- package/components/forms/input-number/variants/InputNumberDefault.vue +155 -0
- package/components/forms/input-radio/InputRadiobuttonCore.vue +212 -0
- package/components/forms/input-radio/InputRadiobuttonWithLabel.vue +103 -0
- package/components/forms/input-radio/variants/MultipleRadiobuttons.vue +166 -0
- package/components/forms/input-range/InputRangeCore.vue +70 -88
- package/components/forms/input-range/variants/InputRangeDefault.vue +74 -46
- package/components/forms/input-text/InputTextCore.vue +141 -109
- package/components/forms/input-text/variants/material/InputPasswordWithLabel.vue +99 -0
- package/components/forms/input-text/variants/material/InputTextAsNumberWithLabel.vue +142 -0
- package/components/forms/input-text/variants/material/InputTextWithLabel.vue +125 -0
- package/components/forms/input-textarea/InputTextareaCore.vue +96 -105
- package/components/forms/input-textarea/variants/InputTextareaWithLabel.vue +106 -0
- package/components/scaffolding/footer/NavFooter.vue +62 -0
- package/composables/useApiRequest.ts +25 -0
- package/composables/useFormControl.ts +2 -0
- package/composables/useSleep.ts +2 -2
- package/composables/useStyleClassPassthrough.ts +30 -0
- package/composables/useZodValidation.ts +120 -0
- package/layouts/default.vue +21 -5
- package/package.json +13 -9
- package/pages/forms/examples/material/cssbattle.vue +60 -0
- package/pages/forms/examples/material/text-fields.vue +375 -153
- package/pages/index.vue +2 -2
- package/pages/typography.vue +83 -0
- package/server/data/places/cities.json +7 -1
- package/types/types.forms.ts +102 -0
- package/types/types.zodFormControl.ts +21 -0
- package/assets/styles/forms/utils/_a11y.css +0 -5
- package/assets/styles/forms/utils/index.css +0 -1
- package/components/forms/input-radio/InputRadioCore.vue +0 -226
- package/components/forms/input-radio/InputRadioWithLabel.vue +0 -118
- package/components/forms/input-radio/variants/MultipleRadio.vue +0 -183
- package/components/forms/input-radio/variants/SingleRadio.vue +0 -131
- package/components/forms/input-text/variants/material/InputEmailMaterial.vue +0 -72
- package/components/forms/input-text/variants/material/InputPasswordMaterial.vue +0 -114
- package/components/forms/input-text/variants/material/InputTextMaterial.vue +0 -68
- package/components/forms/input-text/variants/material/InputTextMaterialCore.vue +0 -313
- package/components/forms/input-textarea/variants/material/InputTextareaMaterial.vue +0 -75
- package/components/forms/input-textarea/variants/material/InputTextareaMaterialCore.vue +0 -290
- package/composables/useUpdateStyleClassPassthrough.ts +0 -29
|
@@ -3,18 +3,8 @@
|
|
|
3
3
|
<NuxtLayout name="default">
|
|
4
4
|
<template #layout-content>
|
|
5
5
|
<div>
|
|
6
|
-
<h1>Material UI text fields ({{ compact ? 'compact' : 'default' }})</h1>
|
|
7
|
-
<
|
|
8
|
-
<li>
|
|
9
|
-
<InputButtonSubmit type="button" @click.stop.prevent="swapCompact(false)" button-text="Use Default UI" theme="secondary" size="normal" />
|
|
10
|
-
</li>
|
|
11
|
-
<li>
|
|
12
|
-
<InputButtonSubmit type="button" @click.stop.prevent="swapCompact(true)" button-text="Use Compact UI" theme="secondary" size="normal" />
|
|
13
|
-
</li>
|
|
14
|
-
</ul>
|
|
15
|
-
|
|
16
|
-
<p>Example test fields in default material UI</p>
|
|
17
|
-
<p>Use 'test@test.com' to trigger server errors</p>
|
|
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>
|
|
18
8
|
</div>
|
|
19
9
|
<ContentGrid>
|
|
20
10
|
<template #slot1>
|
|
@@ -25,77 +15,148 @@
|
|
|
25
15
|
<div aria-live="assertive" id="aria-live-message"></div>
|
|
26
16
|
<FormField width="wide" :has-gutter="false">
|
|
27
17
|
<template #default>
|
|
28
|
-
<
|
|
18
|
+
<InputTextWithLabel
|
|
19
|
+
v-model="state.emailAddress"
|
|
20
|
+
type="email"
|
|
21
|
+
:maxlength="fieldMaxLength('email')"
|
|
29
22
|
id="emailAddress"
|
|
30
23
|
name="emailAddress"
|
|
31
|
-
|
|
24
|
+
placeholder="eg. name@domain.com"
|
|
25
|
+
label="Email address"
|
|
26
|
+
:errorMessage="formErrors?.emailAddress?._errors[0] ?? ''"
|
|
27
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.emailAddress)"
|
|
32
28
|
:required="true"
|
|
33
|
-
:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
:compact
|
|
41
|
-
/>
|
|
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>
|
|
42
36
|
</template>
|
|
43
37
|
</FormField>
|
|
44
38
|
|
|
45
39
|
<FormField width="wide" :has-gutter="false">
|
|
46
40
|
<template #default>
|
|
47
|
-
<
|
|
41
|
+
<InputTextWithLabel
|
|
42
|
+
v-model="state.username"
|
|
43
|
+
type="text"
|
|
44
|
+
:maxlength="fieldMaxLength('username')"
|
|
48
45
|
id="username"
|
|
49
46
|
name="username"
|
|
50
|
-
|
|
47
|
+
placeholder="eg. name@domain.com"
|
|
48
|
+
label="Username"
|
|
49
|
+
:errorMessage="formErrors?.username?._errors[0] ?? ''"
|
|
50
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.username)"
|
|
51
51
|
:required="true"
|
|
52
|
-
:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
:compact
|
|
60
|
-
/>
|
|
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>
|
|
61
59
|
</template>
|
|
62
60
|
</FormField>
|
|
63
61
|
|
|
64
62
|
<FormField width="wide" :has-gutter="false">
|
|
65
63
|
<template #default>
|
|
66
|
-
<
|
|
64
|
+
<InputPasswordWithLabel
|
|
65
|
+
v-model="state.password"
|
|
66
|
+
:maxlength="fieldMaxLength('password')"
|
|
67
67
|
id="password"
|
|
68
68
|
name="password"
|
|
69
|
-
|
|
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)"
|
|
70
73
|
:required="true"
|
|
71
|
-
:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
:compact
|
|
79
|
-
/>
|
|
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>
|
|
80
81
|
</template>
|
|
81
82
|
</FormField>
|
|
82
83
|
|
|
83
84
|
<FormField width="wide" :has-gutter="false">
|
|
84
85
|
<template #default>
|
|
85
|
-
<
|
|
86
|
+
<InputTextareaWithLabel
|
|
87
|
+
v-model="state.message"
|
|
88
|
+
:maxlength="fieldMaxLength('message')"
|
|
86
89
|
id="message"
|
|
87
90
|
name="message"
|
|
88
|
-
|
|
91
|
+
placeholder="Type your message here"
|
|
92
|
+
label="Your mesage"
|
|
93
|
+
:errorMessage="formErrors?.message?._errors[0] ?? ''"
|
|
94
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.message)"
|
|
89
95
|
:required="true"
|
|
90
|
-
:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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>
|
|
99
160
|
</template>
|
|
100
161
|
</FormField>
|
|
101
162
|
|
|
@@ -104,28 +165,66 @@
|
|
|
104
165
|
<InputRangeDefault
|
|
105
166
|
id="score"
|
|
106
167
|
name="score"
|
|
168
|
+
label="Score between 0 & 100"
|
|
107
169
|
:min="0"
|
|
108
170
|
:max="100"
|
|
109
|
-
:step="
|
|
171
|
+
:step="10"
|
|
172
|
+
placeholder="eg. What\'s your score?"
|
|
173
|
+
:errorMessage="formErrors?.score?._errors[0] ?? ''"
|
|
174
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.score)"
|
|
110
175
|
:required="true"
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
placeholder: 'eg. What\'s your score?',
|
|
115
|
-
errorMessage: 'Score between 0 & 100',
|
|
116
|
-
}"
|
|
117
|
-
v-model="formData"
|
|
118
|
-
theme="secondary"
|
|
176
|
+
:styleClassPassthrough="['style-1', 'style-2']"
|
|
177
|
+
v-model.number="state.score"
|
|
178
|
+
theme="primary"
|
|
119
179
|
>
|
|
120
180
|
<template #description>
|
|
121
181
|
<p class="label-description">This is a description of what the user is required to do</p>
|
|
122
182
|
</template>
|
|
123
|
-
<template #
|
|
124
|
-
|
|
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>
|
|
125
198
|
</InputRangeDefault>
|
|
126
199
|
</template>
|
|
127
200
|
</FormField>
|
|
128
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
|
+
|
|
129
228
|
<FormField v-if="citiesData !== null" width="wide" :has-gutter="false">
|
|
130
229
|
<template #default>
|
|
131
230
|
<MultipleCheckboxes
|
|
@@ -133,17 +232,17 @@
|
|
|
133
232
|
name="cities"
|
|
134
233
|
legend="Choose a location"
|
|
135
234
|
:required="true"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
v-model="formData"
|
|
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"
|
|
142
240
|
v-model:fieldData="citiesData"
|
|
143
|
-
theme="secondary"
|
|
144
241
|
size="normal"
|
|
145
|
-
checkbox-style="
|
|
242
|
+
checkbox-style="cross"
|
|
146
243
|
checkbox-appearance="with-decorator"
|
|
244
|
+
optionsLayout="inline"
|
|
245
|
+
theme="primary"
|
|
147
246
|
>
|
|
148
247
|
<template #description>
|
|
149
248
|
<p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
|
|
@@ -159,18 +258,17 @@
|
|
|
159
258
|
name="countries"
|
|
160
259
|
legend="Choose a country"
|
|
161
260
|
:required="true"
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
v-model="formData"
|
|
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"
|
|
168
266
|
v-model:fieldData="countriesData"
|
|
169
|
-
theme="secondary"
|
|
170
267
|
size="normal"
|
|
171
|
-
|
|
172
|
-
checkbox-style="cross"
|
|
268
|
+
checkbox-style="check"
|
|
173
269
|
checkbox-appearance="with-decorator"
|
|
270
|
+
optionsLayout="equal-widths"
|
|
271
|
+
theme="primary"
|
|
174
272
|
>
|
|
175
273
|
<template #description>
|
|
176
274
|
<p class="label-description">This is description: optionsLayout = 'inline'</p>
|
|
@@ -179,29 +277,46 @@
|
|
|
179
277
|
</template>
|
|
180
278
|
</FormField>
|
|
181
279
|
|
|
182
|
-
<FormField
|
|
280
|
+
<FormField width="wide" :has-gutter="false">
|
|
183
281
|
<template #default>
|
|
184
|
-
<
|
|
185
|
-
id="
|
|
186
|
-
name="
|
|
187
|
-
legend="
|
|
282
|
+
<SingleCheckbox
|
|
283
|
+
id="agreed"
|
|
284
|
+
name="agreed"
|
|
285
|
+
legend="I agree (label with description)"
|
|
286
|
+
label="Click to agree to something"
|
|
188
287
|
:required="true"
|
|
189
|
-
:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
errorMessage: 'Please select a title',
|
|
193
|
-
}"
|
|
194
|
-
v-model="formData"
|
|
195
|
-
v-model:fieldData="titleData"
|
|
196
|
-
theme="secondary"
|
|
288
|
+
:errorMessage="formErrors?.agreed?._errors[0] ?? ''"
|
|
289
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.agreed)"
|
|
290
|
+
v-model="state.agreed"
|
|
197
291
|
size="normal"
|
|
198
|
-
|
|
199
|
-
|
|
292
|
+
checkbox-style="check"
|
|
293
|
+
checkbox-appearance="with-decorator"
|
|
294
|
+
theme="primary"
|
|
200
295
|
>
|
|
201
296
|
<template #description>
|
|
202
|
-
<p class="label-description">
|
|
297
|
+
<p class="label-description">You must <strong>agree</strong> to continue</p>
|
|
203
298
|
</template>
|
|
204
|
-
</
|
|
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>
|
|
205
320
|
</template>
|
|
206
321
|
</FormField>
|
|
207
322
|
|
|
@@ -210,21 +325,18 @@
|
|
|
210
325
|
<SingleCheckbox
|
|
211
326
|
id="terms"
|
|
212
327
|
name="terms"
|
|
213
|
-
legend="
|
|
328
|
+
legend="Terms and conditions"
|
|
214
329
|
:required="true"
|
|
215
|
-
:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
errorMessage: 'Please accept our terms and conditions',
|
|
219
|
-
}"
|
|
220
|
-
v-model="formData"
|
|
221
|
-
theme="secondary"
|
|
330
|
+
:errorMessage="formErrors?.terms?._errors[0] ?? ''"
|
|
331
|
+
:fieldHasError="Boolean(zodFormControl.submitAttempted && formErrors?.terms)"
|
|
332
|
+
v-model="state.terms"
|
|
222
333
|
size="normal"
|
|
223
|
-
checkbox-appearance="with-decorator"
|
|
224
334
|
checkbox-style="check"
|
|
335
|
+
checkbox-appearance="with-decorator"
|
|
336
|
+
theme="primary"
|
|
225
337
|
>
|
|
226
|
-
<template #
|
|
227
|
-
<
|
|
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>
|
|
228
340
|
</template>
|
|
229
341
|
</SingleCheckbox>
|
|
230
342
|
</template>
|
|
@@ -232,7 +344,15 @@
|
|
|
232
344
|
|
|
233
345
|
<FormField width="wide" :has-gutter="false">
|
|
234
346
|
<template #default>
|
|
235
|
-
<InputButtonSubmit
|
|
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
|
+
/>
|
|
236
356
|
</template>
|
|
237
357
|
</FormField>
|
|
238
358
|
</form>
|
|
@@ -242,9 +362,18 @@
|
|
|
242
362
|
</template>
|
|
243
363
|
<template #slot2>
|
|
244
364
|
<ClientOnly>
|
|
245
|
-
<p>Client only
|
|
365
|
+
<p>Client only state</p>
|
|
246
366
|
<pre>
|
|
247
|
-
{{
|
|
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 }}
|
|
248
377
|
</pre>
|
|
249
378
|
</ClientOnly>
|
|
250
379
|
</template>
|
|
@@ -255,7 +384,8 @@
|
|
|
255
384
|
</template>
|
|
256
385
|
|
|
257
386
|
<script setup lang="ts">
|
|
258
|
-
import
|
|
387
|
+
import { z, ZodError } from 'zod';
|
|
388
|
+
import type { IFieldsInitialState, TFieldsInitialState, IOptionsConfig, IFormMultipleOptions } from '@/types/types.forms';
|
|
259
389
|
|
|
260
390
|
definePageMeta({
|
|
261
391
|
layout: false,
|
|
@@ -284,46 +414,143 @@ const { data: titleData } = await useFetch<IFormMultipleOptions>('/api/utils?cat
|
|
|
284
414
|
/*
|
|
285
415
|
* Setup forms
|
|
286
416
|
*/
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
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({
|
|
290
499
|
emailAddress: '',
|
|
291
|
-
// username: "",
|
|
292
500
|
username: '',
|
|
293
|
-
// password: "!+Password123",
|
|
294
501
|
password: '',
|
|
295
502
|
message: '',
|
|
296
|
-
|
|
503
|
+
count: 25,
|
|
504
|
+
count2: 25,
|
|
297
505
|
score: 50,
|
|
298
506
|
cities: [],
|
|
299
507
|
countries: [],
|
|
300
|
-
title:
|
|
508
|
+
title: '',
|
|
509
|
+
agreed: false,
|
|
510
|
+
agree: false,
|
|
301
511
|
terms: false,
|
|
302
512
|
});
|
|
303
513
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
514
|
+
const {
|
|
515
|
+
initZodForm,
|
|
516
|
+
zodFormControl,
|
|
517
|
+
zodErrorObj,
|
|
518
|
+
// formErrors,
|
|
519
|
+
pushCustomErrors,
|
|
520
|
+
doZodValidate,
|
|
521
|
+
fieldMaxLength,
|
|
522
|
+
} = useZodValidation(formSchema);
|
|
307
523
|
|
|
308
|
-
|
|
524
|
+
initZodForm();
|
|
525
|
+
|
|
526
|
+
const submitForm = async () => {
|
|
527
|
+
zodFormControl.submitAttempted = true;
|
|
528
|
+
if (!(await doZodValidate(state))) return;
|
|
529
|
+
zodFormControl.displayLoader = true;
|
|
309
530
|
try {
|
|
531
|
+
console.log('Form valid - post it');
|
|
310
532
|
const data = await $fetch('/api/textFields', {
|
|
311
533
|
method: 'post',
|
|
312
|
-
body:
|
|
313
|
-
onResponse({ response }) {
|
|
534
|
+
body: state,
|
|
535
|
+
async onResponse({ response }) {
|
|
314
536
|
if (response.status === 400) {
|
|
315
537
|
console.log('onResponse', response);
|
|
316
538
|
console.log(response.status);
|
|
317
539
|
|
|
318
|
-
useApiErrors(response._data.data.errors);
|
|
540
|
+
// useApiErrors(response._data.data.errors);
|
|
319
541
|
// for (const [key, message] of Object.entries(response._data.data.errors)) {
|
|
320
542
|
// console.log(`${key}: ${message}`);
|
|
321
543
|
// updateErrorMessages(key, message);
|
|
322
544
|
// }
|
|
545
|
+
|
|
546
|
+
// if (error instanceof Error) {
|
|
547
|
+
await pushCustomErrors(response._data, state);
|
|
548
|
+
// zodFormControl.formIsValid = false;
|
|
549
|
+
// }
|
|
550
|
+
// zodFormControl.submitAttempted = false;
|
|
323
551
|
}
|
|
324
552
|
if (response.status === 200) {
|
|
325
|
-
|
|
326
|
-
formData.value.submitSuccess = true;
|
|
553
|
+
zodFormControl.submitSuccessful = true;
|
|
327
554
|
}
|
|
328
555
|
},
|
|
329
556
|
});
|
|
@@ -331,29 +558,19 @@ async function postFormData() {
|
|
|
331
558
|
// return data;
|
|
332
559
|
} catch (error) {
|
|
333
560
|
console.warn('2: An error occured posting form data', error);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const submitForm = async () => {
|
|
338
|
-
getErrorCount(true);
|
|
339
|
-
|
|
340
|
-
if (formIsValid.value) {
|
|
341
|
-
formData.value.isPending = true;
|
|
342
|
-
formData.value.submitDisabled = true;
|
|
343
|
-
console.log('Form is good - post it!');
|
|
344
|
-
|
|
345
|
-
postFormData();
|
|
346
|
-
|
|
347
|
-
// formData.value.errorMessages['emailAddress'] = {
|
|
348
|
-
// useCustomError: true,
|
|
349
|
-
// message: 'This is a custom error message',
|
|
350
|
-
// };
|
|
351
|
-
|
|
352
|
-
// executePost();
|
|
353
|
-
} else {
|
|
354
|
-
console.warn('Form has errors');
|
|
561
|
+
} finally {
|
|
562
|
+
zodFormControl.displayLoader = false;
|
|
355
563
|
}
|
|
356
564
|
};
|
|
565
|
+
|
|
566
|
+
watch(
|
|
567
|
+
() => state,
|
|
568
|
+
() => {
|
|
569
|
+
// console.log('Watching state');
|
|
570
|
+
doZodValidate(state);
|
|
571
|
+
},
|
|
572
|
+
{ deep: true }
|
|
573
|
+
);
|
|
357
574
|
</script>
|
|
358
575
|
|
|
359
576
|
<style lang="css">
|
|
@@ -369,4 +586,9 @@ ul.flex-group {
|
|
|
369
586
|
list-style-type: none;
|
|
370
587
|
padding: 0;
|
|
371
588
|
}
|
|
589
|
+
|
|
590
|
+
.header-1 {
|
|
591
|
+
font-family: var(--font-family);
|
|
592
|
+
color: var(--brand-success-text-text);
|
|
593
|
+
}
|
|
372
594
|
</style>
|