import * as React from 'react' ; import { useCallbackRef } from '@radix-ui/react-use-callback-ref' ; type UseControllableStateParams < T > = { prop ? : T | undefined ; defaultProp ? : T | undefined ; onChange ? : ( state : T ) => void ; } ; type SetStateFn < T > = ( prevState ? : T ) => T ; function useControllableState < T > ( { prop , defaultProp , onChange = ( ) => { } , } ) { const [ uncontrolledProp , setUncontrolledProp ] = useUncontrolledState ( { defaultProp , onChange } ) ; const isControlled = prop !== undefined ; const value = isControlled ? prop : uncontrolledProp ; const handleChange = useCallbackRef ( onChange ) ; const setValue = React . useCallback ( ( nextValue ) => { if ( isControlled ) { const setter = nextValue as SetStateFn < T > ; const value = typeof nextValue === 'function' ? setter ( prop ) : nextValue ; if ( value !== prop ) handleChange ( value as T ) ; } else { setUncontrolledProp ( nextValue ) ; } } , [ isControlled , prop , setUncontrolledProp , handleChange ] ) ; return [ value , setValue ] as const ; } function useUncontrolledState < T > ( { defaultProp , onChange , } ) { const uncontrolledState = React . useState < T | undefined > ( defaultProp ) ; const [ value ] = uncontrolledState ; const prevValueRef = React . useRef ( value ) ; const handleChange = useCallbackRef ( onChange ) ; React . useEffect ( ( ) => { if ( prevValueRef . current !== value ) { handleChange ( value as T ) ; prevValueRef . current = value ; } } , [ value , prevValueRef , handleChange ] ) ; return uncontrolledState ; } export { useControllableState } ;