import { useContext , useState } from 'react' ; import { useObjectRef } from '../../useObjectRef' ; import { FormContext } from '../FormContext' ; export type CheckboxOnChangeEvent < T > = ( value : boolean , name : T ) => void ; export type CheckboxStateOptions < TKey extends string > = { value : string | undefined ; defaultValue : string | undefined ; checked : boolean | undefined ; defaultChecked : boolean | undefined ; } & ( { state : undefined ; name : string | undefined ; onChange : CheckboxOnChangeEvent < string | undefined > | undefined ; } | { state : Record < TKey , boolean | undefined | null | string | string [ ] > | undefined ; name : TKey ; onChange : CheckboxOnChangeEvent < TKey > | undefined ; } ) ; interface ICheckboxState { checked : boolean | undefined ; change : ( event : React . ChangeEvent < HTMLInputElement > ) => void ; } export function useCheckboxState < TKey extends string > ( options ) { const [ count , refresh ] = useState ( 0 ) ; const context = useContext ( FormContext ) ; const controlledValue = options . value ?? options . defaultValue ?? undefined ; const optionsRef = useObjectRef ( { ... options , context , count , value : controlledValue } ) ; const { state , name , value } = optionsRef ; let checked = optionsRef . checked ?? optionsRef . defaultChecked ?? undefined ; if ( state !== undefined && name !== undefined && name in state ) { const currentState = state [ name as TKey ] ; if ( typeof value === 'string' ) { checked = Array . isArray ( currentState ) ? currentState . includes ( value ) : currentState === value ; } else if ( typeof currentState === 'string' ) { checked = currentState . toLowerCase ( ) === 'true' ; } else { checked = ! ! currentState ; } } return useObjectRef < ICheckboxState > ( ( ) => ( { checked , change ( event ) { const { state , name , value , onChange , count , context } = optionsRef ; const checked = event . target . checked ; if ( state !== undefined && name !== undefined ) { const currentState = state [ name as TKey ] ; if ( typeof value === 'string' ) { if ( Array . isArray ( currentState ) ) { const elementIndex = currentState . indexOf ( value ) ; if ( checked && elementIndex === - 1 ) { currentState . push ( value ) ; } else if ( elementIndex !== - 1 ) { currentState . splice ( elementIndex , 1 ) ; } } else { state [ name as TKey ] = value ; } } else { state [ name as TKey ] = checked ; } } onChange ?. ( checked , name as TKey ) ; context ?. change ( checked , name ) ; refresh ( count + 1 ) ; } , } ) , { checked } , [ 'change' ] ) ; }