UNPKG

3.49 kBJavaScriptView Raw
1import React from 'react';
2import PropTypes from 'prop-types';
3import classNames from 'classnames';
4import { Transition } from 'react-transition-group';
5import { CarouselContext } from './CarouselContext';
6import {
7 mapToCssModules,
8 TransitionTimeouts,
9 TransitionStatuses,
10 tagPropType,
11} from './utils';
12
13class CarouselItem extends React.Component {
14 constructor(props) {
15 super(props);
16
17 this.state = {
18 startAnimation: false,
19 };
20
21 this.onEnter = this.onEnter.bind(this);
22 this.onEntering = this.onEntering.bind(this);
23 this.onExit = this.onExit.bind(this);
24 this.onExiting = this.onExiting.bind(this);
25 this.onExited = this.onExited.bind(this);
26 }
27
28 onEnter(node, isAppearing) {
29 this.setState({ startAnimation: false });
30 this.props.onEnter(node, isAppearing);
31 }
32
33 onEntering(node, isAppearing) {
34 // getting this variable triggers a reflow
35 const { offsetHeight } = node;
36 this.setState({ startAnimation: true });
37 this.props.onEntering(node, isAppearing);
38 return offsetHeight;
39 }
40
41 onExit(node) {
42 this.setState({ startAnimation: false });
43 this.props.onExit(node);
44 }
45
46 onExiting(node) {
47 this.setState({ startAnimation: true });
48 node.dispatchEvent(new CustomEvent('slide.bs.carousel'));
49 this.props.onExiting(node);
50 }
51
52 onExited(node) {
53 node.dispatchEvent(new CustomEvent('slid.bs.carousel'));
54 this.props.onExited(node);
55 }
56
57 render() {
58 const {
59 in: isIn,
60 children,
61 cssModule,
62 slide = true,
63 tag: Tag = 'div',
64 className,
65 ...transitionProps
66 } = this.props;
67
68 return (
69 <Transition
70 {...transitionProps}
71 enter={slide}
72 exit={slide}
73 in={isIn}
74 onEnter={this.onEnter}
75 onEntering={this.onEntering}
76 onExit={this.onExit}
77 onExiting={this.onExiting}
78 onExited={this.onExited}
79 >
80 {(status) => {
81 const { direction } = this.context;
82 const isActive =
83 status === TransitionStatuses.ENTERED ||
84 status === TransitionStatuses.EXITING;
85 const directionClassName =
86 (status === TransitionStatuses.ENTERING ||
87 status === TransitionStatuses.EXITING) &&
88 this.state.startAnimation &&
89 (direction === 'end' ? 'carousel-item-start' : 'carousel-item-end');
90 const orderClassName =
91 status === TransitionStatuses.ENTERING &&
92 (direction === 'end' ? 'carousel-item-next' : 'carousel-item-prev');
93 const itemClasses = mapToCssModules(
94 classNames(
95 className,
96 'carousel-item',
97 isActive && 'active',
98 directionClassName,
99 orderClassName,
100 ),
101 cssModule,
102 );
103
104 return <Tag className={itemClasses}>{children}</Tag>;
105 }}
106 </Transition>
107 );
108 }
109}
110
111CarouselItem.propTypes = {
112 ...Transition.propTypes,
113 /** Set a custom element for this component */
114 tag: tagPropType,
115 in: PropTypes.bool,
116 /** Change underlying component's CSS base class name */
117 cssModule: PropTypes.object,
118 children: PropTypes.node,
119 /** Enable/disable animation */
120 slide: PropTypes.bool,
121 /** Add custom class */
122 className: PropTypes.string,
123};
124
125CarouselItem.defaultProps = {
126 ...Transition.defaultProps,
127 timeout: TransitionTimeouts.Carousel,
128};
129
130CarouselItem.contextType = CarouselContext;
131
132export default CarouselItem;