import { memo, useEffect, useRef } from 'react'; import type { RecordArrayFieldValue, RecordArrayFormField } from '@douglasneuroinformatics/libui-form-types'; import { MinusCircleIcon, PlusCircleIcon } from 'lucide-react'; import type { Simplify } from 'type-fest'; import { useTranslation } from '#hooks'; import { Button } from '../Button/Button.tsx'; import { Heading } from '../Heading/Heading.tsx'; import { Label } from '../Label/Label.tsx'; import { ScalarField } from './ScalarField.tsx'; import type { BaseFieldComponentProps } from './types.ts'; export type RecordArrayFieldProps = Simplify & RecordArrayFormField>; export const RecordArrayField = memo(function RecordArrayField({ disableAutoSuffix, disabled, error: arrayError, fieldset, label, readOnly, setError: setArrayError, setValue: setArrayValue, value: arrayValue }: RecordArrayFieldProps) { const fieldsetRef = useRef(fieldset); const { t } = useTranslation('libui'); const createNewRecord = () => Object.fromEntries(Object.keys(fieldset).map((fieldName) => [fieldName, undefined])); useEffect(() => { if (!arrayValue) { setArrayValue([createNewRecord()]); } }, []); useEffect(() => { if (fieldsetRef.current !== fieldset) { setArrayValue([createNewRecord()]); fieldsetRef.current = fieldset; } }, [fieldset]); if (!arrayValue) { return null; } // Creates a new object with all values mapped to null and appends it to the previous arrayValue const appendField = () => { setArrayValue([...arrayValue, createNewRecord()]); }; const removeField = () => { if (arrayValue.length > 1) { setArrayValue(arrayValue.slice(0, arrayValue.length - 1)); } }; return (
{label}
{arrayValue.map((fields, i) => { let itemLabel = label; if (!disableAutoSuffix) { itemLabel += ` ${i + 1}`; } return (
{Object.keys(fields).map((name) => { const field = fieldset[name]; const fieldProps = field?.kind === 'dynamic' ? field.render.call(undefined, fields) : field; if (!fieldProps) { return null; } return ( { const newArrayError = arrayError ? [...arrayError] : []; newArrayError[i] ??= {}; newArrayError[i][name] = error; setArrayError(newArrayError); }} setValue={(value) => { const newArrayValue = [...arrayValue]; newArrayValue[i]![name] = value; setArrayValue(newArrayValue); }} value={arrayValue?.[i]?.[name]} /> ); })}
); })}
); });