import * as React from 'react'; import { type ReactNode, useCallback, useState } from 'react'; import { type UseFieldArrayReturn } from 'react-hook-form'; import type { RaRecord } from '../types'; import { useTranslate } from '../i18n/useTranslate'; import { Translate } from '../i18n/Translate'; import { useFieldValue } from '../util/useFieldValue'; import { useWrappedSource } from '../core/useWrappedSource'; import { useArrayInput } from '../controller/input/useArrayInput'; import { type ArrayInputContextValue } from '../controller/input/ArrayInputContext'; import { useSimpleFormIterator } from '../controller/input/useSimpleFormIterator'; import { useSimpleFormIteratorItem } from '../controller/input/useSimpleFormIteratorItem'; import { SimpleFormIteratorBase } from '../controller/input/SimpleFormIteratorBase'; import { SimpleFormIteratorItemBase } from '../controller/input/SimpleFormIteratorItemBase'; import { Confirm } from './Confirm'; import { useGetArrayInputNewItemDefaults } from '../controller'; import { useEvent } from '../util'; const DefaultAddItemButton = ( props: React.DetailedHTMLProps< React.ButtonHTMLAttributes, HTMLButtonElement > ) => { const { add, source } = useSimpleFormIterator(); const { className, ...rest } = props; return ( ); }; const DefaultRemoveItemButton = ( props: Omit< React.DetailedHTMLProps< React.ButtonHTMLAttributes, HTMLButtonElement >, 'onClick' > ) => { const { remove, index } = useSimpleFormIteratorItem(); const { source } = useSimpleFormIterator(); const { className, ...rest } = props; return ( ); }; const DefaultReOrderButtons = ({ className }: { className?: string }) => { const { index, total, reOrder } = useSimpleFormIteratorItem(); const { source } = useSimpleFormIterator(); return ( ); }; export type DisableRemoveFunction = (record: RaRecord) => boolean; export const SimpleFormIteratorItem = React.forwardRef< any, Partial & { children?: ReactNode; disabled?: boolean; disableRemove?: boolean | DisableRemoveFunction; disableReordering?: boolean; getItemLabel?: boolean | GetItemLabelFunc; index: number; inline?: boolean; record: RaRecord; removeButton?: ReactNode; reOrderButtons?: ReactNode; resource?: string; source?: string; } >(function SimpleFormIteratorItem(props, ref) { const { children, disabled, disableReordering, disableRemove, getItemLabel, index, inline, record, removeButton = , reOrderButtons = , } = props; // Returns a boolean to indicate whether to disable the remove button for certain fields. // If disableRemove is a function, then call the function with the current record to // determining if the button should be disabled. Otherwise, use a boolean property that // enables or disables the button for all of the fields. const disableRemoveField = (record: RaRecord) => { if (typeof disableRemove === 'boolean') { return disableRemove; } return disableRemove && disableRemove(record); }; const label = typeof getItemLabel === 'function' ? getItemLabel(index) : getItemLabel; return (
  • {label != null && label !== false && {label}}
    {children}
    {!disabled && ( {!disableReordering && reOrderButtons} {!disableRemoveField(record) && removeButton} )}

  • ); }); export const SimpleFormIterator = (props: SimpleFormIteratorProps) => { const { addButton = , removeButton, reOrderButtons, children, className, resource, disabled, disableAdd = false, disableClear, disableRemove = false, disableReordering, inline, getItemLabel = false, fullWidth, } = props; const finalSource = useWrappedSource(''); if (!finalSource) { throw new Error( 'SimpleFormIterator can only be called within an iterator input like ArrayInput' ); } const [confirmIsOpen, setConfirmIsOpen] = useState(false); const { fields, remove } = useArrayInput(props); const translate = useTranslate(); const handleArrayClear = useCallback(() => { remove(); setConfirmIsOpen(false); }, [remove]); const records = useFieldValue({ source: finalSource }); const getArrayInputNewItemDefaults = useGetArrayInputNewItemDefaults(fields); const getItemDefaults = useEvent((item: any = undefined) => { if (item != null) return item; return getArrayInputNewItemDefaults(children); }); return fields ? (
      {fields.map((member, index) => ( {children} ))}
    {!disabled && !(disableAdd && (disableClear || disableRemove)) && (
    {!disableAdd &&
    {addButton}
    } {fields.length > 0 && !disableClear && !disableRemove && (
    setConfirmIsOpen(false) } />
    )}
    )}
    ) : null; }; type GetItemLabelFunc = (index: number) => ReactNode; export interface SimpleFormIteratorProps extends Partial { addButton?: ReactNode; children?: ReactNode; className?: string; readOnly?: boolean; disabled?: boolean; disableAdd?: boolean; disableClear?: boolean; disableRemove?: boolean | DisableRemoveFunction; disableReordering?: boolean; fullWidth?: boolean; getItemLabel?: boolean | GetItemLabelFunc; inline?: boolean; meta?: { // the type defined in FieldArrayRenderProps says error is boolean, which is wrong. error?: any; submitFailed?: boolean; }; record?: RaRecord; removeButton?: ReactNode; reOrderButtons?: ReactNode; resource?: string; source?: string; }