1- import React from "react" ;
1+ import React , { Children } from "react" ;
22import PropTypes from "prop-types" ;
33import ResizeObserver from "resize-observer-polyfill" ;
44import Only from "react-only-when" ;
@@ -49,10 +49,11 @@ class Carousel extends React.Component {
4949 } = this . props ;
5050 const { activeIndex, sliderContainerWidth } = this . state ;
5151 const nextItem = this . getNextItemIndex ( activeIndex , false ) ;
52-
52+ const currentChildrenLength = Children . toArray ( children ) . length ;
53+ const prevChildrenLength = Children . toArray ( prevProps . children ) . length ;
5354 // update pages (for pagination)
5455 if (
55- prevProps . children !== children ||
56+ prevChildrenLength !== currentChildrenLength ||
5657 prevProps . itemsToShow !== itemsToShow ||
5758 prevProps . itemsToScroll !== itemsToScroll ||
5859 prevProps . breakPoints !== breakPoints ||
@@ -70,18 +71,18 @@ class Carousel extends React.Component {
7071 this . removeAutoPlay ( ) ;
7172 }
7273
73- if ( prevProps . children . length > children . length ) {
74+ if ( prevChildrenLength !== currentChildrenLength ) {
7475 const {
7576 itemsToShow : calculatedItemsToShow
7677 } = this . getDerivedPropsFromBreakPoint ( ) ;
7778 // number of items is reduced (we don't care if number of items is increased)
7879 // we need to check if our current index is not out of boundaries
7980 // we need to include itemsToShow so we can fill up the slots
80- const lastIndex = children . length - 1 ;
81+ const lastIndex = currentChildrenLength - 1 ;
8182 const isOutOfRange = activeIndex + calculatedItemsToShow > lastIndex ;
8283 if ( isOutOfRange ) {
8384 // we are out of boundaries, go "back" to last item of the list (respect itemsToShow)
84- this . goTo ( Math . max ( 0 , children . length - calculatedItemsToShow ) ) ;
85+ this . goTo ( Math . max ( 0 , currentChildrenLength - calculatedItemsToShow ) ) ;
8586 }
8687 }
8788 }
@@ -173,7 +174,7 @@ class Carousel extends React.Component {
173174 transitionMs
174175 } = this . getDerivedPropsFromBreakPoint ( ) ;
175176 const { childWidth, childHeight, activeIndex } = state ;
176- const totalItems = children . length ;
177+ const totalItems = Children . toArray ( children ) . length ;
177178 const hiddenSlots = totalItems - itemsToShow ;
178179 let moveBy = activeIndex * - 1 ;
179180 const emptySlots = itemsToShow - ( totalItems - activeIndex ) ;
@@ -200,34 +201,51 @@ class Carousel extends React.Component {
200201 children,
201202 itemsToShow
202203 } = this . getDerivedPropsFromBreakPoint ( ) ;
203- const { height } = sliderNode . contentRect ;
204+ const { height : sliderHeight } = sliderNode . contentRect ;
204205 const nextState = { } ;
206+ const childrenLength = Children . toArray ( children ) . length ;
205207 if ( verticalMode ) {
206- const childHeight = height / children . length ;
207- nextState . rootHeight = childHeight * itemsToShow ;
208+ const childHeight = sliderHeight / childrenLength ;
209+ // We use Math.min because don't want to make the child smaller
210+ // if number of children is smaller than itemsToShow.
211+ // Because we will have "empty slots"
212+ nextState . rootHeight =
213+ childHeight * Math . min ( childrenLength , itemsToShow ) ;
208214 nextState . childHeight = childHeight ;
209215 } else {
210- nextState . rootHeight = height ;
216+ nextState . rootHeight = sliderHeight ;
211217 }
212218 this . setState ( nextState ) ;
213219 } ;
214220
215221 onContainerResize = sliderContainerNode => {
216- const { width } = sliderContainerNode . contentRect ;
222+ const { width : sliderContainerWidth } = sliderContainerNode . contentRect ;
217223 // update slider container width
218224 // disable animation on resize see https://github.com/sag1v/react-elastic-carousel/issues/94
219- this . setState ( { sliderContainerWidth : width , transitionMs : 0 } , ( ) => {
225+ this . setState ( { sliderContainerWidth, transitionMs : 0 } , ( ) => {
220226 // we must get these props inside setState (get future props because its async)
221227 const {
222228 onResize,
223229 verticalMode,
224- itemsToShow
230+ itemsToShow,
231+ children
225232 } = this . getDerivedPropsFromBreakPoint ( ) ;
226233
227234 /* based on slider container's width, get num of items to show
228235 * and calculate child's width (and update it in state)
229236 */
230- const childWidth = verticalMode ? width : width / itemsToShow ;
237+ const childrenLength = Children . toArray ( children ) . length ;
238+ let childWidth = 0 ;
239+ if ( verticalMode ) {
240+ childWidth = sliderContainerWidth ;
241+ } else {
242+ // We use Math.min because don't want to make the child smaller
243+ // if number of children is smaller than itemsToShow.
244+ // Because we will have "empty slots"
245+ childWidth =
246+ sliderContainerWidth / Math . min ( childrenLength , itemsToShow ) ;
247+ }
248+
231249 this . setState (
232250 state => ( { childWidth } ) ,
233251 ( ) => {
@@ -263,7 +281,7 @@ class Carousel extends React.Component {
263281 const { children } = this . props ;
264282 // support decimal itemsToShow
265283 const roundedIdx = Math . round ( index ) ;
266- const child = children [ roundedIdx ] ;
284+ const child = Children . toArray ( children ) [ roundedIdx ] ;
267285 return { item : child . props , index : roundedIdx } ;
268286 } ;
269287
@@ -273,8 +291,9 @@ class Carousel extends React.Component {
273291 itemsToShow,
274292 itemsToScroll
275293 } = this . getDerivedPropsFromBreakPoint ( ) ;
276- const notEnoughItemsToShow = itemsToShow > children . length ;
277- let limit = getPrev ? 0 : children . length - itemsToShow ;
294+ const childrenLength = Children . toArray ( children ) . length ;
295+ const notEnoughItemsToShow = itemsToShow > childrenLength ;
296+ let limit = getPrev ? 0 : childrenLength - itemsToShow ;
278297
279298 if ( notEnoughItemsToShow ) {
280299 limit = 0 ; // basically don't move
@@ -292,7 +311,7 @@ class Carousel extends React.Component {
292311 const nextItemIndex = this . getNextItemIndex ( activeIndex , getPrev ) ;
293312 // support decimal itemsToShow
294313 const roundedIdx = Math . round ( nextItemIndex ) ;
295- const asElement = children [ roundedIdx ] ;
314+ const asElement = Children . toArray ( children ) [ roundedIdx ] ;
296315 const asObj = { item : asElement . props , index : roundedIdx } ;
297316 return asObj ;
298317 } ;
@@ -323,8 +342,9 @@ class Carousel extends React.Component {
323342 } = this . getDerivedPropsFromBreakPoint ( ) ;
324343
325344 // determine how far can user swipe
345+ const childrenLength = Children . toArray ( children ) . length ;
326346 const isOnStart = activeIndex === 0 ;
327- const isOnEnd = activeIndex === children . length - itemsToShow ;
347+ const isOnEnd = activeIndex === childrenLength - itemsToShow ;
328348 const defaultDivider = 1.5 ;
329349 const largeDivider = itemsToShow * 2 ;
330350 let divider = defaultDivider ;
@@ -535,16 +555,17 @@ class Carousel extends React.Component {
535555 itemsToShow
536556 } = this . getDerivedPropsFromBreakPoint ( ) ;
537557 const { activeIndex } = this . state ;
558+ const childrenLength = Children . toArray ( children ) . length ;
538559 const isPrev = activeIndex > nextItemId ;
539560 const nextAvailbaleItem = this . getNextItemIndex ( activeIndex , isPrev ) ;
540561 const noChange = nextAvailbaleItem === activeIndex ;
541- const outOfBoundry = nextItemId + itemsToShow >= children . length ;
562+ const outOfBoundry = nextItemId + itemsToShow >= childrenLength ;
542563 if ( noChange ) {
543564 return ;
544565 }
545566 if ( outOfBoundry ) {
546567 // Either go to last index (respect itemsToShow) or 0 index if we can't fill the slider
547- nextItemId = Math . max ( 0 , children . length - itemsToShow ) ;
568+ nextItemId = Math . max ( 0 , childrenLength - itemsToShow ) ;
548569 }
549570 let direction = consts . NEXT ;
550571 let positionEndCb = this . onNextEnd ;
@@ -571,7 +592,8 @@ class Carousel extends React.Component {
571592
572593 getNumOfPages = ( ) => {
573594 const { children, itemsToShow } = this . getDerivedPropsFromBreakPoint ( ) ;
574- const numOfPages = Math . ceil ( children . length / itemsToShow ) ;
595+ const childrenLength = Children . toArray ( children ) . length ;
596+ const numOfPages = Math . ceil ( childrenLength / itemsToShow ) ;
575597 return numOfPages || 1 ;
576598 } ;
577599
@@ -681,7 +703,7 @@ class Carousel extends React.Component {
681703 >
682704 < Track
683705 verticalMode = { verticalMode }
684- children = { children }
706+ children = { Children . toArray ( children ) }
685707 childWidth = { childWidth }
686708 currentItem = { activeIndex }
687709 autoTabIndexVisibleItems = { autoTabIndexVisibleItems }
0 commit comments