UNPKG

react-bootstrap

Version:

Bootstrap 3 components build with React

291 lines (244 loc) 7.54 kB
define(function (require, exports, module) {var React = require('react'); var joinClasses = require('./utils/joinClasses'); var classSet = require('./utils/classSet'); var cloneWithProps = require('./utils/cloneWithProps'); var BootstrapMixin = require('./BootstrapMixin'); var ValidComponentChildren = require('./utils/ValidComponentChildren'); var Carousel = React.createClass({displayName: "Carousel", mixins: [BootstrapMixin], propTypes: { slide: React.PropTypes.bool, indicators: React.PropTypes.bool, controls: React.PropTypes.bool, pauseOnHover: React.PropTypes.bool, wrap: React.PropTypes.bool, onSelect: React.PropTypes.func, onSlideEnd: React.PropTypes.func, activeIndex: React.PropTypes.number, defaultActiveIndex: React.PropTypes.number, direction: React.PropTypes.oneOf(['prev', 'next']) }, getDefaultProps: function () { return { slide: true, interval: 5000, pauseOnHover: true, wrap: true, indicators: true, controls: true }; }, getInitialState: function () { return { activeIndex: this.props.defaultActiveIndex == null ? 0 : this.props.defaultActiveIndex, previousActiveIndex: null, direction: null }; }, getDirection: function (prevIndex, index) { if (prevIndex === index) { return null; } return prevIndex > index ? 'prev' : 'next'; }, componentWillReceiveProps: function (nextProps) { var activeIndex = this.getActiveIndex(); if (nextProps.activeIndex != null && nextProps.activeIndex !== activeIndex) { clearTimeout(this.timeout); this.setState({ previousActiveIndex: activeIndex, direction: nextProps.direction != null ? nextProps.direction : this.getDirection(activeIndex, nextProps.activeIndex) }); } }, componentDidMount: function () { this.waitForNext(); }, componentWillUnmount: function() { clearTimeout(this.timeout); }, next: function (e) { if (e) { e.preventDefault(); } var index = this.getActiveIndex() + 1; var count = ValidComponentChildren.numberOf(this.props.children); if (index > count - 1) { if (!this.props.wrap) { return; } index = 0; } this.handleSelect(index, 'next'); }, prev: function (e) { if (e) { e.preventDefault(); } var index = this.getActiveIndex() - 1; if (index < 0) { if (!this.props.wrap) { return; } index = ValidComponentChildren.numberOf(this.props.children) - 1; } this.handleSelect(index, 'prev'); }, pause: function () { this.isPaused = true; clearTimeout(this.timeout); }, play: function () { this.isPaused = false; this.waitForNext(); }, waitForNext: function () { if (!this.isPaused && this.props.slide && this.props.interval && this.props.activeIndex == null) { this.timeout = setTimeout(this.next, this.props.interval); } }, handleMouseOver: function () { if (this.props.pauseOnHover) { this.pause(); } }, handleMouseOut: function () { if (this.isPaused) { this.play(); } }, render: function () { var classes = { carousel: true, slide: this.props.slide }; return ( React.createElement("div", React.__spread({}, this.props, {className: joinClasses(this.props.className, classSet(classes)), onMouseOver: this.handleMouseOver, onMouseOut: this.handleMouseOut}), this.props.indicators ? this.renderIndicators() : null, React.createElement("div", {className: "carousel-inner", ref: "inner"}, ValidComponentChildren.map(this.props.children, this.renderItem) ), this.props.controls ? this.renderControls() : null ) ); }, renderPrev: function () { return ( React.createElement("a", {className: "left carousel-control", href: "#prev", key: 0, onClick: this.prev}, React.createElement("span", {className: "glyphicon glyphicon-chevron-left"}) ) ); }, renderNext: function () { return ( React.createElement("a", {className: "right carousel-control", href: "#next", key: 1, onClick: this.next}, React.createElement("span", {className: "glyphicon glyphicon-chevron-right"}) ) ); }, renderControls: function () { if (this.props.wrap) { var activeIndex = this.getActiveIndex(); var count = ValidComponentChildren.numberOf(this.props.children); return [ (activeIndex !== 0) ? this.renderPrev() : null, (activeIndex !== count - 1) ? this.renderNext() : null ]; } return [ this.renderPrev(), this.renderNext() ]; }, renderIndicator: function (child, index) { var className = (index === this.getActiveIndex()) ? 'active' : null; return ( React.createElement("li", { key: index, className: className, onClick: this.handleSelect.bind(this, index, null)}) ); }, renderIndicators: function () { var indicators = []; ValidComponentChildren .forEach(this.props.children, function(child, index) { indicators.push( this.renderIndicator(child, index), // Force whitespace between indicator elements, bootstrap // requires this for correct spacing of elements. ' ' ); }, this); return ( React.createElement("ol", {className: "carousel-indicators"}, indicators ) ); }, getActiveIndex: function () { return this.props.activeIndex != null ? this.props.activeIndex : this.state.activeIndex; }, handleItemAnimateOutEnd: function () { this.setState({ previousActiveIndex: null, direction: null }, function() { this.waitForNext(); if (this.props.onSlideEnd) { this.props.onSlideEnd(); } }); }, renderItem: function (child, index) { var activeIndex = this.getActiveIndex(); var isActive = (index === activeIndex); var isPreviousActive = this.state.previousActiveIndex != null && this.state.previousActiveIndex === index && this.props.slide; return cloneWithProps( child, { active: isActive, ref: child.ref, key: child.key ? child.key : index, index: index, animateOut: isPreviousActive, animateIn: isActive && this.state.previousActiveIndex != null && this.props.slide, direction: this.state.direction, onAnimateOutEnd: isPreviousActive ? this.handleItemAnimateOutEnd: null } ); }, handleSelect: function (index, direction) { clearTimeout(this.timeout); var previousActiveIndex = this.getActiveIndex(); direction = direction || this.getDirection(previousActiveIndex, index); if (this.props.onSelect) { this.props.onSelect(index, direction); } if (this.props.activeIndex == null && index !== previousActiveIndex) { if (this.state.previousActiveIndex != null) { // If currently animating don't activate the new index. // TODO: look into queuing this canceled call and // animating after the current animation has ended. return; } this.setState({ activeIndex: index, previousActiveIndex: previousActiveIndex, direction: direction }); } } }); module.exports = Carousel; });