Skip to content

Commit a4c384f

Browse files
committed
fix: enhance form state merging with error map support
1 parent 8ede6d0 commit a4c384f

File tree

2 files changed

+61
-35
lines changed

2 files changed

+61
-35
lines changed

packages/form-core/src/mergeForm.ts

Lines changed: 16 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FormApi } from './FormApi'
1+
import type { AnyFormApi } from './FormApi'
22

33
function isValidKey(key: string | number | symbol): boolean {
44
const dangerousProps = ['__proto__', 'constructor', 'prototype']
@@ -70,38 +70,21 @@ export function mutateMergeDeep(
7070
return target
7171
}
7272

73-
export function mergeForm<TFormData>(
74-
baseForm: FormApi<
75-
NoInfer<TFormData>,
76-
any,
77-
any,
78-
any,
79-
any,
80-
any,
81-
any,
82-
any,
83-
any,
84-
any,
85-
any,
86-
any
87-
>,
88-
state: Partial<
89-
FormApi<
90-
TFormData,
91-
any,
92-
any,
93-
any,
94-
any,
95-
any,
96-
any,
97-
any,
98-
any,
99-
any,
100-
any,
101-
any
102-
>['state']
103-
>,
73+
export function mergeForm<TForm extends AnyFormApi>(
74+
baseForm: TForm,
75+
state: Partial<TForm['state']> | undefined,
10476
) {
105-
mutateMergeDeep(baseForm.state, state)
77+
if (!state) return baseForm
78+
79+
const { errorMap, ...rest } = state as Partial<TForm['state']>
80+
81+
mutateMergeDeep(baseForm.state, rest)
82+
83+
if (errorMap !== undefined) {
84+
baseForm.setErrorMap(
85+
errorMap as Parameters<TForm['setErrorMap']>[0],
86+
)
87+
}
88+
10689
return baseForm
10790
}

packages/form-core/tests/FormApi.spec.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { describe, expect, it, vi } from 'vitest'
22
import { z } from 'zod'
3-
import { FieldApi, FormApi, formEventClient } from '../src/index'
3+
import { FieldApi, FormApi, formEventClient, mergeForm } from '../src/index'
44
import { sleep } from './utils'
5-
import type { AnyFieldApi, AnyFormApi } from '../src/index'
5+
import type {
6+
AnyFieldApi,
7+
AnyFormApi,
8+
FormValidationErrorMap,
9+
GlobalFormValidationError,
10+
} from '../src/index'
611

712
describe('form api', () => {
813
it('should get default form state when default values are passed', () => {
@@ -55,6 +60,44 @@ describe('form api', () => {
5560
})
5661
})
5762

63+
it('should apply server validation errors to field meta when merging state', () => {
64+
const form = new FormApi({
65+
defaultValues: {
66+
name: '',
67+
},
68+
})
69+
70+
form.mount()
71+
72+
const field = new FieldApi({
73+
form,
74+
name: 'name',
75+
})
76+
77+
field.mount()
78+
79+
const serverError: GlobalFormValidationError<{ name: string }> = {
80+
form: 'Form invalid',
81+
fields: {
82+
name: 'Name invalid',
83+
},
84+
}
85+
86+
const serverErrorMap = {
87+
onServer: serverError,
88+
} as FormValidationErrorMap
89+
90+
mergeForm(form as unknown as AnyFormApi, {
91+
errorMap: serverErrorMap,
92+
errors: ['Form invalid'],
93+
})
94+
95+
expect(form.state.errorMap.onServer).toBe('Form invalid')
96+
expect(field.state.meta.errorMap.onServer).toBe('Name invalid')
97+
expect(field.state.meta.errorSourceMap.onServer).toBe('form')
98+
expect(field.state.meta.errors).toContain('Name invalid')
99+
})
100+
58101
it('should reset the form state properly', () => {
59102
const form = new FormApi({
60103
defaultValues: {

0 commit comments

Comments
 (0)