Skip to content

Commit 3b07e51

Browse files
committed
refactor metaHelper for clarity
1 parent fabf0ec commit 3b07e51

File tree

2 files changed

+171
-122
lines changed

2 files changed

+171
-122
lines changed

packages/form-core/src/FormApi.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,7 +2159,7 @@ export class FormApi<
21592159
await this.validateField(field, 'change')
21602160

21612161
// Shift down all meta after validating to make sure the new field has been mounted
2162-
metaHelper(this).handleArrayFieldMetaShift(field, index, 'insert')
2162+
metaHelper(this).handleArrayInsert(field, index)
21632163

21642164
await this.validateArrayFieldsStartingFrom(field, index, 'change')
21652165
}
@@ -2215,7 +2215,7 @@ export class FormApi<
22152215
)
22162216

22172217
// Shift up all meta
2218-
metaHelper(this).handleArrayFieldMetaShift(field, index, 'remove')
2218+
metaHelper(this).handleArrayRemove(field, index)
22192219

22202220
if (lastIndex !== null) {
22212221
const start = `${field}[${lastIndex}]`
@@ -2247,7 +2247,7 @@ export class FormApi<
22472247
)
22482248

22492249
// Swap meta
2250-
metaHelper(this).handleArrayFieldMetaShift(field, index1, 'swap', index2)
2250+
metaHelper(this).handleArraySwap(field, index1, index2)
22512251

22522252
// Validate the whole array
22532253
this.validateField(field, 'change')
@@ -2276,7 +2276,7 @@ export class FormApi<
22762276
)
22772277

22782278
// Move meta between index1 and index2
2279-
metaHelper(this).handleArrayFieldMetaShift(field, index1, 'move', index2)
2279+
metaHelper(this).handleArrayMove(field, index1, index2)
22802280

22812281
// Validate the whole array
22822282
this.validateField(field, 'change')
@@ -2323,7 +2323,11 @@ export class FormApi<
23232323
[field]: defaultFieldMeta,
23242324
},
23252325
values: this.options.defaultValues
2326-
? setBy(prev.values, field, getBy(this.options.defaultValues, field).value)
2326+
? setBy(
2327+
prev.values,
2328+
field,
2329+
getBy(this.options.defaultValues, field).value,
2330+
)
23272331
: prev.values,
23282332
}
23292333
})

packages/form-core/src/metaHelper.ts

Lines changed: 162 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
import type { AnyFieldMeta } from './FieldApi'
77
import type { DeepKeys } from './util-types'
88

9-
type ArrayFieldMode = 'insert' | 'remove' | 'swap' | 'move'
9+
type ValueFieldMode = 'insert' | 'remove' | 'swap' | 'move'
1010

