import * as React from 'react';
import { type ReactNode, useMemo } from 'react';
import { type UseFieldArrayReturn, useFormContext } from 'react-hook-form';
import { useWrappedSource } from '../../core/useWrappedSource';
import type { RaRecord } from '../../types';
import { useEvent } from '../../util';
import { useArrayInput } from './useArrayInput';
import { SimpleFormIteratorContext } from './SimpleFormIteratorContext';
const DefaultGetItemDefaults = item => item;
export const SimpleFormIteratorBase = (props: SimpleFormIteratorBaseProps) => {
const {
children,
getItemDefaults: getItemDefaultsProp = DefaultGetItemDefaults,
disableAutoFocus = false,
} = props;
const getItemDefaults = useEvent(getItemDefaultsProp);
const finalSource = useWrappedSource('');
if (!finalSource) {
throw new Error(
'SimpleFormIterator can only be called within an iterator input like ArrayInput'
);
}
const { append, fields, move, remove } = useArrayInput(props);
const { trigger, getValues } = useFormContext();
const removeField = useEvent((index: number) => {
remove(index);
const isScalarArray = getValues(finalSource).every(
(value: any) => typeof value !== 'object'
);
if (isScalarArray) {
// Trigger validation on the Array to avoid ghost errors.
// Otherwise, validation errors on removed fields might still be displayed
trigger(finalSource);
}
});
const addField = useEvent((item: any = undefined) => {
append(getItemDefaults(item), { shouldFocus: !disableAutoFocus });
});
const handleReorder = useEvent((origin: number, destination: number) => {
move(origin, destination);
});
const handleArrayClear = useEvent(() => {
remove();
});
const context = useMemo(
() => ({
total: fields.length,
add: addField,
clear: handleArrayClear,
remove: removeField,
reOrder: handleReorder,
source: finalSource,
}),
[
addField,
fields.length,
handleArrayClear,
handleReorder,
removeField,
finalSource,
]
);
if (!fields) {
return null;
}
return (
{children}
);
};
export interface SimpleFormIteratorBaseProps
extends Partial {
children: ReactNode;
inline?: boolean;
meta?: {
// the type defined in FieldArrayRenderProps says error is boolean, which is wrong.
error?: any;
submitFailed?: boolean;
};
getItemDefaults?: (item: any) => any;
record?: RaRecord;
resource?: string;
source?: string;
disableAutoFocus?: boolean;
}