Skip to content

Commit d4e12f0

Browse files
committed
feat(carousel): add individual item intervals
Adds the ability to specify intervals per-item, which should hopefully match the functionality of the upstream feature. fixes #5305
1 parent d90ce3e commit d4e12f0

File tree

4 files changed

+87
-2
lines changed

4 files changed

+87
-2
lines changed

src/Carousel.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ function CarouselFunc(uncontrolledProps: CarouselProps, ref) {
250250
activeIndex || 0,
251251
);
252252

253+
const intervals = useRef<number[]>([]);
254+
253255
if (!isSliding && activeIndex !== renderedActiveIndex) {
254256
if (nextDirectionRef.current) {
255257
setDirection(nextDirectionRef.current);
@@ -492,17 +494,23 @@ function CarouselFunc(uncontrolledProps: CarouselProps, ref) {
492494
return undefined;
493495
}
494496

497+
let chosenInterval = interval || undefined;
498+
499+
if (activeIndex !== undefined && intervals.current[activeIndex]) {
500+
chosenInterval = intervals.current[activeIndex];
501+
}
502+
495503
intervalHandleRef.current = window.setInterval(
496504
document.visibilityState ? nextWhenVisible : next,
497-
interval || undefined,
505+
chosenInterval,
498506
);
499507

500508
return () => {
501509
if (intervalHandleRef.current !== null) {
502510
clearInterval(intervalHandleRef.current);
503511
}
504512
};
505-
}, [shouldPlay, next, interval, nextWhenVisible]);
513+
}, [shouldPlay, next, activeIndex, interval, nextWhenVisible]);
506514

507515
const indicatorOnClicks = useMemo(
508516
() =>
@@ -547,6 +555,7 @@ function CarouselFunc(uncontrolledProps: CarouselProps, ref) {
547555
<div className={`${prefix}-inner`}>
548556
{map(children, (child, index) => {
549557
const isActive = index === renderedActiveIndex;
558+
intervals.current[index] = child.props.interval as number;
550559

551560
return slide ? (
552561
<Transition

test/CarouselSpec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,39 @@ describe('<Carousel>', () => {
315315
expect(onSelectSpy).to.have.been.calledOnce;
316316
});
317317

318+
it('should go through the items given the specified intervals', () => {
319+
const defaultInterval = 5000;
320+
const intervals = [
321+
1000,
322+
500,
323+
defaultInterval, // to test for no interval specified, it should be the default
324+
];
325+
const itemsWithIntervals = [
326+
<Carousel.Item key={1} interval={intervals[0]}>
327+
Item 1 content
328+
</Carousel.Item>,
329+
<Carousel.Item key={2} interval={intervals[1]}>
330+
Item 2 content
331+
</Carousel.Item>,
332+
<Carousel.Item key={3}>Item 3 content</Carousel.Item>,
333+
];
334+
335+
const onSelectSpy = sinon.spy();
336+
mount(
337+
<Carousel interval={defaultInterval} onSelect={onSelectSpy}>
338+
{itemsWithIntervals}
339+
</Carousel>,
340+
);
341+
342+
const total = intervals.reduce((sum, current) => sum + current, 0);
343+
clock.tick(total * 1.1);
344+
345+
expect(onSelectSpy).to.have.been.calledThrice;
346+
expect(onSelectSpy.firstCall).to.have.been.calledWith(1);
347+
expect(onSelectSpy.secondCall).to.have.been.calledWith(2);
348+
expect(onSelectSpy.thirdCall).to.have.been.calledWith(0);
349+
});
350+
318351
it('should stop going through items on hover and continue afterwards', () => {
319352
const onSelectSpy = sinon.spy();
320353
const interval = 500;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<Carousel>
2+
<Carousel.Item interval={1000}>
3+
<img
4+
className="d-block w-100"
5+
src="holder.js/800x400?text=First slide&bg=373940"
6+
alt="First slide"
7+
/>
8+
<Carousel.Caption>
9+
<h3>First slide label</h3>
10+
<p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>
11+
</Carousel.Caption>
12+
</Carousel.Item>
13+
<Carousel.Item interval={500}>
14+
<img
15+
className="d-block w-100"
16+
src="holder.js/800x400?text=Second slide&bg=282c34"
17+
alt="Third slide"
18+
/>
19+
<Carousel.Caption>
20+
<h3>Second slide label</h3>
21+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
22+
</Carousel.Caption>
23+
</Carousel.Item>
24+
<Carousel.Item>
25+
<img
26+
className="d-block w-100"
27+
src="holder.js/800x400?text=Third slide&bg=20232a"
28+
alt="Third slide"
29+
/>
30+
<Carousel.Caption>
31+
<h3>Third slide label</h3>
32+
<p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>
33+
</Carousel.Caption>
34+
</Carousel.Item>
35+
</Carousel>;

www/src/pages/components/carousel.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import ComponentApi from '../../components/ComponentApi';
44
import ReactPlayground from '../../components/ReactPlayground';
55
import CarouselControlled from '../../examples/Carousel/Controlled';
66
import CarouselUncontrolled from '../../examples/Carousel/Uncontrolled';
7+
import IndividualIntervals from '../../examples/Carousel/IndividualIntervals';
78

89
# Carousels
910

@@ -29,6 +30,13 @@ You can also _control_ the Carousel state, via the
2930

3031
<ReactPlayground codeText={CarouselControlled} />
3132

33+
## Individual Item Intervals
34+
35+
You can specify individual intervals for each carousel item via the `interval`
36+
prop.
37+
38+
<ReactPlayground codeText={IndividualIntervals} />
39+
3240
## API
3341

3442
<ComponentApi metadata={props.data.carousel} />

0 commit comments

Comments
 (0)