@@ -180,18 +180,25 @@ const formGetSectionStatus = (
180180 return LegendStatus . VALID ;
181181} ;
182182
183- const formValidateSection = async (
183+ const getSectionFieldNames = (
184184 schemaFields : FormHydration [ ] ,
185- section : string ,
186- trigger : UseFormTrigger < FieldValues >
187- ) => {
185+ section : string
186+ ) : string | string [ ] => {
188187 const allSectionFields = formGetAllSectionFields ( schemaFields , section ) ;
189188 const isArrayForm = allSectionFields [ 0 ] ?. is_array_form ;
190- const fields = isArrayForm
189+ return isArrayForm
191190 ? allSectionFields [ 0 ] . title
192191 : allSectionFields
193192 . filter ( schemaField => ! schemaField ?. field ?. hidden )
194193 . map ( field => field . title ) ;
194+ } ;
195+
196+ const formValidateSection = async (
197+ schemaFields : FormHydration [ ] ,
198+ section : string ,
199+ trigger : UseFormTrigger < FieldValues >
200+ ) => {
201+ const fields = getSectionFieldNames ( schemaFields , section ) ;
195202
196203 return await trigger ( fields , { shouldFocus : false } ) ;
197204} ;
@@ -227,9 +234,22 @@ const formGenerateLegendItems = async (
227234 ? await formValidateSection ( schemaFields , section , trigger )
228235 : false ;
229236
230- // Reset form error state
237+ // Reset probe-validation errors, but keep errors for fields the
238+ // user has actually touched (dirty) so they don't vanish on nav
231239 if ( ! submissionRequested ) {
232- clearErrors ( ) ;
240+ const sectionFieldNames = getSectionFieldNames (
241+ schemaFields ,
242+ section
243+ ) ;
244+ const namesToClear = (
245+ Array . isArray ( sectionFieldNames )
246+ ? sectionFieldNames
247+ : [ sectionFieldNames ]
248+ ) . filter ( name => ! dirtyFields [ name ] ) ;
249+
250+ if ( namesToClear . length ) {
251+ clearErrors ( namesToClear ) ;
252+ }
233253 }
234254
235255 // Get status of section
@@ -340,6 +360,38 @@ const formatValidationItems = (items: Partial<FormHydrationValidation>[]) => ({
340360 ) ,
341361} ) ;
342362
363+ const generateValidationRules = ( validationFields : FormHydrationValidation [ ] ) => {
364+ const transformedObject : Record <
365+ string ,
366+ Omit < FormHydrationValidation , "title" >
367+ > = { } ;
368+
369+ validationFields . forEach ( field => {
370+ const { title, items, required, of, ...rest } = field ;
371+
372+ if ( items && Array . isArray ( items ) ) {
373+ // When field has an items array, convert to formatted object (used for field arrays)
374+ transformedObject [ title ] = {
375+ ...rest ,
376+ required,
377+ items : formatValidationItems ( items ) ,
378+ } ;
379+ } else if ( of && required ) {
380+ // Ensure required array of enums requires at least 1 value
381+ transformedObject [ title ] = {
382+ ...rest ,
383+ required,
384+ of,
385+ min : 1 ,
386+ } ;
387+ } else {
388+ transformedObject [ title ] = { ...rest , required, of } ;
389+ }
390+ } ) ;
391+
392+ return transformedObject ;
393+ } ;
394+
343395const convertRevisionsToArray = ( data : {
344396 revisions : Revision | Revision [ ] | null ;
345397} ) => {
@@ -583,6 +635,7 @@ export {
583635 hasVisibleFieldsForLocation ,
584636 renderFormHydrationField ,
585637 formatValidationItems ,
638+ generateValidationRules ,
586639 formGetFieldsCompletedCount ,
587640 mapFormFieldsForSubmission ,
588641 mapExistingDatasetToFormFields ,
0 commit comments