Skip to content

Instantly share code, notes, and snippets.

@selvagsz
Created May 3, 2017 11:51
Show Gist options
  • Save selvagsz/d30e40afd1526a977c0e8403b4b1543a to your computer and use it in GitHub Desktop.
Save selvagsz/d30e40afd1526a977c0e8403b4b1543a to your computer and use it in GitHub Desktop.
react-carousel
<div id="react-root">
</div>
class Carousel extends React.Component {
state = {
translateX: 0,
};
childDimensions = {};
stashChildDimensions = ({ index, width, height }) => {
this.childDimensions[index] = {
width,
height,
};
};
setCarouselDimension(selectedIndex) {
let { width, height } = this.childDimensions[selectedIndex];
this.setState({
width,
height,
});
}
renderChildren() {
let selectedIndex = this.props.selectedIndex;
return React.Children.map(this.props.children, (child, index) => {
if (child.type === CarouselItem) {
return React.cloneElement(child, {
index,
isActive: selectedIndex === index,
onMount: this.stashChildDimensions,
});
}
return child;
});
}
componentDidMount() {
this.setCarouselDimension(this.props.selectedIndex);
}
componentWillReceiveProps({ selectedIndex }) {
this.setCarouselDimension(selectedIndex);
}
render() {
let { selectedIndex } = this.props;
let { width, height } = this.state
return (
<div
className="Carousel"
style={{
width: `${width}px`,
height: `${height}px`,
}}
>
<CarouselBody
selectedIndex={selectedIndex}
childDimensions={this.childDimensions}
>
{this.renderChildren()}
</CarouselBody>
</div>
);
}
}
class CarouselBody extends React.Component {
state = {
translateX: 0
};
componentDidMount() {
let { childDimensions } = this.props;
let carouselBodyDimensions = Object.keys(childDimensions).reduce(
(prev, curr) => {
prev.width = prev.width + childDimensions[curr].width;
prev.height = prev.height + childDimensions[curr].height;
return prev;
},
{ width: 0, height: 0 }
);
this.setState({
...carouselBodyDimensions
});
}
componentWillReceiveProps({ selectedIndex }) {
if (selectedIndex > this.props.selectedIndex) {
this.translateLeft(selectedIndex);
} else if (selectedIndex < this.props.selectedIndex) {
this.translateRight(selectedIndex);
}
}
translateLeft(selectedIndex) {
this.setState({
translateX: this.state.translateX -
this.props.childDimensions[selectedIndex - 1].width
});
}
translateRight(selectedIndex) {
this.setState({
translateX: this.state.translateX +
this.props.childDimensions[selectedIndex].width
});
}
render() {
let { children } = this.props;
let { width, translateX } = this.state;
return (
<div
className="Carousel__Body"
style={{
width: `${width}px`,
transform: `translate3d(${translateX}px, 0, 0)`
}}
>
{children}
</div>
);
}
}
class CarouselItem extends React.Component {
componentDidMount() {
let { index, onMount } = this.props;
onMount({
index,
width: this.carouselItem.offsetWidth,
height: this.carouselItem.offsetHeight
});
}
render() {
let { isActive, children, className } = this.props;
return (
<div
className={`Carousel__Item ${className} ${isActive ? 'Carousel__Item--active' : ''}`}
ref={element => (this.carouselItem = element)}
>
{children}
</div>
);
}
}
class App extends React.Component {
state = {
selectedIndex: 0
};
gotoPrev = () => {
this.setState({
selectedIndex: this.state.selectedIndex-1
})
};
gotoNext = () => {
this.setState({
selectedIndex: this.state.selectedIndex + 1
})
};
render() {
return (
<div>
<Carousel selectedIndex={this.state.selectedIndex}>
<CarouselItem className="bg-color-1">
<h1>Item 1</h1>
</CarouselItem>
<CarouselItem className="bg-color-2">
<h1>Item 2</h1>
</CarouselItem>
<CarouselItem className="bg-color-3">
<h1>Itezm 3</h1>
</CarouselItem>
<CarouselItem className="bg-color-4">
<h1>Itzzzzzzzzem 4</h1>
<h1>Itzzzzzzzzem 4</h1>
<h1>Itzzzzzzzzem 4</h1>
<h1>Itzzzzzzzem 4</h1>
</CarouselItem>
</Carousel>
<div>
<button onClick={this.gotoPrev}>Prev</button>
<button onClick={this.gotoNext}>Next</button>
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('react-root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.min.js"></script>
.Carousel {
overflow: hidden;
display: inline-block;
transition: width 0.3s, height 0.35s;
}
.Carousel__Body {
transition: transform 0.3s;
}
.Carousel__Body::before, .Carousel__Body::after {
content: '';
display: table;
clear: both;
}
.Carousel__Item {
float: left;
padding: 40px;
background-color: #00ffbb;
}
@mixin random-color($selector) {
#{$selector}: unquote("rgba(#{random(256) - 25}, #{random(256) - 1}, #{random(256) - 5}, #{random(100)/50})");
}
@for $i from 1 to 4 {
.bg-color-#{$i} {
@include random-color('background-color');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment