-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #168 from NGMarmaduke/carousel
Update Carousel component to use nuka-carousel
- Loading branch information
Showing
10 changed files
with
339 additions
and
176 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,3 +14,4 @@ build | |
# misc | ||
.DS_Store | ||
npm-debug.log | ||
yarn-error.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,8 @@ | ||
.root { | ||
white-space: nowrap; | ||
-webkit-overflow-scrolling: touch; | ||
width: 100%; | ||
.wrapper { | ||
overflow: hidden; | ||
} | ||
|
||
.root * { | ||
box-sizing: border-box; | ||
} | ||
|
||
.animate { | ||
transition: transform 500ms; | ||
} | ||
|
||
.slide { | ||
display: inline-block; | ||
.peaking { | ||
padding-left: 8%; | ||
padding-right: 8%; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,80 @@ | ||
import React, { PropTypes, Component } from 'react'; | ||
import React, { PropTypes, Component, Children } from 'react'; | ||
import cx from 'classnames'; | ||
import noop from '../../utils/noop'; | ||
|
||
import Inner from './CarouselInner'; | ||
import NukaCarousel from '@appearhere/nuka-carousel'; | ||
|
||
import css from './Carousel.css'; | ||
|
||
export default class Carousel extends Component { | ||
static propTypes = { | ||
children: PropTypes.oneOfType([ | ||
PropTypes.element, | ||
PropTypes.array, | ||
]).isRequired, | ||
className: PropTypes.string, | ||
lowestVisibleItemIndex: PropTypes.number, | ||
items: PropTypes.array.isRequired, | ||
itemsPerColumn: PropTypes.number, | ||
onChange: PropTypes.func, | ||
peaking: PropTypes.bool, | ||
speed: PropTypes.number, | ||
|
||
}; | ||
|
||
static defaultProps = { | ||
lowestVisibleItemIndex: 0, | ||
items: [], | ||
itemsPerColumn: 1, | ||
peaking: false, | ||
speed: 300, | ||
onChange: noop, | ||
}; | ||
|
||
render() { | ||
const { items, itemsPerColumn, lowestVisibleItemIndex } = this.props; | ||
constructor(props) { | ||
super(props); | ||
this.state = { lowestVisibleItemIndex: props.lowestVisibleItemIndex }; | ||
} | ||
|
||
const renderItems = items.filter(item => item); | ||
componentWillReceiveProps(nextProps) { | ||
const { lowestVisibleItemIndex } = this.state; | ||
const nextIndex = nextProps.lowestVisibleItemIndex; | ||
|
||
const renderPerColumn = itemsPerColumn < renderItems.length | ||
? itemsPerColumn | ||
: renderItems.length; | ||
const slideWidth = 100 / renderPerColumn; | ||
if (nextIndex !== lowestVisibleItemIndex) { | ||
this.setState({ lowestVisibleItemIndex: nextIndex }, () => { | ||
const childLength = Children.count(nextProps.children); | ||
const willWrapToEnd = lowestVisibleItemIndex === 0 && nextIndex === childLength - 1; | ||
const willWrapToStart = lowestVisibleItemIndex === childLength - 1 && nextIndex === 0; | ||
|
||
const position = lowestVisibleItemIndex * (-1 * slideWidth); | ||
const transform = `translate3d(${position}%, 0, 0)`; | ||
if (willWrapToEnd) { | ||
this.carousel.previousSlide(); | ||
} else if (willWrapToStart) { | ||
this.carousel.nextSlide(); | ||
} else { | ||
this.carousel.goToSlide(nextIndex); | ||
} | ||
}); | ||
} | ||
} | ||
|
||
handleChange = (lowestVisibleItemIndex) => { | ||
const { onChange } = this.props; | ||
this.setState({ lowestVisibleItemIndex }, () => { onChange(lowestVisibleItemIndex); }); | ||
} | ||
|
||
render() { | ||
const { peaking, children, className, ...rest } = this.props; | ||
const frameOverflow = peaking ? 'visible' : 'hidden'; | ||
|
||
return ( | ||
<div> | ||
<Inner | ||
style={ { | ||
transform, | ||
} } | ||
slideWidth={ slideWidth } | ||
<div className={ cx(css.wrapper, className, peaking ? css.peaking : null) }> | ||
<NukaCarousel | ||
ref={ (c) => { this.carousel = c; } } | ||
decorators={ [] } | ||
frameOverflow={ frameOverflow } | ||
peaking={ peaking } | ||
afterSlide={ this.handleChange } | ||
{ ...rest } | ||
> | ||
{ renderItems } | ||
</Inner> | ||
{ children } | ||
</NukaCarousel> | ||
</div> | ||
); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,60 @@ | ||
import React, { PropTypes, Component } from 'react'; | ||
import { storiesOf } from '@kadira/storybook'; | ||
import Carousel from './Carousel'; | ||
import React, { PropTypes } from 'react'; | ||
import { storiesOf, action } from '@kadira/storybook'; | ||
|
||
import getValidIndex from '../../utils/getValidIndex/getValidIndex'; | ||
import PictureCard from '../Cards/PictureCard/PictureCard'; | ||
import Carousel from './Carousel'; | ||
import ControlledCarousel from './ControlledCarousel'; | ||
|
||
const Slide = ({ i }) => ( | ||
<div | ||
style={ { | ||
width: '100%', | ||
height: '300px', | ||
} } | ||
> | ||
<div | ||
const StorySlide = ({ number }) => ( | ||
<div key={ `slide-${number}` } style={ { paddingLeft: '2%', paddingRight: '2%' } }> | ||
<PictureCard | ||
src={ `http://placekitten.com/g/287/4${(number * 2) + 10}` } | ||
style={ { | ||
width: '100%', | ||
height: '300px', | ||
backgroundColor: 'red', | ||
verticalAlign: 'middle', | ||
textAlign: 'center', | ||
fontSize: '5rem', | ||
} } | ||
center | ||
href="#" | ||
> | ||
slide { i } | ||
</div> | ||
{ number } | ||
</PictureCard> | ||
</div> | ||
); | ||
|
||
Slide.propTypes = { | ||
i: PropTypes.number, | ||
}; | ||
|
||
const slides = [<Slide i={ 0 } />, <Slide i={ 1 } />, <Slide i={ 2 } />, <Slide i={ 3 } />, <Slide i={ 4 } />, <Slide i={ 5 } />, <Slide i={ 6 } />, <Slide i={ 7 } />]; | ||
|
||
class TestComponent extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
lowestVisibleItemIndex: 0, | ||
itemsPerColumn: 1, | ||
} | ||
} | ||
|
||
goToIndex = (i) => { | ||
const { itemsPerColumn } = this.state; | ||
|
||
if (i < 0 || i >= slides.length) return; | ||
const lowestVisibleItemIndex = getValidIndex(i, slides.length, itemsPerColumn); | ||
this.setState({ lowestVisibleItemIndex }); | ||
} | ||
|
||
render() { | ||
const { lowestVisibleItemIndex, itemsPerColumn } = this.state; | ||
|
||
return ( | ||
<div style={ { width: '80vW', overflowX: 'visible', margin: '0 auto' } }> | ||
<Carousel | ||
lowestVisibleItemIndex={ lowestVisibleItemIndex } | ||
items={ slides } | ||
itemsPerColumn={ itemsPerColumn } | ||
/> | ||
<button onClick={this.goToIndex.bind(this, 0)}>Go to 0</button> | ||
<button onClick={this.goToIndex.bind(this, 1)}>Go to 1</button> | ||
<button onClick={this.goToIndex.bind(this, 2)}>Go to 2</button> | ||
<button onClick={this.goToIndex.bind(this, 3)}>Go to 3</button> | ||
<button onClick={this.goToIndex.bind(this, 4)}>Go to 4</button> | ||
</div> | ||
); | ||
} | ||
} | ||
StorySlide.propTypes = { number: PropTypes.number }; | ||
const slides = [...Array(10).keys()].map(i => <StorySlide number={ i } key={ i } />); | ||
|
||
storiesOf('Carousel', module) | ||
.add('Default', () => ( | ||
<TestComponent /> | ||
)); | ||
<Carousel onChange={ action('Slide changed') }> | ||
{ slides } | ||
</Carousel> | ||
)); | ||
|
||
storiesOf('Controlled Carousel', module) | ||
.add('Default', () => ( | ||
<ControlledCarousel> | ||
{ slides } | ||
</ControlledCarousel> | ||
)) | ||
.add('Muliple in view 💯', () => ( | ||
<ControlledCarousel slidesToShow={ 3 }> | ||
{ slides } | ||
</ControlledCarousel> | ||
)) | ||
.add('Infinite ∞', () => ( | ||
<ControlledCarousel wrapAround> | ||
{ slides } | ||
</ControlledCarousel> | ||
)) | ||
.add('Peaking 🐦', () => ( | ||
<ControlledCarousel peaking> | ||
{ slides } | ||
</ControlledCarousel> | ||
)) | ||
.add('🐦 + ∞ + 💯', () => ( | ||
<ControlledCarousel peaking wrapAround slidesToShow={ 3 }> | ||
{ slides } | ||
</ControlledCarousel> | ||
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,9 @@ | ||
import React from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { createRenderer } from 'react-addons-test-utils'; | ||
|
||
import Carousel from './Carousel'; | ||
|
||
it('renders without crashing', () => { | ||
const div = document.createElement('div'); | ||
ReactDOM.render(<Carousel />, div); | ||
}); | ||
|
||
it('calculates the width of slides correctly ', () => { | ||
const items = [<div key="lmao" />, <div key="lol" />]; | ||
const shallowRenderer = createRenderer(); | ||
let result = null; | ||
|
||
shallowRenderer.render( | ||
<Carousel | ||
items={items} | ||
itemsPerColumn={1} | ||
/> | ||
); | ||
|
||
result = shallowRenderer.getRenderOutput(); | ||
expect(result.props.children.props.slideWidth).toBe(100); | ||
|
||
shallowRenderer.render( | ||
<Carousel | ||
items={items} | ||
itemsPerColumn={2} | ||
/> | ||
); | ||
|
||
result = shallowRenderer.getRenderOutput(); | ||
expect(result.props.children.props.slideWidth).toBe(50); | ||
|
||
shallowRenderer.render( | ||
<Carousel | ||
items={items} | ||
itemsPerColumn={3} | ||
/> | ||
); | ||
|
||
result = shallowRenderer.getRenderOutput(); | ||
expect(result.props.children.props.slideWidth).toBe(50); | ||
ReactDOM.render(<Carousel><span>child</span></Carousel>, div); | ||
}); |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.