Skip to content

Dev #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 31, 2024
Merged

Dev #14

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "vuetify-stepper-form",
"name": "@wdns/vuetify-stepper-form",
"version": "1.0.0-beta1",
"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.",
"private": false,
Expand Down Expand Up @@ -137,6 +137,7 @@
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-static-copy": "^2.0.0",
"vite-plugin-stylelint": "6.0.0-beta.1",
"vite-plugin-vue-devtools": "^7.6.0",
"vite-plugin-vuetify": "^2.0.4",
"vitest": "^2.1.4",
"vue-tsc": "^2.1.8",
Expand Down
1,226 changes: 874 additions & 352 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

136 changes: 107 additions & 29 deletions src/documentation/components/examples/ButtonsFieldExample.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
color="primary"
:density="buttonDensityModel"
:pages="pages"
:validationSchema="validationSchema"
:variant="buttonVariantModel"
@submit="submitForm"
/>
Expand All @@ -21,8 +22,8 @@
v-model="drawer"
fixed
location="right"
:scrim="false"
temporary
:scrim="!mobile ? false : 'transparent'"
:temporary="!mobile"
>
<v-container>
<div class="d-flex justify-space-between align-center mb-2">
Expand Down Expand Up @@ -83,17 +84,6 @@
:true-value="true"
/>
</v-col>
<v-col
class="py-0"
cols="12"
>
<v-checkbox
v-model="multipleModel"
v-bind="optionsSettings"
label="Multiple"
:true-value="true"
/>
</v-col>
<v-col
class="pb-0"
cols="12"
Expand Down Expand Up @@ -156,6 +146,12 @@
</template>

<script setup lang="ts">
import { useDisplay } from 'vuetify';
import {
array as yupArray,
object as yupObject,
string as yupString,
} from 'yup';
import AnswersDialog from '../AnswersDialog.vue';


Expand All @@ -168,6 +164,7 @@ const optionsSettings = {
density: 'comfortable' as const,
hideDetails: true,
};
const { mobile } = useDisplay();

