srcdev-nuxt-components 9.3.7 → 9.3.8
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/.claude/hooks/check-component-update.sh +30 -1
- package/.claude/skills/components/breadcrumb.md +49 -0
- package/.claude/skills/components/content-docs.md +1 -1
- package/.claude/skills/components/service-detail.md +156 -0
- package/.claude/skills/components/services-card-grid.md +9 -9
- package/.claude/skills/components/services-card.md +82 -30
- package/.claude/skills/index.md +3 -1
- package/.claude/skills/qa-panel.md +2 -2
- package/.vscode/srcdev-component-breadcrumb.code-snippets +14 -0
- package/.vscode/srcdev-component-service-detail.code-snippets +49 -0
- package/.vscode/srcdev-component-services-card.code-snippets +108 -0
- package/app/components/01.atoms/navigation/breadcrumb/Breadcrumb.vue +94 -0
- package/app/components/01.atoms/navigation/breadcrumb/CONSUMER-STYLING.md +32 -0
- package/app/components/01.atoms/navigation/breadcrumb/stories/Breadcrumb.stories.ts +87 -0
- package/app/components/01.atoms/navigation/breadcrumb/tests/Breadcrumb.spec.ts +87 -0
- package/app/components/01.atoms/navigation/breadcrumb/tests/__snapshots__/Breadcrumb.spec.ts.snap +13 -0
- package/app/components/03.organisms/services/service-detail/CONSUMER-STYLING.md +181 -0
- package/app/components/03.organisms/services/service-detail/ServiceDetail.vue +480 -0
- package/app/components/03.organisms/services/service-detail/stories/ServiceDetail.stories.ts +282 -0
- package/app/components/03.organisms/services/service-detail/tests/ServiceDetail.spec.ts +270 -0
- package/app/components/03.organisms/services/service-detail/tests/__snapshots__/ServiceDetail.spec.ts.snap +99 -0
- package/app/components/03.organisms/services/services-card/CONSUMER-STYLING.md +129 -0
- package/app/components/03.organisms/services/services-card/ServicesCard.vue +153 -39
- package/app/components/03.organisms/services/services-card/stories/ServicesCard.stories.ts +65 -0
- package/app/components/03.organisms/services/services-card/tests/ServicesCard.spec.ts +82 -0
- package/app/components/03.organisms/services/services-card/tests/__snapshots__/ServicesCard.spec.ts.snap +13 -5
- package/app/components/03.organisms/services/services-grids/ServicesCardGrid.vue +3 -7
- package/app/components/03.organisms/services/services-grids/stories/ServicesCardGrid.stories.ts +126 -2
- package/app/components/03.organisms/services/services-grids/stories/ServicesSectionGrid.stories.ts +6 -0
- package/app/components/03.organisms/services/services-grids/tests/__snapshots__/ServicesCardGrid.spec.ts.snap +51 -27
- package/app/types/components/breadcrumb.ts +4 -0
- package/app/types/components/index.ts +1 -0
- package/package.json +2 -2
- package/app/pages/auto-grid.vue +0 -328
- package/app/pages/banner-video.vue +0 -238
- package/app/pages/forms/examples/buttons/index.vue +0 -259
- package/app/pages/forms/examples/material/checkbox-radio-panels.vue +0 -244
- package/app/pages/forms/examples/material/cssbattle.vue +0 -60
- package/app/pages/forms/examples/material/text-fields.vue +0 -910
- package/app/pages/grid-stack.vue +0 -252
- package/app/pages/index.vue +0 -127
- package/app/pages/page-hero-highlights.vue +0 -204
- package/app/pages/samaritan.vue +0 -327
- package/app/pages/typography/hero-text.vue +0 -97
- package/app/pages/typography/index.vue +0 -39
- package/app/pages/typography/page-body.vue +0 -171
- package/app/pages/typography/page-heading.vue +0 -76
- package/app/pages/typography/page-link.vue +0 -103
- package/app/pages/ui/accordian.vue +0 -211
- package/app/pages/ui/anchor-scroll-tab-navigation.vue +0 -191
- package/app/pages/ui/anchor-scroll.vue +0 -367
- package/app/pages/ui/animated-svg-text.vue +0 -85
- package/app/pages/ui/block-decorators.vue +0 -142
- package/app/pages/ui/card-core.vue +0 -82
- package/app/pages/ui/carousel-basic.vue +0 -292
- package/app/pages/ui/carousel-flip.vue +0 -449
- package/app/pages/ui/carousel-infinite.vue +0 -260
- package/app/pages/ui/clipped-panels.vue +0 -101
- package/app/pages/ui/contact-section.vue +0 -323
- package/app/pages/ui/container-glow.vue +0 -106
- package/app/pages/ui/content-width.vue +0 -126
- package/app/pages/ui/deep-expanding-menu.vue +0 -138
- package/app/pages/ui/display-avatar.vue +0 -253
- package/app/pages/ui/display-banner.vue +0 -78
- package/app/pages/ui/display-chip.vue +0 -367
- package/app/pages/ui/display-details.vue +0 -171
- package/app/pages/ui/display-dialog.vue +0 -344
- package/app/pages/ui/display-pill.vue +0 -396
- package/app/pages/ui/display-prompt.vue +0 -284
- package/app/pages/ui/display-toast.vue +0 -311
- package/app/pages/ui/expanding-panel.vue +0 -326
- package/app/pages/ui/glowing-border.vue +0 -111
- package/app/pages/ui/layout-content-docs.vue +0 -72
- package/app/pages/ui/layout-grid-a.vue +0 -96
- package/app/pages/ui/layout-grid-b.vue +0 -132
- package/app/pages/ui/magnetic-navigation.vue +0 -50
- package/app/pages/ui/marquee-scroller.vue +0 -99
- package/app/pages/ui/mask-element.vue +0 -104
- package/app/pages/ui/masonry-columns.vue +0 -55
- package/app/pages/ui/masonry-grid-ordered-experiment.vue +0 -79
- package/app/pages/ui/masonry-grid-ordered.vue +0 -56
- package/app/pages/ui/masonry-grid-sorted.vue +0 -55
- package/app/pages/ui/masonry-grid.vue +0 -55
- package/app/pages/ui/navigation/navigation-horizontal.vue +0 -484
- package/app/pages/ui/navigation/site-navigation/about.vue +0 -36
- package/app/pages/ui/navigation/site-navigation/contact.vue +0 -39
- package/app/pages/ui/navigation/site-navigation/index.vue +0 -38
- package/app/pages/ui/navigation/site-navigation/portfolio.vue +0 -43
- package/app/pages/ui/navigation/site-navigation/services.vue +0 -42
- package/app/pages/ui/navigation/tab-navigation.vue +0 -493
- package/app/pages/ui/page-row.vue +0 -127
- package/app/pages/ui/price-list.vue +0 -65
- package/app/pages/ui/profile-section.vue +0 -142
- package/app/pages/ui/qr-code/[componentName].vue +0 -218
- package/app/pages/ui/rotating-carousel.vue +0 -154
- package/app/pages/ui/scroll-reveal-image.vue +0 -483
- package/app/pages/ui/section-parallax.vue +0 -54
- package/app/pages/ui/services/colour-finder.vue +0 -43
- package/app/pages/ui/services/services-cards.vue +0 -57
- package/app/pages/ui/services/services-section/[slug].vue +0 -61
- package/app/pages/ui/services/services-sections-compact.vue +0 -64
- package/app/pages/ui/settings.vue +0 -54
- package/app/pages/ui/simple-grid.vue +0 -55
- package/app/pages/ui/slider-gallery.vue +0 -261
- package/app/pages/ui/tabs-y.vue +0 -107
- package/app/pages/ui/tabs.vue +0 -189
- package/app/pages/ui/tooltips.vue +0 -104
- package/app/pages/ui/wipe-away-vertical.vue +0 -129
|
@@ -1,910 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<NuxtLayout name="default">
|
|
4
|
-
<template #layout-content>
|
|
5
|
-
<LayoutGridByCols>
|
|
6
|
-
<template #item-0>
|
|
7
|
-
<div>
|
|
8
|
-
<h1 class="header-1">Example form</h1>
|
|
9
|
-
<p class="body-normal">Use 'test@test.com' to trigger server errors</p>
|
|
10
|
-
</div>
|
|
11
|
-
</template>
|
|
12
|
-
</LayoutGridByCols>
|
|
13
|
-
<LayoutGridByCols>
|
|
14
|
-
<template #item-0>
|
|
15
|
-
<div>
|
|
16
|
-
<p>Themes switcher</p>
|
|
17
|
-
<ul class="flex-group">
|
|
18
|
-
<li>
|
|
19
|
-
<InputButtonCore
|
|
20
|
-
type="button"
|
|
21
|
-
:is-pending="false"
|
|
22
|
-
button-text="Default"
|
|
23
|
-
theme="default"
|
|
24
|
-
@click.stop.prevent="swapTheme('default')"
|
|
25
|
-
/>
|
|
26
|
-
</li>
|
|
27
|
-
<li>
|
|
28
|
-
<InputButtonCore
|
|
29
|
-
type="button"
|
|
30
|
-
:is-pending="false"
|
|
31
|
-
button-text="Success"
|
|
32
|
-
theme="success"
|
|
33
|
-
@click.stop.prevent="swapTheme('success')"
|
|
34
|
-
/>
|
|
35
|
-
</li>
|
|
36
|
-
<li>
|
|
37
|
-
<InputButtonCore
|
|
38
|
-
type="button"
|
|
39
|
-
:is-pending="false"
|
|
40
|
-
button-text="Error"
|
|
41
|
-
theme="error"
|
|
42
|
-
@click.stop.prevent="swapTheme('error')"
|
|
43
|
-
/>
|
|
44
|
-
</li>
|
|
45
|
-
<li>
|
|
46
|
-
<InputButtonCore
|
|
47
|
-
type="button"
|
|
48
|
-
:is-pending="false"
|
|
49
|
-
button-text="Warning"
|
|
50
|
-
theme="warning"
|
|
51
|
-
@click.stop.prevent="swapTheme('warning')"
|
|
52
|
-
/>
|
|
53
|
-
</li>
|
|
54
|
-
</ul>
|
|
55
|
-
|
|
56
|
-
<p>Select type of text input to display</p>
|
|
57
|
-
<ul class="flex-group">
|
|
58
|
-
<li>
|
|
59
|
-
<InputButtonCore
|
|
60
|
-
type="button"
|
|
61
|
-
button-text="Normal"
|
|
62
|
-
theme="default"
|
|
63
|
-
@click.stop.prevent="inputVariant = 'normal'"
|
|
64
|
-
/>
|
|
65
|
-
</li>
|
|
66
|
-
<li>
|
|
67
|
-
<InputButtonCore
|
|
68
|
-
type="button"
|
|
69
|
-
button-text="Underlined"
|
|
70
|
-
theme="default"
|
|
71
|
-
@click.stop.prevent="inputVariant = 'underlined'"
|
|
72
|
-
/>
|
|
73
|
-
</li>
|
|
74
|
-
</ul>
|
|
75
|
-
|
|
76
|
-
<PageRow tag="div" variant="popout" :style-class-passthrough="['mbe-20']">
|
|
77
|
-
<h1 class="page-heading-1 mbe-18">Settings</h1>
|
|
78
|
-
<h2 class="page-heading-2 mbe-18">Theme Switcher</h2>
|
|
79
|
-
<DisplayThemeSwitch />
|
|
80
|
-
</PageRow>
|
|
81
|
-
|
|
82
|
-
<FormWrapper width="medium">
|
|
83
|
-
<template #default>
|
|
84
|
-
<ClientOnly>
|
|
85
|
-
<form ref="formRef" class="form-wrapper" @submit.stop.prevent="submitForm()">
|
|
86
|
-
<div id="aria-live-message" aria-live="assertive"></div>
|
|
87
|
-
|
|
88
|
-
<FormField v-if="countriesData !== null" width="wide" :has-gutter="false">
|
|
89
|
-
<template #default>
|
|
90
|
-
<InputSelectWithLabel
|
|
91
|
-
id="countrySelect"
|
|
92
|
-
v-model="state.countrySelect"
|
|
93
|
-
v-model:field-data="countriesData"
|
|
94
|
-
name="countrySelect"
|
|
95
|
-
:required="true"
|
|
96
|
-
label="Where are you from?"
|
|
97
|
-
placeholder="Please select a country"
|
|
98
|
-
:error-message="formErrors?.countrySelect?._errors[0] ?? ''"
|
|
99
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.countrySelect)"
|
|
100
|
-
:theme
|
|
101
|
-
:input-variant
|
|
102
|
-
>
|
|
103
|
-
<template #descriptionText>This is a descriptionText for the message input.</template>
|
|
104
|
-
</InputSelectWithLabel>
|
|
105
|
-
</template>
|
|
106
|
-
</FormField>
|
|
107
|
-
|
|
108
|
-
<FormField width="wide" :has-gutter="false">
|
|
109
|
-
<template #default>
|
|
110
|
-
<InputTextWithLabel
|
|
111
|
-
id="emailAddress"
|
|
112
|
-
v-model="state.emailAddress"
|
|
113
|
-
type="email"
|
|
114
|
-
inputmode="email"
|
|
115
|
-
:maxlength="fieldMaxLength('email')"
|
|
116
|
-
name="emailAddress"
|
|
117
|
-
placeholder="eg. name@domain.com"
|
|
118
|
-
label="Email address"
|
|
119
|
-
:error-message="formErrors?.emailAddress?._errors[0] ?? ''"
|
|
120
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.emailAddress)"
|
|
121
|
-
:required="true"
|
|
122
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
123
|
-
:theme
|
|
124
|
-
:input-variant
|
|
125
|
-
>
|
|
126
|
-
<template #descriptionText>This is a descriptionText for the email input.</template>
|
|
127
|
-
<template #left>
|
|
128
|
-
<Icon name="radix-icons:envelope-closed" class="icon" />
|
|
129
|
-
</template>
|
|
130
|
-
<template #right>
|
|
131
|
-
<Icon name="radix-icons:envelope-closed" class="icon" />
|
|
132
|
-
</template>
|
|
133
|
-
</InputTextWithLabel>
|
|
134
|
-
</template>
|
|
135
|
-
</FormField>
|
|
136
|
-
|
|
137
|
-
<FormField width="wide" :has-gutter="false">
|
|
138
|
-
<template #default>
|
|
139
|
-
<InputTextWithLabel
|
|
140
|
-
id="username"
|
|
141
|
-
v-model="state.username"
|
|
142
|
-
type="text"
|
|
143
|
-
:maxlength="fieldMaxLength('username')"
|
|
144
|
-
name="username"
|
|
145
|
-
placeholder="eg. JoeBloggs1"
|
|
146
|
-
label="Username"
|
|
147
|
-
:error-message="formErrors?.username?._errors[0] ?? ''"
|
|
148
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.username)"
|
|
149
|
-
:required="true"
|
|
150
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
151
|
-
:theme
|
|
152
|
-
:input-variant
|
|
153
|
-
>
|
|
154
|
-
<template #descriptionHtml>
|
|
155
|
-
<p class="mbs-4 mbe-8" style="font-weight: 900">
|
|
156
|
-
This is a descriptionHtml for the email input.
|
|
157
|
-
</p>
|
|
158
|
-
</template>
|
|
159
|
-
<template #left>
|
|
160
|
-
<Icon name="radix-icons:person" class="icon" />
|
|
161
|
-
</template>
|
|
162
|
-
</InputTextWithLabel>
|
|
163
|
-
</template>
|
|
164
|
-
</FormField>
|
|
165
|
-
|
|
166
|
-
<FormField width="wide" :has-gutter="false">
|
|
167
|
-
<template #default>
|
|
168
|
-
<InputPasswordWithLabel
|
|
169
|
-
id="password"
|
|
170
|
-
v-model="state.password"
|
|
171
|
-
:maxlength="fieldMaxLength('password')"
|
|
172
|
-
name="password"
|
|
173
|
-
placeholder="eg. a mixure of numbers and letters"
|
|
174
|
-
label="Password"
|
|
175
|
-
:error-message="formErrors?.password?._errors[0] ?? ''"
|
|
176
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.password)"
|
|
177
|
-
:required="true"
|
|
178
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
179
|
-
:theme
|
|
180
|
-
:input-variant
|
|
181
|
-
>
|
|
182
|
-
<template #descriptionText>This is a descriptionText for the password input.</template>
|
|
183
|
-
<template #right>
|
|
184
|
-
<Icon name="radix-icons:eye-open" class="icon" />
|
|
185
|
-
</template>
|
|
186
|
-
</InputPasswordWithLabel>
|
|
187
|
-
</template>
|
|
188
|
-
</FormField>
|
|
189
|
-
|
|
190
|
-
<FormField width="wide" :has-gutter="false">
|
|
191
|
-
<template #default>
|
|
192
|
-
<InputTextareaWithLabel
|
|
193
|
-
v-model="state.message"
|
|
194
|
-
:maxlength="fieldMaxLength('message')"
|
|
195
|
-
name="message"
|
|
196
|
-
placeholder="Type your message here"
|
|
197
|
-
label="Your message"
|
|
198
|
-
:error-message="formErrors?.message?._errors[0] ?? ''"
|
|
199
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.message)"
|
|
200
|
-
:required="true"
|
|
201
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
202
|
-
:theme
|
|
203
|
-
:input-variant
|
|
204
|
-
>
|
|
205
|
-
<template #descriptionText>This is a descriptionText for the message input.</template>
|
|
206
|
-
</InputTextareaWithLabel>
|
|
207
|
-
</template>
|
|
208
|
-
</FormField>
|
|
209
|
-
|
|
210
|
-
<FormField v-if="tagsData !== null" width="wide" :has-gutter="false">
|
|
211
|
-
<template #default>
|
|
212
|
-
<MultipleCheckboxes
|
|
213
|
-
v-model="state.tags"
|
|
214
|
-
v-model:field-data="tagsData"
|
|
215
|
-
name="tags"
|
|
216
|
-
legend="Choose tags (MultipleCheckboxes)"
|
|
217
|
-
:required="true"
|
|
218
|
-
label="Check between 3 and 8 tags"
|
|
219
|
-
placeholder="eg. Type something here"
|
|
220
|
-
:is-button="true"
|
|
221
|
-
:is-pill="false"
|
|
222
|
-
:error-message="formErrors?.tags?._errors[0] ?? ''"
|
|
223
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.tags)"
|
|
224
|
-
options-layout="inline"
|
|
225
|
-
:theme
|
|
226
|
-
:display-as-disc="false"
|
|
227
|
-
>
|
|
228
|
-
<template #descriptionText>descriptionText slot</template>
|
|
229
|
-
<template #itemIcon>
|
|
230
|
-
<Icon name="material-symbols:bookmark-add-outline" class="icon" />
|
|
231
|
-
</template>
|
|
232
|
-
</MultipleCheckboxes>
|
|
233
|
-
</template>
|
|
234
|
-
</FormField>
|
|
235
|
-
|
|
236
|
-
<FormField width="wide" :has-gutter="false">
|
|
237
|
-
<template #default>
|
|
238
|
-
<ToggleSwitchWithLabel
|
|
239
|
-
v-model="state.darkMode"
|
|
240
|
-
name="darkMode"
|
|
241
|
-
label="Toggle Dark mode"
|
|
242
|
-
true-value="dark"
|
|
243
|
-
false-value="light"
|
|
244
|
-
:theme
|
|
245
|
-
>
|
|
246
|
-
<template #description>
|
|
247
|
-
<p class="label-description">Light or Dark mode?</p>
|
|
248
|
-
</template>
|
|
249
|
-
<template #iconOn>
|
|
250
|
-
<Icon name="radix-icons:sun" class="icon" />
|
|
251
|
-
</template>
|
|
252
|
-
<template #iconOff>
|
|
253
|
-
<Icon name="radix-icons:moon" class="icon" />
|
|
254
|
-
</template>
|
|
255
|
-
</ToggleSwitchWithLabel>
|
|
256
|
-
</template>
|
|
257
|
-
</FormField>
|
|
258
|
-
|
|
259
|
-
<FormField width="wide" :has-gutter="false">
|
|
260
|
-
<template #default>
|
|
261
|
-
<ToggleSwitchWithLabelInline
|
|
262
|
-
v-model="state.anotherToggle"
|
|
263
|
-
name="anotherToggle"
|
|
264
|
-
label="Toggle Dark mode (inline)"
|
|
265
|
-
:theme
|
|
266
|
-
>
|
|
267
|
-
<template #iconOn>
|
|
268
|
-
<Icon name="radix-icons:moon" class="icon" />
|
|
269
|
-
</template>
|
|
270
|
-
<template #iconOff>
|
|
271
|
-
<Icon name="radix-icons:sun" class="icon" />
|
|
272
|
-
</template>
|
|
273
|
-
</ToggleSwitchWithLabelInline>
|
|
274
|
-
</template>
|
|
275
|
-
</FormField>
|
|
276
|
-
|
|
277
|
-
<FormField width="wide" :has-gutter="false">
|
|
278
|
-
<template #default>
|
|
279
|
-
<ToggleSwitchWithLabel
|
|
280
|
-
v-model="state.toggleBoolean"
|
|
281
|
-
:error-message="formErrors?.toggleBoolean?._errors[0] ?? ''"
|
|
282
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.toggleBoolean)"
|
|
283
|
-
name="toggleBoolean"
|
|
284
|
-
label="Toggle Dark mode"
|
|
285
|
-
:theme
|
|
286
|
-
>
|
|
287
|
-
<template #descriptionHtml>
|
|
288
|
-
<p class="label-description">Toggle some value</p>
|
|
289
|
-
</template>
|
|
290
|
-
</ToggleSwitchWithLabel>
|
|
291
|
-
</template>
|
|
292
|
-
</FormField>
|
|
293
|
-
|
|
294
|
-
<FormField width="wide" :has-gutter="false">
|
|
295
|
-
<template #default>
|
|
296
|
-
<InputTextAsNumberWithLabel
|
|
297
|
-
v-model.number="state.count2"
|
|
298
|
-
:maxlength="fieldMaxLength('count2')"
|
|
299
|
-
:min="25"
|
|
300
|
-
:max="75"
|
|
301
|
-
:step="5"
|
|
302
|
-
name="count2"
|
|
303
|
-
placeholder="eg. 10"
|
|
304
|
-
label="How many things? Between 25 & 75"
|
|
305
|
-
:error-message="formErrors?.count2?._errors[0] ?? ''"
|
|
306
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.count2)"
|
|
307
|
-
:required="true"
|
|
308
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
309
|
-
:theme
|
|
310
|
-
>
|
|
311
|
-
<template #descriptionHtml>
|
|
312
|
-
<p class="label-description">Input type="text" inputmode="numeric"</p>
|
|
313
|
-
</template>
|
|
314
|
-
<template #left>
|
|
315
|
-
<Icon name="gridicons:minus-small" class="icon" />
|
|
316
|
-
</template>
|
|
317
|
-
<template #right>
|
|
318
|
-
<Icon name="gridicons:plus-small" class="icon" />
|
|
319
|
-
</template>
|
|
320
|
-
</InputTextAsNumberWithLabel>
|
|
321
|
-
</template>
|
|
322
|
-
</FormField>
|
|
323
|
-
|
|
324
|
-
<FormField width="wide" :has-gutter="false">
|
|
325
|
-
<template #default>
|
|
326
|
-
<InputNumberDefault
|
|
327
|
-
v-model.number="state.count"
|
|
328
|
-
name="count"
|
|
329
|
-
label="How many things? Between 25 & 75 , step 5"
|
|
330
|
-
:min="25"
|
|
331
|
-
:max="75"
|
|
332
|
-
:step="5"
|
|
333
|
-
placeholder="eg. What\'s your count?"
|
|
334
|
-
:error-message="formErrors?.count?._errors[0] ?? ''"
|
|
335
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.count)"
|
|
336
|
-
:required="true"
|
|
337
|
-
:style-class-passthrough="['count-1', 'count-2']"
|
|
338
|
-
:theme
|
|
339
|
-
>
|
|
340
|
-
<template #descriptionHtml>
|
|
341
|
-
<p class="label-description">Input type="number" inputmode="numeric"</p>
|
|
342
|
-
</template>
|
|
343
|
-
<template #left>
|
|
344
|
-
<Icon name="gridicons:minus-small" class="icon" />
|
|
345
|
-
</template>
|
|
346
|
-
<template #right>
|
|
347
|
-
<Icon name="gridicons:plus-small" class="icon" />
|
|
348
|
-
</template>
|
|
349
|
-
</InputNumberDefault>
|
|
350
|
-
</template>
|
|
351
|
-
</FormField>
|
|
352
|
-
|
|
353
|
-
<FormField v-if="tagsData !== null" width="wide" :has-gutter="false">
|
|
354
|
-
<template #default>
|
|
355
|
-
<MultipleRadiobuttons
|
|
356
|
-
v-model="state.tagsRadio"
|
|
357
|
-
v-model:field-data="tagsData"
|
|
358
|
-
name="tagsRadio"
|
|
359
|
-
legend="Choose tags (as radiobuttons)"
|
|
360
|
-
:required="true"
|
|
361
|
-
label="Check between 3 and 8 tags"
|
|
362
|
-
placeholder="eg. Type something here"
|
|
363
|
-
:is-button="true"
|
|
364
|
-
:is-pill="true"
|
|
365
|
-
:error-message="formErrors?.tagsRadio?._errors[0] ?? ''"
|
|
366
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.tagsRadio)"
|
|
367
|
-
options-layout="inline"
|
|
368
|
-
:theme
|
|
369
|
-
direction="row-reverse"
|
|
370
|
-
>
|
|
371
|
-
<template #description>
|
|
372
|
-
<p class="label-description">This is description: optionsLayout = 'inline'</p>
|
|
373
|
-
</template>
|
|
374
|
-
</MultipleRadiobuttons>
|
|
375
|
-
</template>
|
|
376
|
-
</FormField>
|
|
377
|
-
|
|
378
|
-
<FormField
|
|
379
|
-
width="wide"
|
|
380
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.score)"
|
|
381
|
-
:has-gutter="false"
|
|
382
|
-
>
|
|
383
|
-
<template #default>
|
|
384
|
-
<InputRangeDefault
|
|
385
|
-
v-model.number="state.score"
|
|
386
|
-
name="score"
|
|
387
|
-
label="Score between 0 & 100"
|
|
388
|
-
:min="0"
|
|
389
|
-
:max="100"
|
|
390
|
-
:step="10"
|
|
391
|
-
placeholder="eg. What\'s your score?"
|
|
392
|
-
:error-message="formErrors?.score?._errors[0] ?? ''"
|
|
393
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.score)"
|
|
394
|
-
:required="true"
|
|
395
|
-
:style-class-passthrough="['style-1', 'style-2']"
|
|
396
|
-
:theme
|
|
397
|
-
>
|
|
398
|
-
<template #descriptionText>
|
|
399
|
-
<p class="label-description">This is a description of what the user is required to do</p>
|
|
400
|
-
</template>
|
|
401
|
-
<template #datalist>
|
|
402
|
-
<datalist id="score-datalist" class="input-range-datalist">
|
|
403
|
-
<option value="0" label="Rubbish!"></option>
|
|
404
|
-
<option value="25" label="Below par"></option>
|
|
405
|
-
<option value="50" label="Average"></option>
|
|
406
|
-
<option value="75" label="Quite good"></option>
|
|
407
|
-
<option value="100" label="Excellent"></option>
|
|
408
|
-
</datalist>
|
|
409
|
-
</template>
|
|
410
|
-
<template #left>
|
|
411
|
-
<Icon name="gridicons:minus-small" class="icon" />
|
|
412
|
-
</template>
|
|
413
|
-
<template #right>
|
|
414
|
-
<Icon name="gridicons:plus-small" class="icon" />
|
|
415
|
-
</template>
|
|
416
|
-
</InputRangeDefault>
|
|
417
|
-
</template>
|
|
418
|
-
</FormField>
|
|
419
|
-
|
|
420
|
-
<FormField v-if="titleData !== null" width="wide" :has-gutter="false">
|
|
421
|
-
<template #default>
|
|
422
|
-
<MultipleRadiobuttons
|
|
423
|
-
v-model="state.title"
|
|
424
|
-
v-model:field-data="titleData"
|
|
425
|
-
name="title"
|
|
426
|
-
legend="What is your title"
|
|
427
|
-
:required="true"
|
|
428
|
-
label="Check one"
|
|
429
|
-
placeholder="eg. Type something here"
|
|
430
|
-
:error-message="formErrors?.title?._errors[0] ?? ''"
|
|
431
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.title)"
|
|
432
|
-
options-layout="inline"
|
|
433
|
-
:theme
|
|
434
|
-
>
|
|
435
|
-
<template #checkedIcon>
|
|
436
|
-
<Icon name="material-symbols:check-small" class="input-checked-icon" />
|
|
437
|
-
</template>
|
|
438
|
-
<template #descriptionHtml>
|
|
439
|
-
<p class="label-description">
|
|
440
|
-
NOTE: Custom check icon set via slot
|
|
441
|
-
<br />
|
|
442
|
-
This is description: optionsLayout = 'inline'
|
|
443
|
-
</p>
|
|
444
|
-
</template>
|
|
445
|
-
</MultipleRadiobuttons>
|
|
446
|
-
</template>
|
|
447
|
-
</FormField>
|
|
448
|
-
|
|
449
|
-
<FormField v-if="titleData !== null" width="wide" :has-gutter="false">
|
|
450
|
-
<template #default>
|
|
451
|
-
<MultipleRadiobuttons
|
|
452
|
-
v-model="state.otherTitle"
|
|
453
|
-
v-model:field-data="titleData"
|
|
454
|
-
name="otherTitle"
|
|
455
|
-
legend="What is your title"
|
|
456
|
-
:required="true"
|
|
457
|
-
label="Check one"
|
|
458
|
-
placeholder="eg. Type something here"
|
|
459
|
-
:error-message="formErrors?.otherTitle?._errors[0] ?? ''"
|
|
460
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.otherTitle)"
|
|
461
|
-
options-layout="equal-widths"
|
|
462
|
-
:theme
|
|
463
|
-
>
|
|
464
|
-
<template #descriptionHtml>
|
|
465
|
-
<p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
|
|
466
|
-
</template>
|
|
467
|
-
</MultipleRadiobuttons>
|
|
468
|
-
</template>
|
|
469
|
-
</FormField>
|
|
470
|
-
|
|
471
|
-
<FormField v-if="citiesData !== null" width="wide" :has-gutter="false">
|
|
472
|
-
<template #default>
|
|
473
|
-
<MultipleCheckboxes
|
|
474
|
-
v-model="state.cities"
|
|
475
|
-
v-model:field-data="citiesData"
|
|
476
|
-
name="cities"
|
|
477
|
-
legend="Choose a location"
|
|
478
|
-
:required="true"
|
|
479
|
-
label="Check all Cities you like"
|
|
480
|
-
placeholder="eg. Type something here"
|
|
481
|
-
:error-message="formErrors?.cities?._errors[0] ?? ''"
|
|
482
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.cities)"
|
|
483
|
-
options-layout="inline"
|
|
484
|
-
:theme
|
|
485
|
-
>
|
|
486
|
-
<template #description>
|
|
487
|
-
<p class="label-description">This is description: optionsLayout = 'equal-widths'</p>
|
|
488
|
-
</template>
|
|
489
|
-
</MultipleCheckboxes>
|
|
490
|
-
</template>
|
|
491
|
-
</FormField>
|
|
492
|
-
|
|
493
|
-
<FormField v-if="countriesData !== null" width="wide" :has-gutter="false">
|
|
494
|
-
<template #default>
|
|
495
|
-
<MultipleCheckboxes
|
|
496
|
-
v-model="state.countries"
|
|
497
|
-
v-model:field-data="countriesData"
|
|
498
|
-
name="countries"
|
|
499
|
-
legend="Choose a country"
|
|
500
|
-
:required="true"
|
|
501
|
-
label="Check all Countries you like"
|
|
502
|
-
placeholder="eg. Type something here"
|
|
503
|
-
:error-message="formErrors?.countries?._errors[0] ?? ''"
|
|
504
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.countries)"
|
|
505
|
-
options-layout="equal-widths"
|
|
506
|
-
:theme
|
|
507
|
-
>
|
|
508
|
-
<template #checkedIcon>
|
|
509
|
-
<Icon name="material-symbols:circle" class="input-checked-icon" />
|
|
510
|
-
</template>
|
|
511
|
-
<template #descriptionHtml>
|
|
512
|
-
<p class="label-description">
|
|
513
|
-
NOTE: Custom chefck icon set via slot
|
|
514
|
-
<br />
|
|
515
|
-
This is description: optionsLayout = 'inline'
|
|
516
|
-
</p>
|
|
517
|
-
</template>
|
|
518
|
-
</MultipleCheckboxes>
|
|
519
|
-
</template>
|
|
520
|
-
</FormField>
|
|
521
|
-
|
|
522
|
-
<FormField width="wide" :has-gutter="false">
|
|
523
|
-
<template #default>
|
|
524
|
-
<SingleCheckbox
|
|
525
|
-
v-model="state.agreed"
|
|
526
|
-
name="agreed"
|
|
527
|
-
legend="I agree (label with description)"
|
|
528
|
-
label="Click to agree to something"
|
|
529
|
-
:required="true"
|
|
530
|
-
:error-message="formErrors?.agreed?._errors[0] ?? ''"
|
|
531
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.agreed)"
|
|
532
|
-
:theme
|
|
533
|
-
>
|
|
534
|
-
<template #description>
|
|
535
|
-
<p class="label-description">
|
|
536
|
-
You must
|
|
537
|
-
<strong>agree</strong>
|
|
538
|
-
to continue
|
|
539
|
-
</p>
|
|
540
|
-
</template>
|
|
541
|
-
</SingleCheckbox>
|
|
542
|
-
</template>
|
|
543
|
-
</FormField>
|
|
544
|
-
|
|
545
|
-
<FormField width="wide" :has-gutter="false">
|
|
546
|
-
<template #default>
|
|
547
|
-
<SingleCheckbox
|
|
548
|
-
v-model="state.agree"
|
|
549
|
-
name="agree"
|
|
550
|
-
legend="I agree (label no description)"
|
|
551
|
-
label="Click to agree to something"
|
|
552
|
-
:required="true"
|
|
553
|
-
:error-message="formErrors?.agree?._errors[0] ?? ''"
|
|
554
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.agree)"
|
|
555
|
-
:theme
|
|
556
|
-
/>
|
|
557
|
-
</template>
|
|
558
|
-
</FormField>
|
|
559
|
-
|
|
560
|
-
<FormField width="wide" :has-gutter="false">
|
|
561
|
-
<template #default>
|
|
562
|
-
<SingleCheckbox
|
|
563
|
-
v-model="state.terms"
|
|
564
|
-
name="terms"
|
|
565
|
-
legend="Terms and conditions"
|
|
566
|
-
:required="true"
|
|
567
|
-
:error-message="formErrors?.terms?._errors[0] ?? ''"
|
|
568
|
-
:field-has-error="Boolean(zodFormControl.submitAttempted && formErrors?.terms)"
|
|
569
|
-
:theme
|
|
570
|
-
>
|
|
571
|
-
<template #labelContent>
|
|
572
|
-
<span class="body-normal">
|
|
573
|
-
You must agree to our
|
|
574
|
-
<NuxtLink to="/typography" class="link-normal">terms and conditions</NuxtLink>
|
|
575
|
-
to continue
|
|
576
|
-
</span>
|
|
577
|
-
</template>
|
|
578
|
-
</SingleCheckbox>
|
|
579
|
-
</template>
|
|
580
|
-
</FormField>
|
|
581
|
-
|
|
582
|
-
<FormField width="wide" :has-gutter="false">
|
|
583
|
-
<template #default>
|
|
584
|
-
<InputButtonCore
|
|
585
|
-
type="button"
|
|
586
|
-
:is-pending="false"
|
|
587
|
-
:readonly="zodFormControl.submitDisabled"
|
|
588
|
-
button-text="Submit"
|
|
589
|
-
:theme
|
|
590
|
-
@click.stop.prevent="submitForm()"
|
|
591
|
-
/>
|
|
592
|
-
</template>
|
|
593
|
-
</FormField>
|
|
594
|
-
</form>
|
|
595
|
-
</ClientOnly>
|
|
596
|
-
</template>
|
|
597
|
-
</FormWrapper>
|
|
598
|
-
</div>
|
|
599
|
-
</template>
|
|
600
|
-
<template #item-1>
|
|
601
|
-
<div>
|
|
602
|
-
<ClientOnly>
|
|
603
|
-
<p>Client only state</p>
|
|
604
|
-
<pre>
|
|
605
|
-
{{ state }}
|
|
606
|
-
</pre
|
|
607
|
-
>
|
|
608
|
-
<p>Client only zodFormControl</p>
|
|
609
|
-
<pre>
|
|
610
|
-
{{ zodFormControl }}
|
|
611
|
-
</pre
|
|
612
|
-
>
|
|
613
|
-
<p>Client only formErrors</p>
|
|
614
|
-
|
|
615
|
-
<pre>
|
|
616
|
-
{{ formErrors }}
|
|
617
|
-
</pre
|
|
618
|
-
>
|
|
619
|
-
</ClientOnly>
|
|
620
|
-
</div>
|
|
621
|
-
</template>
|
|
622
|
-
</LayoutGridByCols>
|
|
623
|
-
</template>
|
|
624
|
-
</NuxtLayout>
|
|
625
|
-
</div>
|
|
626
|
-
</template>
|
|
627
|
-
|
|
628
|
-
<script setup lang="ts">
|
|
629
|
-
import { z } from "zod";
|
|
630
|
-
import type { IFormMultipleOptions, FormUiTheme, InputUiVariant } from "~/types/forms/types.forms";
|
|
631
|
-
// Inline fallback for ReturnTypeUseZodValidation if not exported
|
|
632
|
-
type ReturnTypeUseZodValidation = ReturnType<typeof useZodValidation>;
|
|
633
|
-
|
|
634
|
-
definePageMeta({
|
|
635
|
-
layout: false,
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
useHead({
|
|
639
|
-
title: "Text Field Example",
|
|
640
|
-
meta: [{ name: "description", content: "Homepage" }],
|
|
641
|
-
bodyAttrs: {
|
|
642
|
-
class: "text-fields-page",
|
|
643
|
-
},
|
|
644
|
-
});
|
|
645
|
-
|
|
646
|
-
const inputVariant = ref<InputUiVariant>("normal");
|
|
647
|
-
// const inputVariantData = ref<IFormMultipleOptions>({
|
|
648
|
-
// data: [
|
|
649
|
-
// {
|
|
650
|
-
// id: 'normal',
|
|
651
|
-
// name: 'normal',
|
|
652
|
-
// value: 'normal',
|
|
653
|
-
// label: 'Normal',
|
|
654
|
-
// },
|
|
655
|
-
// {
|
|
656
|
-
// id: 'outlined',
|
|
657
|
-
// name: 'outlined',
|
|
658
|
-
// value: 'outlined',
|
|
659
|
-
// label: 'Material - Outlined',
|
|
660
|
-
// },
|
|
661
|
-
// {
|
|
662
|
-
// id: 'underlined',
|
|
663
|
-
// name: 'underlined',
|
|
664
|
-
// value: 'underlined',
|
|
665
|
-
// label: 'Material - Underlined',
|
|
666
|
-
// },
|
|
667
|
-
// ],
|
|
668
|
-
// total: 3,
|
|
669
|
-
// skip: 0,
|
|
670
|
-
// limit: 3,
|
|
671
|
-
// });
|
|
672
|
-
const theme = ref<FormUiTheme>("default");
|
|
673
|
-
const swapTheme = (newTheme: FormUiTheme) => {
|
|
674
|
-
theme.value = newTheme;
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
// const variant = ref<"primary" | "secondary" | "tertiary">("primary");
|
|
678
|
-
// const swapVariant = (newVariant: "primary" | "secondary" | "tertiary") => {
|
|
679
|
-
// variant.value = newVariant;
|
|
680
|
-
// };
|
|
681
|
-
|
|
682
|
-
/*
|
|
683
|
-
* Fetch some sample data
|
|
684
|
-
**/
|
|
685
|
-
const { data: citiesData } = await useFetch<IFormMultipleOptions>("/api/places/list?category=cities");
|
|
686
|
-
const { data: countriesData } = await useFetch<IFormMultipleOptions>("/api/places/list?category=countries");
|
|
687
|
-
const { data: titleData } = await useFetch<IFormMultipleOptions>("/api/utils?category=title");
|
|
688
|
-
const { data: tagsData } = await useFetch<IFormMultipleOptions>("/api/recipes/tags");
|
|
689
|
-
|
|
690
|
-
/*
|
|
691
|
-
* Setup forms
|
|
692
|
-
*/
|
|
693
|
-
const formSchema = z
|
|
694
|
-
.object({
|
|
695
|
-
emailAddress: z
|
|
696
|
-
.string({
|
|
697
|
-
error: (issue) => (issue.input === undefined ? "Email address is required" : "Email address must be a string"),
|
|
698
|
-
})
|
|
699
|
-
.email({ error: "Invalid email address" })
|
|
700
|
-
.refine(
|
|
701
|
-
(email) => {
|
|
702
|
-
// Defensive: previousState may be undefined on first run
|
|
703
|
-
return email !== (zodFormControl?.previousState?.emailAddress?.value ?? "");
|
|
704
|
-
},
|
|
705
|
-
{
|
|
706
|
-
error: "This email address has already been used",
|
|
707
|
-
}
|
|
708
|
-
),
|
|
709
|
-
username: z
|
|
710
|
-
.string({
|
|
711
|
-
error: (issue) => (issue.input === undefined ? "Username is required" : "Username must be a string"),
|
|
712
|
-
})
|
|
713
|
-
.trim()
|
|
714
|
-
.min(2, "Username is too short")
|
|
715
|
-
.max(25, "Username is too long")
|
|
716
|
-
.refine(
|
|
717
|
-
(username) => {
|
|
718
|
-
return username !== (zodFormControl?.previousState?.username?.value ?? "");
|
|
719
|
-
},
|
|
720
|
-
{
|
|
721
|
-
error: "This username has already been used",
|
|
722
|
-
}
|
|
723
|
-
),
|
|
724
|
-
password: z
|
|
725
|
-
.string()
|
|
726
|
-
.trim()
|
|
727
|
-
.min(8, "Password is too short")
|
|
728
|
-
.max(25, "Password is too long")
|
|
729
|
-
.refine(
|
|
730
|
-
(password) => {
|
|
731
|
-
return password !== (zodFormControl?.previousState?.password?.value ?? "");
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
error: "You've already used this password",
|
|
735
|
-
}
|
|
736
|
-
),
|
|
737
|
-
message: z.string().trim().min(2, "Message is too short").max(255, "Message is too long"),
|
|
738
|
-
count: z
|
|
739
|
-
.number({
|
|
740
|
-
error: (issue) => (issue.input === undefined ? "Count is required" : "Count must be a number"),
|
|
741
|
-
})
|
|
742
|
-
.int({ error: "Count must be a whole number" })
|
|
743
|
-
.gte(25, "Count must be between 25 and 75")
|
|
744
|
-
.lte(75, "Count must be between 25 and 75")
|
|
745
|
-
.multipleOf(5, "Count must be a multiple of 5"),
|
|
746
|
-
count2: z
|
|
747
|
-
.number({
|
|
748
|
-
error: (issue) => (issue.input === undefined ? "Count is required" : "Count must be a number"),
|
|
749
|
-
})
|
|
750
|
-
.int({ error: "Count must be a whole number" })
|
|
751
|
-
.gte(25, "Count must be between 25 and 75")
|
|
752
|
-
.lte(75, "Count must be between 25 and 75"),
|
|
753
|
-
score: z
|
|
754
|
-
.number({
|
|
755
|
-
error: (issue) => (issue.input === undefined ? "Score is required" : "Score must be a number"),
|
|
756
|
-
})
|
|
757
|
-
.gte(0)
|
|
758
|
-
.lte(100),
|
|
759
|
-
cities: z.array(z.string()).min(1, "Please select at least one city"),
|
|
760
|
-
countries: z
|
|
761
|
-
.array(z.string())
|
|
762
|
-
.min(2, "Please select at least 2 countries")
|
|
763
|
-
.max(5, "Please select no more than 5 countries"),
|
|
764
|
-
countrySelect: z.string().min(1, { error: "Please select a country" }),
|
|
765
|
-
tags: z.array(z.string()).min(3, "Please select at least 3 tags").max(8, "Please select no more than 8 tags"),
|
|
766
|
-
tagsRadio: z.string().min(1, { error: "Please choose a tag" }),
|
|
767
|
-
darkMode: z.string().min(1, { error: "Please choose a mode" }),
|
|
768
|
-
title: z.string().min(1, { error: "Title is required" }),
|
|
769
|
-
otherTitle: z.string().min(1, { error: "Title is required" }),
|
|
770
|
-
toggleBoolean: z.boolean().refine((val) => val === true, { error: "You must tick this box" }),
|
|
771
|
-
agreed: z.boolean().refine((val) => val === true, { error: "You must tick this box" }),
|
|
772
|
-
agree: z.boolean().refine((val) => val === true, { error: "You must tick this box" }),
|
|
773
|
-
terms: z.boolean().refine((val) => val === true, { error: "You must accept our terms" }),
|
|
774
|
-
})
|
|
775
|
-
.required({
|
|
776
|
-
emailAddress: true,
|
|
777
|
-
username: true,
|
|
778
|
-
password: true,
|
|
779
|
-
message: true,
|
|
780
|
-
count: true,
|
|
781
|
-
count2: true,
|
|
782
|
-
score: true,
|
|
783
|
-
cities: true,
|
|
784
|
-
countries: true,
|
|
785
|
-
countrySelect: true,
|
|
786
|
-
tags: true,
|
|
787
|
-
tagsRadio: true,
|
|
788
|
-
title: true,
|
|
789
|
-
otherTitle: true,
|
|
790
|
-
toggleBoolean: true,
|
|
791
|
-
agreed: true,
|
|
792
|
-
agree: true,
|
|
793
|
-
terms: true,
|
|
794
|
-
});
|
|
795
|
-
|
|
796
|
-
type FormSchema = z.infer<typeof formSchema>;
|
|
797
|
-
const formErrors = computed<z.ZodFormattedError<FormSchema> | null>(() => zodErrorObj.value);
|
|
798
|
-
|
|
799
|
-
const state = reactive({
|
|
800
|
-
emailAddress: "",
|
|
801
|
-
username: "",
|
|
802
|
-
password: "",
|
|
803
|
-
message: "",
|
|
804
|
-
count: 25,
|
|
805
|
-
count2: 25,
|
|
806
|
-
score: 50,
|
|
807
|
-
cities: [],
|
|
808
|
-
countries: [],
|
|
809
|
-
countrySelect: "",
|
|
810
|
-
tags: [],
|
|
811
|
-
tagsRadio: [],
|
|
812
|
-
title: "",
|
|
813
|
-
otherTitle: "",
|
|
814
|
-
darkMode: "light",
|
|
815
|
-
toggleBoolean: false,
|
|
816
|
-
anotherToggle: false,
|
|
817
|
-
agreed: false,
|
|
818
|
-
agree: false,
|
|
819
|
-
terms: false,
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
const formRef = ref<HTMLFormElement | null>(null);
|
|
823
|
-
|
|
824
|
-
// If you don't have this type, you can define it inline as:
|
|
825
|
-
// type ReturnTypeUseZodValidation = ReturnType<typeof useZodValidation>;
|
|
826
|
-
|
|
827
|
-
const {
|
|
828
|
-
initZodForm,
|
|
829
|
-
zodFormControl,
|
|
830
|
-
zodErrorObj,
|
|
831
|
-
pushCustomErrors,
|
|
832
|
-
doZodValidate,
|
|
833
|
-
fieldMaxLength,
|
|
834
|
-
scrollToFirstError,
|
|
835
|
-
} = useZodValidation<typeof formSchema>(formSchema, formRef) as ReturnTypeUseZodValidation;
|
|
836
|
-
|
|
837
|
-
initZodForm();
|
|
838
|
-
|
|
839
|
-
const submitForm = async () => {
|
|
840
|
-
zodFormControl.submitAttempted = true;
|
|
841
|
-
if (!(await doZodValidate(state))) {
|
|
842
|
-
scrollToFirstError();
|
|
843
|
-
return;
|
|
844
|
-
}
|
|
845
|
-
zodFormControl.displayLoader = true;
|
|
846
|
-
try {
|
|
847
|
-
console.log("Form valid - post it");
|
|
848
|
-
const data = await $fetch("/api/textFields", {
|
|
849
|
-
method: "post",
|
|
850
|
-
body: state,
|
|
851
|
-
async onResponse({ response }) {
|
|
852
|
-
if (response.status === 400) {
|
|
853
|
-
console.log("onResponse", response);
|
|
854
|
-
console.log(response.status);
|
|
855
|
-
|
|
856
|
-
// useApiErrors(response._data.data.errors);
|
|
857
|
-
// for (const [key, message] of Object.entries(response._data.data.errors)) {
|
|
858
|
-
// console.log(`${key}: ${message}`);
|
|
859
|
-
// updateErrorMessages(key, message);
|
|
860
|
-
// }
|
|
861
|
-
|
|
862
|
-
// if (error instanceof Error) {
|
|
863
|
-
await pushCustomErrors(response._data, state);
|
|
864
|
-
// zodFormControl.formIsValid = false;
|
|
865
|
-
// }
|
|
866
|
-
// zodFormControl.submitAttempted = false;
|
|
867
|
-
}
|
|
868
|
-
if (response.status === 200) {
|
|
869
|
-
zodFormControl.submitSuccessful = true;
|
|
870
|
-
}
|
|
871
|
-
},
|
|
872
|
-
});
|
|
873
|
-
console.log("3: Finished data", data);
|
|
874
|
-
// return data;
|
|
875
|
-
} catch (error) {
|
|
876
|
-
console.warn("2: An error occured posting form data", error);
|
|
877
|
-
} finally {
|
|
878
|
-
zodFormControl.displayLoader = false;
|
|
879
|
-
}
|
|
880
|
-
};
|
|
881
|
-
|
|
882
|
-
watch(
|
|
883
|
-
() => state,
|
|
884
|
-
() => {
|
|
885
|
-
// console.log('Watching state');
|
|
886
|
-
doZodValidate(state);
|
|
887
|
-
},
|
|
888
|
-
{ deep: true }
|
|
889
|
-
);
|
|
890
|
-
</script>
|
|
891
|
-
|
|
892
|
-
<style lang="css">
|
|
893
|
-
.flex-group {
|
|
894
|
-
align-items: flex-start;
|
|
895
|
-
display: flex;
|
|
896
|
-
flex-wrap: wrap;
|
|
897
|
-
gap: 2.4rem;
|
|
898
|
-
margin-bottom: 3.2rem;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
ul.flex-group {
|
|
902
|
-
list-style-type: none;
|
|
903
|
-
padding: 0;
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
.header-1 {
|
|
907
|
-
font-family: var(--font-family);
|
|
908
|
-
color: var(--brand-success-text-text);
|
|
909
|
-
}
|
|
910
|
-
</style>
|