Skip to content

Commit dba6950

Browse files
Merge pull request #14 from webdevnerdstuff/dev
Dev
2 parents d79227e + 25b7571 commit dba6950

File tree

14 files changed

+1091
-445
lines changed

14 files changed

+1091
-445
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "vuetify-stepper-form",
2+
"name": "@wdns/vuetify-stepper-form",
33
"version": "1.0.0-beta1",
44
"description": "The Vuetify Stepper Form plugin provides a structured way to create multi-step forms using Vue 3, TypeScript, and Vuetify. It features a stepper layout that allows users to navigate between steps with form validation. The plugin is customizable and streamlines building dynamic, interactive forms that guide users through sequential steps.",
55
"private": false,
@@ -137,6 +137,7 @@
137137
"vite-plugin-eslint": "^1.8.1",
138138
"vite-plugin-static-copy": "^2.0.0",
139139
"vite-plugin-stylelint": "6.0.0-beta.1",
140+
"vite-plugin-vue-devtools": "^7.6.0",
140141
"vite-plugin-vuetify": "^2.0.4",
141142
"vitest": "^2.1.4",
142143
"vue-tsc": "^2.1.8",

pnpm-lock.yaml

Lines changed: 874 additions & 352 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/documentation/components/examples/ButtonsFieldExample.vue

Lines changed: 107 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
color="primary"
1414
:density="buttonDensityModel"
1515
:pages="pages"
16+
:validationSchema="validationSchema"
1617
:variant="buttonVariantModel"
1718
@submit="submitForm"
1819
/>
@@ -21,8 +22,8 @@
2122
v-model="drawer"
2223
fixed
2324
location="right"
24-
:scrim="false"
25-
temporary
25+
:scrim="!mobile ? false : 'transparent'"
26+
:temporary="!mobile"
2627
>
2728
<v-container>
2829
<div class="d-flex justify-space-between align-center mb-2">
@@ -83,17 +84,6 @@
8384
:true-value="true"
8485
/>
8586
</v-col>
86-
<v-col
87-
class="py-0"
88-
cols="12"
89-
>
90-
<v-checkbox
91-
v-model="multipleModel"
92-
v-bind="optionsSettings"
93-
label="Multiple"
94-
:true-value="true"
95-
/>
96-
</v-col>
9787
<v-col
9888
class="pb-0"
9989
cols="12"
@@ -156,6 +146,12 @@
156146
</template>
157147

