import { useRef , useMemo } from 'react' ; import { Errors } from './types' ; import { FieldMeta , UseFieldMetaOptions , useFieldMeta } from './useField' ; import { move , remove , shift , unshift } from './Errors' ; import { ValidationPathSpec } from './errorManager' ; import { BITS , useFormContext } from './Contexts' ; export type FieldArrayMeta = FieldMeta ; export interface FieldArrayHelpers < T = any > { /** Add an item to the beginning of the array */ unshift ( item ) : void ; deprecated add ( item ) : void ; /** Add an item to the end of the array */ push ( item ) : void ; /** Insert an item at the provided index */ insert ( item , index ) : void ; /** Move an item to a new index */ move ( item , toIndex ) : void ; /** Remove an item from the list */ remove ( item ) : void ; /**
     * update or replace an item with a new one.
     */ update ( item , oldItem ) : void ; onItemError ( name , errors ) : void ; } export type UseFieldArrayOptions = Omit < UseFieldMetaOptions , 'validates' > & { validates ? : string | string [ ] | null ; } ; param name function useFieldArray < T = any > ( name ) ; param name function useFieldArray < T = any > ( options ) ; function useFieldArray < T = any > ( optionsOrName ) { let options = typeof optionsOrName === 'string' ? { name : optionsOrName , exclusive : true } : optionsOrName ; let { name } = options ; const { actions } = useFormContext ( BITS . actions ) ; const fieldsToValidate = useMemo < ValidationPathSpec [ ] > ( ( ) => [ { path : name , shallow : true } ] , [ name ] ) ; const meta = useFieldMeta ( { ... options , exclusive : options . exclusive ?? true , validates : fieldsToValidate , } ) ; const { errors , onError , value , onChange , update } = meta ; const sendErrors = ( fn ) => { onError ( fn ( errors || { } , options . name ) ) ; } ; const helpers = { unshift : ( item ) => helpers . insert ( item , 0 ) , add : ( item ) => helpers . push ( item ) , push : ( item ) => helpers . insert ( item , value ? value . length : 0 ) , insert : ( item , index ) => { const newValue = value == null ? [ ] : [ ... value ] ; newValue . splice ( index , 0 , item ) ; onChange ( newValue ) ; sendErrors ( ( errors , name ) => unshift ( errors , name , index ) ) ; } , move : ( item , toIndex ) => { const fromIndex = value . indexOf ( item ) ; const newValue = value == null ? [ ] : [ ... value ] ; if ( fromIndex === - 1 ) throw new Error ( '`onMove` must be called with an item in the array' ) ; newValue . splice ( toIndex , 0 , ... newValue . splice ( fromIndex , 1 ) ) ; onChange ( newValue ) ; sendErrors ( ( errors , name ) => move ( errors , name , fromIndex , toIndex ) ) ; } , remove : ( item ) => { if ( value == null ) return ; const index = value . indexOf ( item ) ; onChange ( value . filter ( ( v ) => v !== item ) ) ; sendErrors ( ( errors , name ) => shift ( errors , name , index ) ) ; } , onItemError : ( name , errors ) => { sendErrors ( ( fieldErrors ) => ( { ... remove ( fieldErrors , name ) , ... errors , } ) ) ; } , update : ( updatedItem , oldItem ) => { const index = value . indexOf ( oldItem ) ; const newValue = value == null ? [ ] : [ ... value ] ; newValue . splice ( index , 1 , updatedItem ) ; update ( newValue ) ; if ( options . noValidate ) return ; actions ?. onValidate ( [ `${ name }[${ index }]` ] , 'onChange' , [ ] ) ; } , } ; return [ value as T [ ] , Object . assign ( useRef ( { } as any ) . current , helpers ) , meta , ] ; } export default useFieldArray ;