import {type RefObject, useEffect, useRef} from 'react'; import {useStableCallback} from '@rozhkov/react-useful-hooks'; import {useEffectWithDynamicDepsLength} from '../../../utils/react'; import type {ListMethods} from '../../types'; const SYNC_SCROLL_DELAY_MS = 100; const useSyncScrollEffect = ({ listRef, value, valueIndex, extraValues = [], activeIndexRef, touching, enableSyncScrollAfterScrollEnd, }: { listRef: RefObject; value: unknown; valueIndex: number; extraValues: unknown[] | undefined; activeIndexRef: RefObject; touching: boolean; enableSyncScrollAfterScrollEnd: boolean; }) => { const timeoutId = useRef | undefined>( undefined, ); const isScrollingRef = useRef(false); const prevEnableSyncScrollAfterScrollEnd = useRef( enableSyncScrollAfterScrollEnd, ); const cancelSyncScroll = useStableCallback(() => { clearTimeout(timeoutId.current); timeoutId.current = undefined; }); const syncScroll = useStableCallback(() => { if ( listRef.current == null || touching || activeIndexRef.current === valueIndex ) { return; } listRef.current.scrollToIndex({ index: valueIndex, animated: true, }); }); const scheduleSyncScroll = useStableCallback((delay: number) => { cancelSyncScroll(); timeoutId.current = setTimeout(() => { timeoutId.current = undefined; syncScroll(); }, delay); }); useEffect(() => cancelSyncScroll, [cancelSyncScroll]); useEffect(() => { const prevEnabled = prevEnableSyncScrollAfterScrollEnd.current; prevEnableSyncScrollAfterScrollEnd.current = enableSyncScrollAfterScrollEnd; if (!enableSyncScrollAfterScrollEnd) { cancelSyncScroll(); return; } if (!prevEnabled && value !== undefined && !isScrollingRef.current) { scheduleSyncScroll(SYNC_SCROLL_DELAY_MS); } }, [ cancelSyncScroll, enableSyncScrollAfterScrollEnd, scheduleSyncScroll, value, ]); useEffectWithDynamicDepsLength(() => { if (value === undefined) { return; } scheduleSyncScroll(0); }, [valueIndex, ...extraValues]); const onScrollStart = useStableCallback(() => { isScrollingRef.current = true; cancelSyncScroll(); }); const onScrollEnd = useStableCallback(() => { isScrollingRef.current = false; if (enableSyncScrollAfterScrollEnd && value !== undefined) { scheduleSyncScroll(SYNC_SCROLL_DELAY_MS); } }); return { onScrollStart, onScrollEnd, }; }; export default useSyncScrollEffect;