158148
<script setup lang="ts">
149+
import { useDisplay } from 'vuetify';
150+
import {
151+
array as yupArray,
152+
object as yupObject,
153+
string as yupString,
154+
} from 'yup';
159155
import AnswersDialog from '../AnswersDialog.vue';
160156
161157
@@ -168,6 +164,7 @@ const optionsSettings = {
168164
density: 'comfortable' as const,
169165
hideDetails: true,
170166
};
167+
const { mobile } = useDisplay();
171168
172169
const buttonVariantOptions = [
173170
{
@@ -239,31 +236,37 @@ const buttonDensityOptions = [
239236
value: 'oversized',
240237
},
241238
];
242-
const multipleModel = ref(false);
243239
const useIcon = ref(false);
244240
245241
246-
const answers = ref<{ iLikeButtons: string | string[] | null | undefined; }>({
242+
const answers = ref<{
243+
animalsILike: string[] | null | undefined;
244+
iLikeButtons: string | null | undefined;
245+
}>({
246+
animalsILike: null,
247247
iLikeButtons: null,
248248
});
249249
250-
watch(() => multipleModel.value, () => {
251-
answers.value.iLikeButtons = multipleModel.value ? [] as string[] : null;
252-
});
253-
254250
const appendIcon = ref(false);
255251
const prependIcon = ref(false);
256252
const useColors = ref(false);
257253
258254
255+
watch(() => [useIcon.value, useColors.value, appendIcon.value, prependIcon.value], () => {
256+
answers.value = {
257+
animalsILike: null,
258+
iLikeButtons: null,
259+
};
260+
});
261+
262+
259263
const pages = computed(() => [
260264
{
261265
fields: [
262266
{
263267
align: buttonAlignModel,
264268
block: buttonBlock,
265269
label: 'I like buttons',
266-
multiple: multipleModel,
267270
name: 'iLikeButtons',
268271
options: [
269272
{
@@ -290,6 +293,42 @@ const pages = computed(() => [
290293
value: 'maybe',
291294
},
292295
],
296+
required: true,
297+
type: 'buttons' as const,
298+
},
299+
{
300+
align: buttonAlignModel,
301+
block: buttonBlock,
302+
label: 'I like...',
303+
multiple: true,
304+
name: 'animalsILike',
305+
options: [
306+
{
307+
appendIcon: appendIcon.value ? 'mdi:mdi-rabbit' : undefined,
308+
color: useColors.value ? 'white' : undefined,
309+
icon: useIcon.value ? 'mdi:mdi-rabbit' : undefined,
310+
label: 'Bunnies',
311+
prependIcon: prependIcon.value ? 'mdi:mdi-rabbit' : undefined,
312+
value: 'bunnies',
313+
},
314+
{
315+
appendIcon: appendIcon.value ? 'mdi:mdi-tortoise' : undefined,
316+
color: useColors.value ? 'success' : undefined,
317+
icon: useIcon.value ? 'mdi:mdi-tortoise' : undefined,
318+
label: 'Turtles',
319+
prependIcon: prependIcon.value ? 'mdi:mdi-tortoise' : undefined,
320+
value: 'turtles',
321+
},
322+
{
323+
appendIcon: appendIcon.value ? 'mdi:mdi-duck' : undefined,
324+
color: useColors.value ? 'yellow' : undefined,
325+
icon: useIcon.value ? 'mdi:mdi-duck' : undefined,
326+
label: 'duck',
327+
prependIcon: prependIcon.value ? 'mdi:mdi-duck' : undefined,
328+
value: 'duck',
329+
},
330+
],
331+
required: true,
293332
type: 'buttons' as const,
294333
},
295334
],
@@ -303,6 +342,12 @@ watch(() => pages.value, () => {
303342
exampleKey.value = String(Math.random());
304343
});
305344
345+
const validationSchema = yupObject({
346+
animalsILike: yupArray().required('This field is required.')
347+
.min(1, 'Must select at least ${min} option.'),
348+
iLikeButtons: yupString().required('This field is required.'),
349+
});
350+
306351
function submitForm(): void {
307352
dialog.value = true;
308353
}
@@ -373,16 +418,34 @@ const maybeOption = computed(() => buildOption({
373418
value: 'maybe',
374419
}));
375420
421+
const bunniesOption = computed(() => buildOption({
422+
color: 'white',
423+
icon: 'mdi:mdi-rabbit',
424+
label: 'Bunnies',
425+
value: 'bunnies',
426+
}));
427+
428+
const turtlesOption = computed(() => buildOption({
429+
color: 'success',
430+
icon: 'mdi:mdi-tortoise',
431+
label: 'Turtles',
432+
value: 'turtles',
433+
}));
434+
435+
const duckOption = computed(() => buildOption({
436+
color: 'yellow',
437+
icon: 'mdi:mdi-duck',
438+
label: 'duck',
439+
value: 'duck',
440+
}));
441+
442+
376443
const exampleAnswer = computed<string>(() => {
377-
if (!answers.value.iLikeButtons || (answers.value.iLikeButtons as string[]).length === 0) {
444+
if (!answers.value.iLikeButtons) {
378445
return 'null';
379446
}
380447
381-
if (multipleModel.value) {
382-
return `${JSON.stringify(answers.value.iLikeButtons)}`;
383-
}
384-
385-
return `'${answers.value.iLikeButtons as string}'`;
448+
return `'${answers.value.iLikeButtons}'`;
386449
});
387450
388451
const scriptCode = computed(() => (
@@ -398,8 +461,7 @@ const pages = computed(() => [
398461
align: '${buttonAlignModel.value}',
399462
block: ${buttonBlock.value},
400463
label: 'I like buttons',
401-
multiple: ${multipleModel.value},
402-
name: 'foo',
464+
name: 'iLikeButtons',
403465
options: [
404466
{${yesOption.value}
405467
}
@@ -410,6 +472,22 @@ const pages = computed(() => [
410472
],
411473
type: 'buttons',
412474
},
475+
{
476+
align: '${buttonAlignModel.value}',
477+
block: ${buttonBlock.value},
478+
label: 'Animals I Like',
479+
multiple: true,
480+
name: 'animalsILike',
481+
options: [
482+
{${bunniesOption.value}
483+
}
484+
{${turtlesOption.value}
485+
},
486+
{${duckOption.value}
487+
}
488+
],
489+
type: 'buttons',
490+
},
413491
],
414492
title: 'Page 1',
415493
},
@@ -425,7 +503,7 @@ watch(() => [scriptCode.value, templateCode.value], () => {
425503
});
426504
427505
const exampleCode = computed(() => ({
428-
desc: multipleModel.value,
506+
desc: 'This example utilizes a custom-built component designed for this form, allowing users to select a value through buttons.',
429507
name: 'Buttons Field',
430508
script: scriptCode.value,
431509
template: templateCode.value,

src/documentation/sections/ComponentsSection.vue

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
v-for="component in componentList"
2323
:key="component.title"
2424
>
25-
<code class="ic mr-2">{{ component.title }}</code>
25+
<span><code class="ic mr-2 d-inline-flex">{{ component.title }}</code></span>
2626
</template>
2727
</v-col>
2828

@@ -98,19 +98,6 @@
9898
An example of its usage can be found in the <a href="#examples-buttons-field">Buttons Field</a> example within the
9999
Examples section below.
100100
</v-col>
101-
102-
<!-- <v-col
103-
id="components-field-label"
104-
cols="12"
105-
>
106-
<h3 :class="classes.h3">
107-
<a
108-
:class="classes.headerA"
109-
href="#components-field-label"
110-
>#</a>
111-
Field Label
112-
</h3>
113-
</v-col> -->
114101
</v-row>
115102
</template>
116103

@@ -191,11 +178,15 @@ const buttonsFieldOptions = `interface Option {
191178
appendIcon?: VBtn['appendIcon'];
192179
class?: string;
193180
color?: VBtn['color'];
181+
height?: VBtn['height'];
194182
icon?: VBtn['icon'];
195183
id?: Field['id'];
196184
label: Field['label'];
185+
maxWidth?: VBtn['maxWidth'];
186+
minWidth?: VBtn['minWidth'];
197187
prependIcon?: VBtn['prependIcon'];
198188
value: string | number;
189+
width?: VBtn['width'];
199190
}`;
200191
</script>
201192

src/documentation/sections/UsageSection.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
>
2424
<template #label>
2525
Global Plugin Registration
26-
<!-- <br>
27-
<i>Global options have a higher precedence and will override local props</i> -->
2826
</template>
2927
</VCodeBlock>
3028
</v-col>
@@ -69,6 +67,7 @@ app.use(createVStepperForm({
6967
7068
app.mount('#app');`;
7169
70+
// Needed to add ${''} to prevent console thinking it's actually trying to import the plugin //
7271
const usageGlobalComponent = `import { createApp } from 'vue';
7372
import App from './App.vue';
7473
import { VStepperForm } from '@wdns/vuetify-stepper-form';
@@ -86,7 +85,7 @@ const usageIndividual = `<template>
8685
</template>
8786
8887
\<script setup\>
89-
import VStepperForm from '@wdns/vuetify-stepper-form';
88+
im${''}port { VStepperForm } from '@wdns/vuetify-stepper-form';
9089
9190
const foo = ref(null);
9291
\</script\>`;

src/plugin/VStepperForm.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,6 @@ function removePageError(pageIndex: number): void {
321321
// ------------------------ Check the if the page has errors //
322322
function checkForPageErrors(errors: ValidateResult['errors'], source: string, next = () => { }): void {
323323
const currentPage = stepperModel.value - 1;
324-
325324
const page = pages[currentPage];
326325
327326
if (!page) {
@@ -330,7 +329,7 @@ function checkForPageErrors(errors: ValidateResult['errors'], source: string, ne
330329
331330
const pageIndex = pages.findIndex((p) => p === page);
332331
const pageFields = page?.fields ?? [];
333-
const hasErrorInField = Object.keys(Array(errors)).some(errorKey => pageFields.some(field => field.name === errorKey));
332+
const hasErrorInField = Object.keys(errors as object[]).some(errorKey => pageFields.some(field => field.name === errorKey));
334333
335334
if (hasErrorInField) {
336335
currentPageHasErrors.value = true;

0 commit comments

Comments
 (0)