import React, { useCallback, useEffect, useRef, useState } from 'react'; import { Dimensions, FlatList, ListRenderItemInfo, ScaledSize, View, ViewToken, } from 'react-native'; import { isFunction } from '@aws-amplify/ui'; import CarouselPageIndicator from './CarouselPageIndicator'; import { VIEWABILITY_CONFIG } from './constants'; import { styles } from './styles'; import { CarouselProps } from './types'; export default function Carousel( props: CarouselProps ): JSX.Element | null { const { data, indicatorActiveStyle, indicatorInactiveStyle, renderItem, style, } = props; const flatListRef = useRef(null); const indexRef = useRef(0); const [currentIndex, setCurrentIndex] = useState(0); const windowWidthRef = useRef(Dimensions.get('window').width); const [width, setWidth] = useState(windowWidthRef.current); const onViewableItemsChanged = useRef( ({ viewableItems }: { viewableItems: ViewToken[] }) => { if (viewableItems.length !== 1) { return; } const [item] = viewableItems; indexRef.current = item.index; setCurrentIndex(indexRef.current); } ); const updateOrientation = useCallback((updatedWidth: number) => { if (windowWidthRef.current !== updatedWidth) { windowWidthRef.current = updatedWidth; setWidth(updatedWidth); } }, []); useEffect(() => { // on width change (due to orientation change), jump to the new index offset flatListRef?.current?.scrollToOffset({ offset: width * indexRef.current!, animated: false, }); }, [width]); useEffect(() => { const orientationHandler = ({ window }: { window: ScaledSize }) => { updateOrientation(window.width); }; const subscription = Dimensions.addEventListener( 'change', orientationHandler ); // Clean up listener. Dimensions.removeEventListener is deprecated as of React Native 0.65 but it is technically // available so try to remove via a `EmitterSubscription` first before falling back to `removeEventListener` return () => { if (isFunction(subscription?.remove)) { subscription.remove(); } else { Dimensions.removeEventListener('change', orientationHandler); } }; }, [updateOrientation]); const carouselRenderItem = (renderInfo: ListRenderItemInfo) => ( {renderItem(renderInfo)} ); if (!data?.length) { return null; } return ( <> ); }