@modular-forms/react
Version:
The modular and type-safe form library for React
63 lines (62 loc) • 3.19 kB
JavaScript
import { batch } from '@preact/signals-react';
import { getFieldArrayNames, getFieldArrayState, getFieldArrayStore, getFieldNames, getFieldState, getPathIndex, setFieldArrayState, setFieldState, updateFieldArrayDirty, } from '../utils';
/**
* Swaps two fields of a field array by their index.
*
* @param form The form of the field array.
* @param name The name of the field array.
* @param options The swap options.
*/
export function swap(form, name, { at: index1, and: index2 }) {
// Get store of specified field array
const fieldArray = getFieldArrayStore(form, name);
// Continue if specified field array exists
if (fieldArray) {
// Get last index of field array
const lastIndex = fieldArray.items.peek().length - 1;
// Continue if specified indexes are valid
if (index1 >= 0 &&
index1 <= lastIndex &&
index2 >= 0 &&
index2 <= lastIndex &&
index1 !== index2) {
// Create prefix for each index
const index1Prefix = `${name}.${index1}`;
const index2Prefix = `${name}.${index2}`;
// Create field and field array state map
const fieldStateMap = new Map();
const fieldArrayStateMap = new Map();
// Create filter name function
const filterName = (value) => value.startsWith(`${name}.`) &&
[index1, index2].includes(getPathIndex(name, value));
// Create swap index function
const swapIndex = (value) => (value.startsWith(index1Prefix)
? value.replace(index1Prefix, index2Prefix)
: value.replace(index2Prefix, index1Prefix));
// Add state of each required field to map
getFieldNames(form)
.filter(filterName)
.forEach((fieldName) => fieldStateMap.set(fieldName, getFieldState(form, fieldName)));
// Add state of each required field array to map
getFieldArrayNames(form)
.filter(filterName)
.forEach((fieldArrayName) => fieldArrayStateMap.set(fieldArrayName, getFieldArrayState(form, fieldArrayName)));
batch(() => {
// Finally swap state of fields
fieldStateMap.forEach((fieldState, fieldName) => setFieldState(form, swapIndex(fieldName), fieldState));
// Finally swap state of field arrays
fieldArrayStateMap.forEach((fieldArrayState, fieldArrayName) => setFieldArrayState(form, swapIndex(fieldArrayName), fieldArrayState));
// Swap items of field array
const nextItems = [...fieldArray.items.peek()];
nextItems[index1] = fieldArray.items.peek()[index2];
nextItems[index2] = fieldArray.items.peek()[index1];
fieldArray.items.value = nextItems;
// Set touched at field array and form to true;
fieldArray.touched.value = true;
form.touched.value = true;
// Update dirty state at field array and form
updateFieldArrayDirty(form, fieldArray);
});
}
}
}