From 583f0bb4ddb3d3d454141842404eb2c2e4986e02 Mon Sep 17 00:00:00 2001 From: WebDevNerdStuff Date: Thu, 23 Jul 2026 17:47:12 -0400 Subject: [PATCH 1/2] fix: scope auto-page validation to the current page --- src/plugin/VStepperForm.vue | 26 +++++------- src/plugin/__tests__/VStepperForm.cy.ts | 56 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/plugin/VStepperForm.vue b/src/plugin/VStepperForm.vue index f9b5949..82acb21 100755 --- a/src/plugin/VStepperForm.vue +++ b/src/plugin/VStepperForm.vue @@ -596,7 +596,6 @@ function setPageToError(pageIndex: number, page?: Page, source = 'submit'): void let debounceTimer: ReturnType; function onFieldValidate(field: Field, next: () => void): void { - const errors = $useForm.errorBag as ValidateResult['errors']; const shouldAutoPage = (field.autoPage || settings.value.autoPage ? next : null) as () => void; // If autoPage // @@ -606,20 +605,17 @@ function onFieldValidate(field: Field, next: () => void): void { // First validate the page before proceeding to the next page // $useForm.validate() .then((res: ValidateResult) => { - if (res.valid) { - // debounce next // - clearTimeout(debounceTimer); - debounceTimer = setTimeout(() => { - checkForPageErrors(errors, 'field', shouldAutoPage); - }, (field?.autoPageDelay ?? settings.value?.autoPageDelay)); - - return; - } - - const page = computedPages.value[currentPageIdx.value]; - const pageIndex = computedPages.value.findIndex((p) => p === page); - - setPageToError(pageIndex, page, 'validating'); + // `validate()` covers the whole form, so fields on later pages + // are still invalid while the user is on an earlier one. Only + // the current page's errors may block auto paging, which is + // what `checkForPageErrors` filters on (same as the next button). + const errors = res.errors as unknown as ValidateResult['errors']; + + // debounce next // + clearTimeout(debounceTimer); + debounceTimer = setTimeout(() => { + checkForPageErrors(errors, 'field', shouldAutoPage); + }, (field?.autoPageDelay ?? settings.value?.autoPageDelay)); }) .catch((error: Error) => { console.error('Error', error); diff --git a/src/plugin/__tests__/VStepperForm.cy.ts b/src/plugin/__tests__/VStepperForm.cy.ts index b0a87d7..2f6861f 100644 --- a/src/plugin/__tests__/VStepperForm.cy.ts +++ b/src/plugin/__tests__/VStepperForm.cy.ts @@ -1,3 +1,7 @@ +import { + object as yupObject, + string as yupString, +} from 'yup'; import type { Field, Page } from '../../plugin/types'; import * as DATA from '@cypress/templates/testData'; import VStepperForm from '../VStepperForm.vue'; @@ -637,6 +641,58 @@ describe('Stepper Form', () => { .should('exist') .and('be.visible'); }); + + // ? The validation schema covers the whole form, so fields on later pages + // ? are always invalid while the user is still on an earlier page. Auto + // ? paging must only care about the errors on the current page. // + it('should auto page when a later page still has unfilled required fields', () => { + const schema = yupObject({ + address: yupString().required('Address is required'), + animal: yupString().required('Animal is required'), + }); + + cy.mount(VStepperForm as any, { + props: { + modelValue: { address: null, animal: null }, + pages: [ + { + fields: [ + { + autoPage: true, + label: 'Animal', + name: 'animal', + options: [ + { label: 'Rabbit', value: 'rabbit' }, + { label: 'Duck', value: 'duck' }, + ], + required: true, + type: 'buttons', + }, + ], + title: 'Page 1', + }, + { + fields: [defaultFields.address], + title: 'Page 2', + }, + ], + validationSchema: schema, + }, + global, + }); + + cy.getDataCy('vsf-field-address') + .should('not.exist'); + + cy.getDataCy('vsf-field-animal') + .first() + .click(); + + // Moved onto the next page // + cy.getDataCy('vsf-field-address') + .should('exist') + .and('be.visible'); + }); }); describe('Header Tooltip', () => { From 5c13f298bd9ddda363f390c9a07de499ecb30fca Mon Sep 17 00:00:00 2001 From: WebDevNerdStuff Date: Thu, 23 Jul 2026 17:56:20 -0400 Subject: [PATCH 2/2] refactor: remove unused useAutoPage composable --- src/plugin/composables/helpers.ts | 19 ------------------- src/plugin/types/index.ts | 13 ------------- 2 files changed, 32 deletions(-) diff --git a/src/plugin/composables/helpers.ts b/src/plugin/composables/helpers.ts index d00cfa3..1dee4d0 100755 --- a/src/plugin/composables/helpers.ts +++ b/src/plugin/composables/helpers.ts @@ -1,6 +1,4 @@ -import { watchDebounced } from '@vueuse/core'; import type { - UseAutoPage, UseBuildSettings, UseColumnErrorCheck, UseDeepMerge, @@ -84,23 +82,6 @@ export const useBuildSettings: UseBuildSettings = (stepperProps: Settings) => { }; -/** -* Automatically pages to the next field. -*/ -export const useAutoPage: UseAutoPage = (options) => { - const { emit, field, modelValue, settings } = options; - watchDebounced(modelValue, () => { - if (field?.autoPage == false) { - return; - } - - if (field?.autoPage || settings?.autoPage) { - emit('next', field); - } - }, { debounce: (field?.autoPageDelay ?? settings?.autoPageDelay) }); -}; - - /** * Checks if the column values are between 1 and 12. */ diff --git a/src/plugin/types/index.ts b/src/plugin/types/index.ts index f808694..db1d0b6 100755 --- a/src/plugin/types/index.ts +++ b/src/plugin/types/index.ts @@ -268,19 +268,6 @@ export interface UseDeepMerge { ): Record; } -export interface UseAutoPage { - ( - options: { - emit: { - (e: 'next', field: Field): void; - }, - field: Field; - modelValue: any; - settings: Settings; - } - ): void; -} - export interface UseColumnErrorCheck { ( options: {