UNPKG

13.7 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime-corejs2/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");
6
7exports.__esModule = true;
8exports.default = void 0;
9
10var _extends2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/extends"));
11
12var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/objectWithoutPropertiesLoose"));
13
14var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/inheritsLoose"));
15
16var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime-corejs2/helpers/assertThisInitialized"));
17
18var _classnames = _interopRequireDefault(require("classnames"));
19
20var _react = _interopRequireWildcard(require("react"));
21
22var _propTypes = _interopRequireDefault(require("prop-types"));
23
24var _CarouselCaption = _interopRequireDefault(require("./CarouselCaption"));
25
26var _CarouselItem = _interopRequireDefault(require("./CarouselItem"));
27
28var _Glyphicon = _interopRequireDefault(require("./Glyphicon"));
29
30var _SafeAnchor = _interopRequireDefault(require("./SafeAnchor"));
31
32var _bootstrapUtils = require("./utils/bootstrapUtils");
33
34var _ValidComponentChildren = _interopRequireDefault(require("./utils/ValidComponentChildren"));
35
36// TODO: `slide` should be `animate`.
37// TODO: Use uncontrollable.
38var propTypes = {
39 slide: _propTypes.default.bool,
40 indicators: _propTypes.default.bool,
41
42 /**
43 * The amount of time to delay between automatically cycling an item.
44 * If `null`, carousel will not automatically cycle.
45 */
46 interval: _propTypes.default.number,
47 controls: _propTypes.default.bool,
48 pauseOnHover: _propTypes.default.bool,
49 wrap: _propTypes.default.bool,
50
51 /**
52 * Callback fired when the active item changes.
53 *
54 * ```js
55 * (eventKey: any, ?event: Object) => any
56 * ```
57 *
58 * If this callback takes two or more arguments, the second argument will
59 * be a persisted event object with `direction` set to the direction of the
60 * transition.
61 */
62 onSelect: _propTypes.default.func,
63 onSlideEnd: _propTypes.default.func,
64 activeIndex: _propTypes.default.number,
65 defaultActiveIndex: _propTypes.default.number,
66 direction: _propTypes.default.oneOf(['prev', 'next']),
67 prevIcon: _propTypes.default.node,
68
69 /**
70 * Label shown to screen readers only, can be used to show the previous element
71 * in the carousel.
72 * Set to null to deactivate.
73 */
74 prevLabel: _propTypes.default.string,
75 nextIcon: _propTypes.default.node,
76
77 /**
78 * Label shown to screen readers only, can be used to show the next element
79 * in the carousel.
80 * Set to null to deactivate.
81 */
82 nextLabel: _propTypes.default.string
83};
84var defaultProps = {
85 slide: true,
86 interval: 5000,
87 pauseOnHover: true,
88 wrap: true,
89 indicators: true,
90 controls: true,
91 prevIcon: _react.default.createElement(_Glyphicon.default, {
92 glyph: "chevron-left"
93 }),
94 prevLabel: 'Previous',
95 nextIcon: _react.default.createElement(_Glyphicon.default, {
96 glyph: "chevron-right"
97 }),
98 nextLabel: 'Next'
99};
100
101var Carousel =
102/*#__PURE__*/
103function (_React$Component) {
104 (0, _inheritsLoose2.default)(Carousel, _React$Component);
105
106 function Carousel(props, context) {
107 var _this;
108
109 _this = _React$Component.call(this, props, context) || this;
110 _this.handleMouseOver = _this.handleMouseOver.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
111 _this.handleMouseOut = _this.handleMouseOut.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
112 _this.handlePrev = _this.handlePrev.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
113 _this.handleNext = _this.handleNext.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
114 _this.handleItemAnimateOutEnd = _this.handleItemAnimateOutEnd.bind((0, _assertThisInitialized2.default)((0, _assertThisInitialized2.default)(_this)));
115 var defaultActiveIndex = props.defaultActiveIndex;
116 _this.state = {
117 activeIndex: defaultActiveIndex != null ? defaultActiveIndex : 0,
118 previousActiveIndex: null,
119 direction: null
120 };
121 _this.isUnmounted = false;
122 return _this;
123 }
124
125 var _proto = Carousel.prototype;
126
127 _proto.componentDidMount = function componentDidMount() {
128 this.waitForNext();
129 };
130
131 _proto.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
132 var activeIndex = this.getActiveIndex();
133
134 if (nextProps.activeIndex != null && nextProps.activeIndex !== activeIndex) {
135 clearTimeout(this.timeout);
136 this.setState({
137 previousActiveIndex: activeIndex,
138 direction: nextProps.direction != null ? nextProps.direction : this.getDirection(activeIndex, nextProps.activeIndex)
139 });
140 }
141
142 if (nextProps.activeIndex == null && this.state.activeIndex >= nextProps.children.length) {
143 this.setState({
144 activeIndex: 0,
145 previousActiveIndex: null,
146 direction: null
147 });
148 }
149 };
150
151 _proto.componentWillUnmount = function componentWillUnmount() {
152 clearTimeout(this.timeout);
153 this.isUnmounted = true;
154 };
155
156 _proto.getActiveIndex = function getActiveIndex() {
157 var activeIndexProp = this.props.activeIndex;
158 return activeIndexProp != null ? activeIndexProp : this.state.activeIndex;
159 };
160
161 _proto.getDirection = function getDirection(prevIndex, index) {
162 if (prevIndex === index) {
163 return null;
164 }
165
166 return prevIndex > index ? 'prev' : 'next';
167 };
168
169 _proto.handleItemAnimateOutEnd = function handleItemAnimateOutEnd() {
170 var _this2 = this;
171
172 this.setState({
173 previousActiveIndex: null,
174 direction: null
175 }, function () {
176 _this2.waitForNext();
177
178 if (_this2.props.onSlideEnd) {
179 _this2.props.onSlideEnd();
180 }
181 });
182 };
183
184 _proto.handleMouseOut = function handleMouseOut() {
185 if (this.isPaused) {
186 this.play();
187 }
188 };
189
190 _proto.handleMouseOver = function handleMouseOver() {
191 if (this.props.pauseOnHover) {
192 this.pause();
193 }
194 };
195
196 _proto.handleNext = function handleNext(e) {
197 var index = this.getActiveIndex() + 1;
198
199 var count = _ValidComponentChildren.default.count(this.props.children);
200
201 if (index > count - 1) {
202 if (!this.props.wrap) {
203 return;
204 }
205
206 index = 0;
207 }
208
209 this.select(index, e, 'next');
210 };
211
212 _proto.handlePrev = function handlePrev(e) {
213 var index = this.getActiveIndex() - 1;
214
215 if (index < 0) {
216 if (!this.props.wrap) {
217 return;
218 }
219
220 index = _ValidComponentChildren.default.count(this.props.children) - 1;
221 }
222
223 this.select(index, e, 'prev');
224 }; // This might be a public API.
225
226
227 _proto.pause = function pause() {
228 this.isPaused = true;
229 clearTimeout(this.timeout);
230 }; // This might be a public API.
231
232
233 _proto.play = function play() {
234 this.isPaused = false;
235 this.waitForNext();
236 };
237
238 _proto.select = function select(index, e, direction) {
239 clearTimeout(this.timeout); // TODO: Is this necessary? Seems like the only risk is if the component
240 // unmounts while handleItemAnimateOutEnd fires.
241
242 if (this.isUnmounted) {
243 return;
244 }
245
246 var previousActiveIndex = this.props.slide ? this.getActiveIndex() : null;
247 direction = direction || this.getDirection(previousActiveIndex, index);
248 var onSelect = this.props.onSelect;
249
250 if (onSelect) {
251 if (onSelect.length > 1) {
252 // React SyntheticEvents are pooled, so we need to remove this event
253 // from the pool to add a custom property. To avoid unnecessarily
254 // removing objects from the pool, only do this when the listener
255 // actually wants the event.
256 if (e) {
257 e.persist();
258 e.direction = direction;
259 } else {
260 e = {
261 direction: direction
262 };
263 }
264
265 onSelect(index, e);
266 } else {
267 onSelect(index);
268 }
269 }
270
271 if (this.props.activeIndex == null && index !== previousActiveIndex) {
272 if (this.state.previousActiveIndex != null) {
273 // If currently animating don't activate the new index.
274 // TODO: look into queueing this canceled call and
275 // animating after the current animation has ended.
276 return;
277 }
278
279 this.setState({
280 activeIndex: index,
281 previousActiveIndex: previousActiveIndex,
282 direction: direction
283 });
284 }
285 };
286
287 _proto.waitForNext = function waitForNext() {
288 var _this$props = this.props,
289 slide = _this$props.slide,
290 interval = _this$props.interval,
291 activeIndexProp = _this$props.activeIndex;
292
293 if (!this.isPaused && slide && interval && activeIndexProp == null) {
294 this.timeout = setTimeout(this.handleNext, interval);
295 }
296 };
297
298 _proto.renderControls = function renderControls(properties) {
299 var wrap = properties.wrap,
300 children = properties.children,
301 activeIndex = properties.activeIndex,
302 prevIcon = properties.prevIcon,
303 nextIcon = properties.nextIcon,
304 bsProps = properties.bsProps,
305 prevLabel = properties.prevLabel,
306 nextLabel = properties.nextLabel;
307 var controlClassName = (0, _bootstrapUtils.prefix)(bsProps, 'control');
308
309 var count = _ValidComponentChildren.default.count(children);
310
311 return [(wrap || activeIndex !== 0) && _react.default.createElement(_SafeAnchor.default, {
312 key: "prev",
313 className: (0, _classnames.default)(controlClassName, 'left'),
314 onClick: this.handlePrev
315 }, prevIcon, prevLabel && _react.default.createElement("span", {
316 className: "sr-only"
317 }, prevLabel)), (wrap || activeIndex !== count - 1) && _react.default.createElement(_SafeAnchor.default, {
318 key: "next",
319 className: (0, _classnames.default)(controlClassName, 'right'),
320 onClick: this.handleNext
321 }, nextIcon, nextLabel && _react.default.createElement("span", {
322 className: "sr-only"
323 }, nextLabel))];
324 };
325
326 _proto.renderIndicators = function renderIndicators(children, activeIndex, bsProps) {
327 var _this3 = this;
328
329 var indicators = [];
330
331 _ValidComponentChildren.default.forEach(children, function (child, index) {
332 indicators.push(_react.default.createElement("li", {
333 key: index,
334 className: index === activeIndex ? 'active' : null,
335 onClick: function onClick(e) {
336 return _this3.select(index, e);
337 }
338 }), // Force whitespace between indicator elements. Bootstrap requires
339 // this for correct spacing of elements.
340 ' ');
341 });
342
343 return _react.default.createElement("ol", {
344 className: (0, _bootstrapUtils.prefix)(bsProps, 'indicators')
345 }, indicators);
346 };
347
348 _proto.render = function render() {
349 var _this4 = this;
350
351 var _this$props2 = this.props,
352 slide = _this$props2.slide,
353 indicators = _this$props2.indicators,
354 controls = _this$props2.controls,
355 wrap = _this$props2.wrap,
356 prevIcon = _this$props2.prevIcon,
357 prevLabel = _this$props2.prevLabel,
358 nextIcon = _this$props2.nextIcon,
359 nextLabel = _this$props2.nextLabel,
360 className = _this$props2.className,
361 children = _this$props2.children,
362 props = (0, _objectWithoutPropertiesLoose2.default)(_this$props2, ["slide", "indicators", "controls", "wrap", "prevIcon", "prevLabel", "nextIcon", "nextLabel", "className", "children"]);
363 var _this$state = this.state,
364 previousActiveIndex = _this$state.previousActiveIndex,
365 direction = _this$state.direction;
366
367 var _splitBsPropsAndOmit = (0, _bootstrapUtils.splitBsPropsAndOmit)(props, ['interval', 'pauseOnHover', 'onSelect', 'onSlideEnd', 'activeIndex', // Accessed via this.getActiveIndex().
368 'defaultActiveIndex', 'direction']),
369 bsProps = _splitBsPropsAndOmit[0],
370 elementProps = _splitBsPropsAndOmit[1];
371
372 var activeIndex = this.getActiveIndex();
373 var classes = (0, _extends2.default)({}, (0, _bootstrapUtils.getClassSet)(bsProps), {
374 slide: slide
375 });
376 return _react.default.createElement("div", (0, _extends2.default)({}, elementProps, {
377 className: (0, _classnames.default)(className, classes),
378 onMouseOver: this.handleMouseOver,
379 onMouseOut: this.handleMouseOut
380 }), indicators && this.renderIndicators(children, activeIndex, bsProps), _react.default.createElement("div", {
381 className: (0, _bootstrapUtils.prefix)(bsProps, 'inner')
382 }, _ValidComponentChildren.default.map(children, function (child, index) {
383 var active = index === activeIndex;
384 var previousActive = slide && index === previousActiveIndex;
385 return (0, _react.cloneElement)(child, {
386 active: active,
387 index: index,
388 animateOut: previousActive,
389 animateIn: active && previousActiveIndex != null && slide,
390 direction: direction,
391 onAnimateOutEnd: previousActive ? _this4.handleItemAnimateOutEnd : null
392 });
393 })), controls && this.renderControls({
394 wrap: wrap,
395 children: children,
396 activeIndex: activeIndex,
397 prevIcon: prevIcon,
398 prevLabel: prevLabel,
399 nextIcon: nextIcon,
400 nextLabel: nextLabel,
401 bsProps: bsProps
402 }));
403 };
404
405 return Carousel;
406}(_react.default.Component);
407
408Carousel.propTypes = propTypes;
409Carousel.defaultProps = defaultProps;
410Carousel.Caption = _CarouselCaption.default;
411Carousel.Item = _CarouselItem.default;
412
413var _default = (0, _bootstrapUtils.bsClass)('carousel', Carousel);
414
415exports.default = _default;
416module.exports = exports["default"];
\No newline at end of file