import { MutableRefObject } from 'react' ; import { animatedScrollToX , animatedScrollToY , TimingFunction } from '../../utils' ; import { ScrollAxis , ScrollAlign } from './types' ; const positionModByScrollAlign = ( { scrollAlign , position , carouselSize , itemSize , offset , scrollStart , axis , } ) => { if ( scrollAlign === 'start' ) { const inaccuracy = 1 ; const paddingOffset = axis === 'y' ? offset - itemSize / 2 + inaccuracy : 0 ; return position + paddingOffset ; } if ( scrollAlign === 'center' ) { return position - carouselSize / 2 + itemSize / 2 ; } if ( scrollAlign === 'end' ) { return position - carouselSize + itemSize + offset ; } if ( scrollAlign === 'activeDirection' ) { if ( position >= scrollStart + carouselSize - itemSize ) { return position - carouselSize + itemSize + offset ; } if ( position > scrollStart ) { return scrollStart ; } } return position ; } ; /**
 * Подсчет скролла до переданного индекса.
 */ export const getCalculatedPos = ( { scrollEl , items , axis , index , offset , scrollAlign , } ) => { let position = scrollAlign === 'center' ? offset : 0 ; let carouselSize ; let itemSize ; let scrollStart ; if ( ! items [ index ] ) { return position ; } for ( let i = 0 ; i < index ; i ++ ) { if ( axis === 'x' ) { position += items [ i ] . current ?. offsetWidth || 0 ; } else { position += items [ i ] . current ?. offsetHeight || 0 ; } } if ( axis === 'x' ) { carouselSize = scrollEl . offsetWidth ; itemSize = items [ index ] . current ?. offsetWidth || 0 ; scrollStart = scrollEl . scrollLeft ; } else { carouselSize = scrollEl . offsetHeight ; itemSize = items [ index ] . current ?. offsetHeight || 0 ; scrollStart = scrollEl . scrollTop ; } return positionModByScrollAlign ( { scrollAlign , position , carouselSize , itemSize , offset , scrollStart , axis , } ) ; } ; /**
 * Подсчет смещения из-за паддингов.
 */ export const getCalculatedOffset = ( scrollEl , trackEl , axis ) => { const paddingProp = axis === 'x' ? 'paddingLeft' : 'paddingTop' ; return parseInt ( getComputedStyle ( scrollEl ) [ paddingProp ] , 10 ) + parseInt ( getComputedStyle ( trackEl ) [ paddingProp ] , 10 ) ; } ; /**
 * Прокрутка к указанной позиции с анимацией или без.
 */ export const scrollToPos = ( { scrollEl , pos , axis , animated , duration , timingFunction , } ) => { if ( axis === 'x' && Math . abs ( pos - scrollEl . scrollLeft ) > 1 ) { if ( animated ) { animatedScrollToX ( scrollEl , pos , duration , timingFunction ) ; } else { scrollEl . scrollTo ( { left : pos } ) ; } } if ( axis === 'y' && Math . abs ( pos - scrollEl . scrollTop ) > 1 ) { if ( animated ) { animatedScrollToY ( scrollEl , pos , duration , timingFunction ) ; } else { scrollEl . scrollTo ( { top : pos } ) ; } } } ; const round = ( n ) => Math . round ( n * 100 ) / 100 ; /**
 * Получить позицию (слот) айтема в каруселе.
 * Каждый айтем имеет свой слот относительно вьюпорта карусели.
 */ export const getItemSlot = ( itemIndex , itemEnd , itemSize , scrollStart , scrollSize , scrollAlign , prevIndex = 0 , offset = 0 ) => { /**
     * Граница и центр скролла (видимой части).
     * Смещение + размер.
     */ const scrollEnd = scrollStart + scrollSize ; const scrollCenter = scrollStart + scrollSize / 2 ; const itemCenter = itemEnd - itemSize / 2 ; if ( scrollAlign === 'center' ) { return round ( ( itemCenter - scrollCenter ) / itemSize ) ; } if ( scrollAlign === 'start' ) { return round ( ( itemEnd - itemSize - scrollStart ) / itemSize ) ; } if ( scrollAlign === 'end' ) { return round ( ( itemEnd - ( scrollSize + scrollStart ) ) / itemSize ) ; } if ( scrollAlign === 'activeDirection' ) { const prevStart = offset + itemSize * prevIndex ; const prevEnd = prevStart + itemSize ; const prevVisible = prevEnd > scrollStart && prevStart < scrollEnd ; if ( ! prevVisible ) { if ( prevIndex < itemIndex ) { return round ( ( itemEnd - ( scrollSize + scrollStart ) ) / itemSize ) ; } return round ( ( itemEnd - itemSize - scrollStart ) / itemSize ) ; } } return null ; } ;