import type { RefObject } from 'react'; import { useIntersectionObserver } from '../../../hooks/useIntersectionObserver'; import useSyncEffect from '../../../hooks/useSyncEffect'; import { useCallback, useRef, useState } from '../../../lib/teact/teact'; import { ANIMATION_END_DELAY } from '../../../config'; import animateScroll from '../../../util/animateScroll'; import { REM } from '../helpers/mediaDimensions'; const STICKER_INTERSECTION_THROTTLE = 200; const STICKER_INTERSECTION_MARGIN = 100; const SLIDE_TRANSITION_DURATION = 350 + ANIMATION_END_DELAY; const SCROLL_MAX_DISTANCE_WHEN_CLOSE = 200; const SCROLL_MAX_DISTANCE_WHEN_FAR = 80; const FOCUS_MARGIN = 0.5 * REM; export function useStickerPickerObservers( containerRef: RefObject, headerRef: RefObject, idPrefix: string, isHidden?: boolean, ) { const stickerSetIntersectionsRef = useRef([]); const [activeSetIndex, setActiveSetIndex] = useState(0); const { observe: observeIntersectionForSet, freeze: freezeForSet, unfreeze: unfreezeForSet, } = useIntersectionObserver({ rootRef: containerRef, }, (entries) => { const stickerSetIntersections = stickerSetIntersectionsRef.current; entries.forEach((entry) => { const index = Number(entry.target.id.replace(`${idPrefix}-`, '')); stickerSetIntersections[index] = entry.isIntersecting; }); const minIntersectingIndex = stickerSetIntersections.reduce((lowestIndex, isIntersecting, index) => { return isIntersecting && index < lowestIndex ? index : lowestIndex; }, Infinity); if (minIntersectingIndex === Infinity) { return; } setActiveSetIndex(minIntersectingIndex); }); const { observe: observeIntersectionForShowingItems, freeze: freezeForShowingItems, unfreeze: unfreezeForShowingItems, } = useIntersectionObserver({ rootRef: containerRef, throttleMs: STICKER_INTERSECTION_THROTTLE, margin: STICKER_INTERSECTION_MARGIN, }); const { observe: observeIntersectionForPlayingItems, } = useIntersectionObserver({ rootRef: containerRef, throttleMs: STICKER_INTERSECTION_THROTTLE, margin: STICKER_INTERSECTION_MARGIN, }); const { observe: observeIntersectionForCovers, } = useIntersectionObserver({ rootRef: headerRef, }); useSyncEffect(() => { if (isHidden) { freezeForSet(); freezeForShowingItems(); } else { setTimeout(() => { unfreezeForShowingItems(); unfreezeForSet(); }, SLIDE_TRANSITION_DURATION); } }, [freezeForSet, freezeForShowingItems, isHidden, unfreezeForSet, unfreezeForShowingItems]); const selectStickerSet = useCallback((index: number) => { setActiveSetIndex((currentIndex) => { const stickerSetEl = document.getElementById(`${idPrefix}-${index}`)!; const isClose = Math.abs(currentIndex - index) === 1; animateScroll( containerRef.current!, stickerSetEl, 'start', FOCUS_MARGIN, isClose ? SCROLL_MAX_DISTANCE_WHEN_CLOSE : SCROLL_MAX_DISTANCE_WHEN_FAR, ); return index; }); }, [containerRef, idPrefix]); return { activeSetIndex, observeIntersectionForSet, observeIntersectionForShowingItems, observeIntersectionForPlayingItems, observeIntersectionForCovers, selectStickerSet, }; }