import {
NativeScrollEvent,
NativeSyntheticEvent,
ScrollView,
StyleSheet,
View,
} from 'react-native'
import {
getHorizontalMonthOffset,
getIndexFromVerticalOffset,
getMonthHeight,
getVerticalMonthsOffset,
montHeaderHeight,
} from './Month'
import { SwiperProps, useYearChange, isIndexWithinRange } from './SwiperUtils'
import {
estimatedMonthHeight,
getTotalMonths,
getBeginOffset,
} from './dateUtils'
import AutoSizer from './AutoSizer'
import { memo, useCallback, useRef, useState } from 'react'
import { sharedStyles } from '../shared/styles'
function getVisibleArray(
i: number,
{ isHorizontal, height }: { isHorizontal: boolean; height: number }
) {
if (isHorizontal || height < 700) {
return [i - 1, i, i + 1]
}
return [i - 2, i - 1, i, i + 1, i + 2]
}
function Swiper(props: SwiperProps) {
return (
{({ width, height }) => (
)}
)
}
function SwiperInner({
scrollMode,
renderItem,
renderHeader,
renderFooter,
selectedYear,
initialIndex,
width,
height,
startWeekOnMonday,
startYear,
endYear,
}: SwiperProps & { width: number; height: number }) {
const idx = useRef(initialIndex)
const isHorizontal = scrollMode === 'horizontal'
const [visibleIndexes, setVisibleIndexes] = useState(
getVisibleArray(initialIndex, { isHorizontal, height })
)
const parentRef = useRef(null)
const scrollTo = useCallback(
(index: number, animated: boolean) => {
if (!isIndexWithinRange(index, startYear, endYear)) {
return
}
idx.current = index
setVisibleIndexes(getVisibleArray(index, { isHorizontal, height }))
if (!parentRef.current) {
return
}
const offset = isHorizontal
? getHorizontalMonthOffset(index, width)
: getVerticalMonthsOffset(
index,
startWeekOnMonday,
startYear,
endYear
) - montHeaderHeight
if (isHorizontal) {
parentRef.current.scrollTo({
y: 0,
x: offset,
animated,
})
} else {
parentRef.current.scrollTo({
y: offset,
x: 0,
animated,
})
}
},
[
parentRef,
isHorizontal,
width,
height,
startWeekOnMonday,
startYear,
endYear,
]
)
const onPrev = useCallback(() => {
const newIndex = idx.current - 1
if (isIndexWithinRange(newIndex, startYear, endYear)) {
scrollTo(newIndex, true)
}
}, [scrollTo, idx, startYear, endYear])
const onNext = useCallback(() => {
const newIndex = idx.current + 1
if (isIndexWithinRange(newIndex, startYear, endYear)) {
scrollTo(newIndex, true)
}
}, [scrollTo, idx, startYear, endYear])
const scrollToInitial = useCallback(() => {
scrollTo(idx.current, false)
}, [scrollTo])
const onMomentumScrollEnd = useCallback(
(e: NativeSyntheticEvent) => {
const contentOffset = e.nativeEvent.contentOffset
const viewSize = e.nativeEvent.layoutMeasurement
const dynamicBeginOffset = getBeginOffset(startYear, endYear)
const newIndex = isHorizontal
? Math.round(contentOffset.x / viewSize.width)
: getIndexFromVerticalOffset(
contentOffset.y - dynamicBeginOffset,
startWeekOnMonday,
startYear,
endYear
)
if (newIndex === 0) {
return
}
if (!isIndexWithinRange(newIndex, startYear, endYear)) {
return
}
if (idx.current !== newIndex) {
idx.current = newIndex
setVisibleIndexes(getVisibleArray(newIndex, { isHorizontal, height }))
}
},
[idx, height, isHorizontal, startWeekOnMonday, startYear, endYear]
)
const renderProps = {
index: 0,
onPrev,
onNext,
}
useYearChange(
(newIndex) => {
if (newIndex && isIndexWithinRange(newIndex, startYear, endYear)) {
scrollTo(newIndex, false)
}
},
{
selectedYear,
currentIndexRef: idx,
startYear,
endYear,
}
)
return (
<>
{visibleIndexes
? new Array(visibleIndexes.length).fill(undefined).map((_, vi) => (
{renderItem({
index: visibleIndexes[vi],
onPrev: onPrev,
onNext: onNext,
})}
))
: null}
{renderHeader && renderHeader(renderProps)}
{renderFooter && renderFooter(renderProps)}
>
)
}
const styles = StyleSheet.create({
inner: {
position: 'relative',
},
})
export default memo(Swiper)