1111
export const defaultFieldMeta: AnyFieldMeta = {
1212
isValidating: false,
@@ -33,7 +33,7 @@ export function metaHelper<
3333
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
3434
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
3535
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
36-
TSubmitMeta,
36+
TSubmitMeta = never,
3737
>(
3838
formApi: FormApi<
3939
TFormData,
@@ -50,57 +50,176 @@ export function metaHelper<
5050
TSubmitMeta
5151
>,
5252
) {
53-
function handleArrayFieldMetaShift(
53+
/**
54+
* Handle the meta shift caused from moving a field from one index to another.
55+
*/
56+
function handleArrayMove(
5457
field: DeepKeys<TFormData>,
55-
index: number,
56-
mode: ArrayFieldMode,
57-
secondIndex?: number,
58+
fromIndex: number,
59+
toIndex: number,
5860
) {
59-
const affectedFields = getAffectedFields(field, index, mode, secondIndex)
60-
61-
const handlers = {
62-
insert: () => handleInsertMode(affectedFields, field, index),
63-
remove: () => handleRemoveMode(affectedFields),
64-
swap: () =>
65-
secondIndex !== undefined &&
66-
handleSwapMode(affectedFields, field, index, secondIndex),
67-
move: () =>
68-
secondIndex !== undefined &&
69-
handleMoveMode(affectedFields, field, index, secondIndex),
61+
const affectedFields = getAffectedFields(field, fromIndex, 'move', toIndex)
62+
63+
const startIndex = Math.min(fromIndex, toIndex)
64+
const endIndex = Math.max(fromIndex, toIndex)
65+
for (let i = startIndex; i <= endIndex; i++) {
66+
affectedFields.push(getFieldPath(field, i))
7067
}
7168

72-
handlers[mode]()
69+
// Store the original field meta that will be reapplied at the destination index
70+
const fromFields = Object.keys(formApi.fieldInfo).reduce(
71+
(fieldMap, fieldKey) => {
72+
if (fieldKey.startsWith(getFieldPath(field, fromIndex))) {
73+
fieldMap.set(
74+
fieldKey as DeepKeys<TFormData>,
75+
formApi.getFieldMeta(fieldKey as DeepKeys<TFormData>),
76+
)
77+
}
78+
return fieldMap
79+
},
80+
new Map<DeepKeys<TFormData>, AnyFieldMeta | undefined>(),
81+
)
82+
83+
shiftMeta(affectedFields, fromIndex < toIndex ? 'up' : 'down')
84+
85+
// Reapply the stored field meta at the destination index
86+
Object.keys(formApi.fieldInfo)
87+
.filter((fieldKey) => fieldKey.startsWith(getFieldPath(field, toIndex)))
88+
.forEach((fieldKey) => {
89+
const fromKey = fieldKey.replace(
90+
getFieldPath(field, toIndex),
91+
getFieldPath(field, fromIndex),
92+
) as DeepKeys<TFormData>
93+
94+
const fromMeta = fromFields.get(fromKey)
95+
if (fromMeta) {
96+
formApi.setFieldMeta(fieldKey as DeepKeys<TFormData>, fromMeta)
97+
}
98+
})
99+
}
100+
101+
/**
102+
* Handle the meta shift from removing a field at the specified index.
103+
*/
104+
function handleArrayRemove(field: DeepKeys<TFormData>, index: number) {
105+
const affectedFields = getAffectedFields(field, index, 'remove')
106+
107+
shiftMeta(affectedFields, 'up')
108+
}
109+
110+
/**
111+
* Handle the meta shift from swapping two fields at the specified indeces.
112+
*/
113+
function handleArraySwap(
114+
field: DeepKeys<TFormData>,
115+
index: number,
116+
secondIndex: number,
117+
) {
118+
const affectedFields = getAffectedFields(field, index, 'swap', secondIndex)
119+
120+
affectedFields.forEach((fieldKey) => {
121+
if (!fieldKey.toString().startsWith(getFieldPath(field, index))) {
122+
return
123+
}
124+
125+
const swappedKey = fieldKey
126+
.toString()
127+
.replace(
128+
getFieldPath(field, index),
129+
getFieldPath(field, secondIndex),
130+
) as DeepKeys<TFormData>
131+
132+
const [meta1, meta2] = [
133+
formApi.getFieldMeta(fieldKey),
134+
formApi.getFieldMeta(swappedKey),
135+
]
136+
137+
if (meta1) formApi.setFieldMeta(swappedKey, meta1)
138+
if (meta2) formApi.setFieldMeta(fieldKey, meta2)
139+
})
140+
}
141+
142+
/**
143+
* Handle the meta shift from inserting a field at the specified index.
144+
*/
145+
function handleArrayInsert(field: DeepKeys<TFormData>, insertIndex: number) {
146+
const affectedFields = getAffectedFields(field, insertIndex, 'insert')
147+
148+
shiftMeta(affectedFields, 'down')
149+
150+
affectedFields.forEach((fieldKey) => {
151+
if (fieldKey.toString().startsWith(getFieldPath(field, insertIndex))) {
152+
formApi.setFieldMeta(fieldKey, getEmptyFieldMeta())
153+
}
154+
})
155+
}
156+
157+
/**
158+
* Handle the meta shift from filtering out indeces.
159+
* @param remainingIndices An array of indeces that were NOT filtered out of the original array.
160+
*/
161+
function handleArrayFilter(
162+
field: DeepKeys<TFormData>,
163+
remainingIndices: number[],
164+
) {
165+
if (remainingIndices.length === 0) return
166+
167+
// create a map between the index and its new location
168+
remainingIndices.forEach((fromIndex, toIndex) => {
169+
if (fromIndex === toIndex) return
170+
// assign it the original meta
171+
const fieldKey = getFieldPath(field, toIndex)
172+
const originalFieldKey = getFieldPath(field, fromIndex)
173+
const originalFieldMeta = formApi.getFieldMeta(originalFieldKey)
174+
if (originalFieldMeta) {
175+
formApi.setFieldMeta(fieldKey, originalFieldMeta)
176+
} else {
177+
formApi.setFieldMeta(fieldKey, {
178+
...getEmptyFieldMeta(),
179+
isTouched: originalFieldKey as unknown as boolean,
180+
})
181+
}
182+
})
73183
}
74184

75-
function getFieldPath(field: DeepKeys<TFormData>, index: number): string {
76-
return `${field}[${index}]`
185+
function getFieldPath(
186+
field: DeepKeys<TFormData>,
187+
index: number,
188+
): DeepKeys<TFormData> {
189+
return `${field}[${index}]` as DeepKeys<TFormData>
77190
}
78191

79192
function getAffectedFields(
80193
field: DeepKeys<TFormData>,
81194
index: number,
82-
mode: ArrayFieldMode,
195+
mode: ValueFieldMode,
83196
secondIndex?: number,
84197
): DeepKeys<TFormData>[] {
85198
const affectedFieldKeys = [getFieldPath(field, index)]
86199

87-
if (mode === 'swap') {
88-
affectedFieldKeys.push(getFieldPath(field, secondIndex!))
89-
} else if (mode === 'move') {
90-
const [startIndex, endIndex] = [
91-
Math.min(index, secondIndex!),
92-
Math.max(index, secondIndex!),
93-
]
94-
for (let i = startIndex; i <= endIndex; i++) {
95-
affectedFieldKeys.push(getFieldPath(field, i))
200+
switch (mode) {
201+
case 'swap':
202+
affectedFieldKeys.push(getFieldPath(field, secondIndex!))
203+
break
204+
case 'move': {
205+
const [startIndex, endIndex] = [
206+
Math.min(index, secondIndex!),
207+
Math.max(index, secondIndex!),
208+
]
209+
for (let i = startIndex; i <= endIndex; i++) {
210+
affectedFieldKeys.push(getFieldPath(field, i))
211+
}
212+
break
96213
}
97-
} else {
98-
const currentValue = formApi.getFieldValue(field)
99-
const fieldItems = Array.isArray(currentValue)
100-
? (currentValue as Array<unknown>).length
101-
: 0
102-
for (let i = index + 1; i < fieldItems; i++) {
103-
affectedFieldKeys.push(getFieldPath(field, i))
214+
default: {
215+
const currentValue = formApi.getFieldValue(field)
216+
const fieldItems = Array.isArray(currentValue)
217+
? (currentValue as Array<unknown>).length
218+
: 0
219+
for (let i = index + 1; i < fieldItems; i++) {
220+
affectedFieldKeys.push(getFieldPath(field, i))
221+
}
222+
break
104223
}
105224
}
106225

@@ -137,85 +256,11 @@ export function metaHelper<
137256

138257
const getEmptyFieldMeta = (): AnyFieldMeta => defaultFieldMeta
139258

140-
const handleInsertMode = (
141-
fields: DeepKeys<TFormData>[],
142-
field: DeepKeys<TFormData>,
143-
insertIndex: number,
144-
) => {
145-
shiftMeta(fields, 'down')
146-
147-
fields.forEach((fieldKey) => {
148-
if (fieldKey.toString().startsWith(getFieldPath(field, insertIndex))) {
149-
formApi.setFieldMeta(fieldKey, getEmptyFieldMeta())
150-
}
151-
})
152-
}
153-
154-
const handleRemoveMode = (fields: DeepKeys<TFormData>[]) => {
155-
shiftMeta(fields, 'up')
259+
return {
260+
handleArrayMove,
261+
handleArrayRemove,
262+
handleArraySwap,
263+
handleArrayInsert,
264+
handleArrayFilter,
156265
}
157-
158-
const handleMoveMode = (
159-
fields: DeepKeys<TFormData>[],
160-
field: DeepKeys<TFormData>,
161-
fromIndex: number,
162-
toIndex: number,
163-
) => {
164-
// Store the original field meta that will be reapplied at the destination index
165-
const fromFields = new Map(
166-
Object.keys(formApi.fieldInfo)
167-
.filter((fieldKey) =>
168-
fieldKey.startsWith(getFieldPath(field, fromIndex)),
169-
)
170-
.map((fieldKey) => [
171-
fieldKey as DeepKeys<TFormData>,
172-
formApi.getFieldMeta(fieldKey as DeepKeys<TFormData>),
173-
]),
174-
)
175-
176-
shiftMeta(fields, fromIndex < toIndex ? 'up' : 'down')
177-
178-
// Reapply the stored field meta at the destination index
179-
Object.keys(formApi.fieldInfo)
180-
.filter((fieldKey) => fieldKey.startsWith(getFieldPath(field, toIndex)))
181-
.forEach((fieldKey) => {
182-
const fromKey = fieldKey.replace(
183-
getFieldPath(field, toIndex),
184-
getFieldPath(field, fromIndex),
185-
) as DeepKeys<TFormData>
186-
187-
const fromMeta = fromFields.get(fromKey)
188-
if (fromMeta) {
189-
formApi.setFieldMeta(fieldKey as DeepKeys<TFormData>, fromMeta)
190-
}
191-
})
192-
}
193-
194-
const handleSwapMode = (
195-
fields: DeepKeys<TFormData>[],
196-
field: DeepKeys<TFormData>,
197-
index: number,
198-
secondIndex: number,
199-
) => {
200-
fields.forEach((fieldKey) => {
201-
if (!fieldKey.toString().startsWith(getFieldPath(field, index))) return
202-
203-
const swappedKey = fieldKey
204-
.toString()
205-
.replace(
206-
getFieldPath(field, index),
207-
getFieldPath(field, secondIndex),
208-
) as DeepKeys<TFormData>
209-
210-
const [meta1, meta2] = [
211-
formApi.getFieldMeta(fieldKey),
212-
formApi.getFieldMeta(swappedKey),
213-
]
214-
215-
if (meta1) formApi.setFieldMeta(swappedKey, meta1)
216-
if (meta2) formApi.setFieldMeta(fieldKey, meta2)
217-
})
218-
}
219-
220-
return { handleArrayFieldMetaShift }
221266
}

0 commit comments

Comments
 (0)