import { DependencyList , useEffect , useMemo , useState , ChangeEvent } from 'react' ; import useHandler from '../../hooks/useHandler' ; param activeID param allIDs param resetDependencies returns const useItemsSelection = ( activeID , allIDs , resetDependencies ) => { const [ checkedMap , setCheckedMap ] = useState < { [ ID ] : boolean ; } > ( { } ) ; const [ lastChecked , setLastChecked ] = useState < string > ( '' ) ; const isChecked = ( ID ) => ! ! checkedMap [ ID ] ; useEffect ( ( ) => setCheckedMap ( { } ) , resetDependencies ) ; const checkedIDs = useMemo ( ( ) => { return Object . entries ( checkedMap ) . reduce < string [ ] > ( ( acc , [ ID , isChecked ] ) => { if ( ! isChecked ) { return acc ; } acc . push ( ID ) ; return acc ; } , [ ] ) ; } , [ checkedMap ] ) ; const selectedIDs = useMemo ( ( ) => { if ( checkedIDs . length ) { return checkedIDs ; } if ( activeID ) { return [ activeID ] ; } return [ ] ; } , [ checkedIDs , activeID ] ) ; /**
     * Put *IDs* to *checked* state
     * Uncheck others if *replace* is true
     */ const handleCheck = useHandler ( ( IDs , checked , replace ) => { setCheckedMap ( allIDs . reduce < { [ ID ] : boolean ; } > ( ( acc , ID ) => { const wasChecked = isChecked ( ID ) ; const toCheck = IDs . includes ( ID ) ; let value ; if ( toCheck ) { value = checked ; } else if ( replace ) { value = ! checked ; } else { value = wasChecked ; } acc [ ID ] = value ; return acc ; } , { } ) ) ; setLastChecked ( '' ) ; } ) ; /**
     * Check or uncheck all items
     */ const handleCheckAll = useHandler ( ( check ) => check ? handleCheck ( allIDs , true , true ) : handleCheck ( [ ] , true , true ) ) ; /**
     * Just check the given id, nothing more
     */ const handleCheckOnlyOne = useHandler ( ( id ) => { handleCheck ( [ id ] , ! isChecked ( id ) , false ) ; setLastChecked ( id ) ; } ) ; /**
     * Check all items from the last checked to the given id
     */ const handleCheckRange = useHandler ( ( id ) => { const ids = [ id ] ; if ( lastChecked ) { const start = allIDs . findIndex ( ( ID ) => ID === id ) ; const end = allIDs . findIndex ( ( ID ) => ID === lastChecked ) ; ids . push ( ... allIDs . slice ( Math . min ( start , end ) , Math . max ( start , end ) + 1 ) ) ; } handleCheck ( ids , ! isChecked ( id ) , false ) ; setLastChecked ( id ) ; } ) ; /**
     * Check only one or check range depending on the shift key value in the event
     */ const handleCheckOne = useHandler ( ( event , id ) => { const { shiftKey } = event . nativeEvent as any ; if ( shiftKey ) { handleCheckRange ( id ) ; } else { handleCheckOnlyOne ( id ) ; } } ) ; useEffect ( ( ) => { const filteredCheckedIDs = checkedIDs . filter ( ( id ) => allIDs . includes ( id ) ) ; if ( filteredCheckedIDs . length !== checkedIDs . length ) { handleCheck ( filteredCheckedIDs , true , true ) ; } } , [ allIDs ] ) ; return { checkedIDs , selectedIDs , handleCheck , handleCheckAll , handleCheckOne , handleCheckOnlyOne , handleCheckRange , } ; } ; export default useItemsSelection ;