@@ -23,17 +23,67 @@ export const Carousel = (props: CarouselProps<CarouselStyle>): ReactElement => {
2323
2424 const [ activeSlide , setActiveSlide ] = useState ( 0 ) ;
2525
26+ const [ firstItem , setFirstItem ] = useState ( 0 ) ;
27+
2628 const [ loading , setLoading ] = useState ( true ) ;
2729
2830 useEffect ( ( ) => {
29- if ( props . contentSource ?. status === ValueStatus . Available ) {
31+ if ( props . contentSource ?. status === ValueStatus . Available && loading ) {
32+ // Set initial index of the first item to show the associated active selection.
33+ const index =
34+ ( props . activeSelection ?. value
35+ ? props . contentSource ?. items ?. findIndex ( i => i . id === props . activeSelection ?. value ?. id )
36+ : 0 ) ?? 0 ;
37+ setFirstItem ( index ) ;
38+ setActiveSlide ( index ) ;
3039 setLoading ( false ) ;
3140 }
32- } , [ props . contentSource ] ) ;
41+ } , [ loading , props . activeSelection , props . contentSource ] ) ;
3342
34- const onSnap = useCallback ( ( index : number ) => {
35- setActiveSlide ( index ) ;
36- } , [ ] ) ;
43+ useEffect ( ( ) => {
44+ if ( carouselRef && props . activeSelection ) {
45+ let index = props . contentSource . items ?. findIndex ( i => i . id === props . activeSelection ?. value ?. id ) ?? 0 ;
46+ // Removed item that is active selection can not be found
47+ index = index >= 0 ? index : 0 ;
48+ // Should check carouselRef.currentIndex though this is not fast enough for update.
49+ if ( index !== activeSlide ) {
50+ // Update carousel when associated item is changed
51+ setActiveSlide ( index ) ;
52+ const animate = props . animateExpression ?. value ?? true ;
53+ // Async snap to index, use case add item is added before current selected
54+ setTimeout ( ( ) => {
55+ ( carouselRef as NativeCarousel < ObjectItem > ) . snapToItem ( index , animate ) ;
56+ } , 1 ) ;
57+ }
58+ }
59+ } , [ activeSlide , carouselRef , props . activeSelection , props . animateExpression , props . contentSource ] ) ;
60+
61+ useEffect ( ( ) => {
62+ if ( props . activeSelection && props . contentSource . status === "available" ) {
63+ // Check if selected item is still available, reset to index 0 or null
64+ let item = props . contentSource . items ?. find ( i => i . id === props . activeSelection ?. value ?. id ) ;
65+ if ( item == null ) {
66+ item = props . contentSource . items ?. [ 0 ] ;
67+ }
68+ if ( props . activeSelection . value ?. id !== item ?. id ) {
69+ // Set association when empty to first slide
70+ props . activeSelection . setValue ( item ) ;
71+ }
72+ }
73+ } , [ props . activeSelection , props . contentSource ] ) ;
74+
75+ const onSnap = useCallback (
76+ ( index : number ) => {
77+ setActiveSlide ( index ) ;
78+ if ( props . activeSelection ) {
79+ const item = props . contentSource ?. items ?. [ index ] ;
80+ if ( item ?. id !== props . activeSelection . value ?. id ) {
81+ props . activeSelection . setValue ( item ) ;
82+ }
83+ }
84+ } ,
85+ [ props . activeSelection , props . contentSource ]
86+ ) ;
3787
3888 const renderItem = useCallback ( ( { item, index } : { item : ObjectItem ; index : number } ) => {
3989 const viewStyle = layoutSpecificStyle . slideItem ;
@@ -97,7 +147,7 @@ export const Carousel = (props: CarouselProps<CarouselStyle>): ReactElement => {
97147 ) ;
98148 } , [ activeSlide , carouselRef , props . contentSource , props . showPagination ] ) ;
99149
100- const onLayout = ( event : LayoutChangeEvent ) => {
150+ const onLayout = ( event : LayoutChangeEvent ) : void => {
101151 let viewHeight = event . nativeEvent . layout . height ;
102152 const viewWidth = event . nativeEvent . layout . width ;
103153
@@ -149,7 +199,7 @@ export const Carousel = (props: CarouselProps<CarouselStyle>): ReactElement => {
149199 testID = { `${ props . name } $carousel` }
150200 activeSlideAlignment = { props . activeSlideAlignment }
151201 layout = "default"
152- firstItem = { 0 }
202+ firstItem = { firstItem }
153203 useScrollView
154204 enableSnap
155205 data = { props . contentSource . items }
0 commit comments