const buttonVariantOptions = [
{
Expand Down Expand Up @@ -239,31 +236,37 @@ const buttonDensityOptions = [
value: 'oversized',
},
];
const multipleModel = ref(false);
const useIcon = ref(false);


const answers = ref<{ iLikeButtons: string | string[] | null | undefined; }>({
const answers = ref<{
animalsILike: string[] | null | undefined;
iLikeButtons: string | null | undefined;
}>({
animalsILike: null,
iLikeButtons: null,
});

watch(() => multipleModel.value, () => {
answers.value.iLikeButtons = multipleModel.value ? [] as string[] : null;
});

const appendIcon = ref(false);
const prependIcon = ref(false);
const useColors = ref(false);


watch(() => [useIcon.value, useColors.value, appendIcon.value, prependIcon.value], () => {
answers.value = {
animalsILike: null,
iLikeButtons: null,
};
});


const pages = computed(() => [
{
fields: [
{
align: buttonAlignModel,
block: buttonBlock,
label: 'I like buttons',
multiple: multipleModel,
name: 'iLikeButtons',
options: [
{
Expand All @@ -290,6 +293,42 @@ const pages = computed(() => [
value: 'maybe',
},
],
required: true,
type: 'buttons' as const,
},
{
align: buttonAlignModel,
block: buttonBlock,
label: 'I like...',
multiple: true,
name: 'animalsILike',
options: [
{
appendIcon: appendIcon.value ? 'mdi:mdi-rabbit' : undefined,
color: useColors.value ? 'white' : undefined,
icon: useIcon.value ? 'mdi:mdi-rabbit' : undefined,
label: 'Bunnies',
prependIcon: prependIcon.value ? 'mdi:mdi-rabbit' : undefined,
value: 'bunnies',
},
{
appendIcon: appendIcon.value ? 'mdi:mdi-tortoise' : undefined,
color: useColors.value ? 'success' : undefined,
icon: useIcon.value ? 'mdi:mdi-tortoise' : undefined,
label: 'Turtles',
prependIcon: prependIcon.value ? 'mdi:mdi-tortoise' : undefined,
value: 'turtles',
},
{
appendIcon: appendIcon.value ? 'mdi:mdi-duck' : undefined,
color: useColors.value ? 'yellow' : undefined,
icon: useIcon.value ? 'mdi:mdi-duck' : undefined,
label: 'duck',
prependIcon: prependIcon.value ? 'mdi:mdi-duck' : undefined,
value: 'duck',
},
],
required: true,
type: 'buttons' as const,
},
],
Expand All @@ -303,6 +342,12 @@ watch(() => pages.value, () => {
exampleKey.value = String(Math.random());
});

const validationSchema = yupObject({
animalsILike: yupArray().required('This field is required.')
.min(1, 'Must select at least ${min} option.'),
iLikeButtons: yupString().required('This field is required.'),
});

function submitForm(): void {
dialog.value = true;
}
Expand Down Expand Up @@ -373,16 +418,34 @@ const maybeOption = computed(() => buildOption({
value: 'maybe',
}));

const bunniesOption = computed(() => buildOption({
color: 'white',
icon: 'mdi:mdi-rabbit',
label: 'Bunnies',
value: 'bunnies',
}));

const turtlesOption = computed(() => buildOption({
color: 'success',
icon: 'mdi:mdi-tortoise',
label: 'Turtles',
value: 'turtles',
}));

const duckOption = computed(() => buildOption({
color: 'yellow',
icon: 'mdi:mdi-duck',
label: 'duck',
value: 'duck',
}));


const exampleAnswer = computed<string>(() => {
if (!answers.value.iLikeButtons || (answers.value.iLikeButtons as string[]).length === 0) {
if (!answers.value.iLikeButtons) {
return 'null';
}

if (multipleModel.value) {
return `${JSON.stringify(answers.value.iLikeButtons)}`;
}

return `'${answers.value.iLikeButtons as string}'`;
return `'${answers.value.iLikeButtons}'`;
});

const scriptCode = computed(() => (
Expand All @@ -398,8 +461,7 @@ const pages = computed(() => [
align: '${buttonAlignModel.value}',
block: ${buttonBlock.value},
label: 'I like buttons',
multiple: ${multipleModel.value},
name: 'foo',
name: 'iLikeButtons',
options: [
{${yesOption.value}
}
Expand All @@ -410,6 +472,22 @@ const pages = computed(() => [
],
type: 'buttons',
},
{
align: '${buttonAlignModel.value}',
block: ${buttonBlock.value},
label: 'Animals I Like',
multiple: true,
name: 'animalsILike',
options: [
{${bunniesOption.value}
}
{${turtlesOption.value}
},
{${duckOption.value}
}
],
type: 'buttons',
},
],
title: 'Page 1',
},
Expand All @@ -425,7 +503,7 @@ watch(() => [scriptCode.value, templateCode.value], () => {
});

const exampleCode = computed(() => ({
desc: multipleModel.value,
desc: 'This example utilizes a custom-built component designed for this form, allowing users to select a value through buttons.',
name: 'Buttons Field',
script: scriptCode.value,
template: templateCode.value,
Expand Down
19 changes: 5 additions & 14 deletions src/documentation/sections/ComponentsSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
v-for="component in componentList"
:key="component.title"
>
<code class="ic mr-2">{{ component.title }}</code>
<span><code class="ic mr-2 d-inline-flex">{{ component.title }}</code></span>
</template>
</v-col>

Expand Down Expand Up @@ -98,19 +98,6 @@
An example of its usage can be found in the <a href="#examples-buttons-field">Buttons Field</a> example within the
Examples section below.
</v-col>

<!-- <v-col
id="components-field-label"
cols="12"
>
<h3 :class="classes.h3">
<a
:class="classes.headerA"
href="#components-field-label"
>#</a>
Field Label
</h3>
</v-col> -->
</v-row>
</template>

Expand Down Expand Up @@ -191,11 +178,15 @@ const buttonsFieldOptions = `interface Option {
appendIcon?: VBtn['appendIcon'];
class?: string;
color?: VBtn['color'];
height?: VBtn['height'];
icon?: VBtn['icon'];
id?: Field['id'];
label: Field['label'];
maxWidth?: VBtn['maxWidth'];
minWidth?: VBtn['minWidth'];
prependIcon?: VBtn['prependIcon'];
value: string | number;
width?: VBtn['width'];
}`;
</script>

Expand Down
5 changes: 2 additions & 3 deletions src/documentation/sections/UsageSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
>
<template #label>
Global Plugin Registration
<!-- <br>
<i>Global options have a higher precedence and will override local props</i> -->
</template>
</VCodeBlock>
</v-col>
Expand Down Expand Up @@ -69,6 +67,7 @@ app.use(createVStepperForm({

app.mount('#app');`;

// Needed to add ${''} to prevent console thinking it's actually trying to import the plugin //
const usageGlobalComponent = `import { createApp } from 'vue';
import App from './App.vue';
import { VStepperForm } from '@wdns/vuetify-stepper-form';
Expand All @@ -86,7 +85,7 @@ const usageIndividual = `<template>
</template>

\<script setup\>
import VStepperForm from '@wdns/vuetify-stepper-form';
im${''}port { VStepperForm } from '@wdns/vuetify-stepper-form';

const foo = ref(null);
\</script\>`;
Expand Down
3 changes: 1 addition & 2 deletions src/plugin/VStepperForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,6 @@ function removePageError(pageIndex: number): void {
// ------------------------ Check the if the page has errors //
function checkForPageErrors(errors: ValidateResult['errors'], source: string, next = () => { }): void {
const currentPage = stepperModel.value - 1;

const page = pages[currentPage];

if (!page) {
Expand All @@ -330,7 +329,7 @@ function checkForPageErrors(errors: ValidateResult['errors'], source: string, ne

const pageIndex = pages.findIndex((p) => p === page);
const pageFields = page?.fields ?? [];
const hasErrorInField = Object.keys(Array(errors)).some(errorKey => pageFields.some(field => field.name === errorKey));
const hasErrorInField = Object.keys(errors as object[]).some(errorKey => pageFields.some(field => field.name === errorKey));

if (hasErrorInField) {
currentPageHasErrors.value = true;
Expand Down
Loading