UNPKG

@modular-forms/react

Version:

The modular and type-safe form library for React

67 lines (66 loc) 3.54 kB
import { batch } from '@preact/signals-react'; import { getFieldArrayStore, getFieldArrayState, getFieldState, getPathIndex, getUniqueId, setFieldArrayState, setFieldArrayValue, setFieldState, sortArrayPathIndex, validateIfRequired, getFieldNames, getFieldArrayNames, } from '../utils'; /** * Inserts a new item into the field array. * * @param form The form of the field array. * @param name The name of the field array. * @param options The insert options. */ export function insert(form, name, options) { // Get store of specified field array const fieldArray = getFieldArrayStore(form, name); // Continue if specified field array exists if (fieldArray) { // Get length of field array const arrayLength = fieldArray.items.peek().length; // Destructure options const { at: index = arrayLength, value } = options; // Continue if specified index is valid if (index >= 0 && index <= arrayLength) { batch(() => { // If item is not inserted at end, move fields and field arrays of items // that come after new item one index further if (index < arrayLength) { // Create function to filter a name const filterName = (value) => value.startsWith(`${name}.`) && getPathIndex(name, value) >= index; // Create function to get next index name const getNextIndexName = (fieldOrFieldArrayName, fieldOrFieldArrayIndex) => fieldOrFieldArrayName.replace(`${name}.${fieldOrFieldArrayIndex}`, `${name}.${fieldOrFieldArrayIndex + 1}`); // Move fields that come after new item one index further getFieldNames(form) .filter(filterName) .sort(sortArrayPathIndex(name)) .reverse() .forEach((fieldName) => { setFieldState(form, getNextIndexName(fieldName, getPathIndex(name, fieldName)), getFieldState(form, fieldName)); }); // Move field arrays that come after new item one index further getFieldArrayNames(form) .filter(filterName) .sort(sortArrayPathIndex(name)) .reverse() .forEach((fieldArrayName) => { setFieldArrayState(form, getNextIndexName(fieldArrayName, getPathIndex(name, fieldArrayName)), getFieldArrayState(form, fieldArrayName)); }); } // Set value of new field array item setFieldArrayValue(form, name, { at: index, value }); // Insert item into field array const nextItems = [...fieldArray.items.peek()]; nextItems.splice(index, 0, getUniqueId()); fieldArray.items.value = nextItems; // Set touched at field array and form to true fieldArray.touched.value = true; form.touched.value = true; // Set dirty at field array and form to true fieldArray.dirty.value = true; form.dirty.value = true; }); } // Validate field array if required with delay to allow new fields to be // mounted beforehand setTimeout(() => validateIfRequired(form, fieldArray, name, { on: ['touched', 'change'], }), 250); } }