Skip to content
Permalink
Browse files

major refactor implementation

  • Loading branch information
yaodingyd committed Sep 27, 2018
1 parent 9b2b87f commit ce23364f0b9ba5eb6b5906fbb1332acec0990dfa
Showing with 87 additions and 63 deletions.
  1. +0 −2 index.d.ts
  2. +46 −9 src/__tests__/Carousel.js
  3. +41 −52 src/components/Carousel.js
@@ -48,8 +48,6 @@ export interface CarouselState {
cancelClick: boolean;
swiping: boolean;
autoPlay: boolean;
loop: boolean;
swipeLoop: boolean;
}

export class Carousel extends React.Component<CarouselProps, CarouselState> {
@@ -5,10 +5,6 @@ import renderer from 'react-test-renderer';
import * as index from '../index';
import Swipe from 'react-easy-swipe';

window.requestAnimationFrame = fn => {
setTimeout(fn, 0);
};

describe("Slider", function() {
jest.autoMockOff();

@@ -103,17 +99,13 @@ describe("Slider", function() {
describe("Initial State", () => {
const props = {
selectedItem: 0,
hasMount: false,
loop: false,
swipeLoop: false
hasMount: false
};

Object.keys(props).forEach(prop => {
it(`should have ${prop} as ${props[prop]}`, () => {
expect(componentInstance.state.selectedItem).toBe(0);
expect(componentInstance.state.hasMount).toBe(false);
expect(componentInstance.state.loop).toBe(false);
expect(componentInstance.state.swipeLoop).toBe(false);
});
});
});
@@ -501,6 +493,51 @@ describe("Slider", function() {

expect(componentInstance.state.selectedItem).toBe(lastItemIndex);
});

it('should render the clone slides', () => {
expect(component.find('.slide').at(0).key()).toContain('itemKey6clone');
expect(component.find('.slide').at(8).key()).toContain('itemKey0clone');
});

it('should set slide position directly and trigger a reflow when doing first to last transition', () => {
componentInstance.setPosition = jest.genMockFunction();
componentInstance.decrement();
expect(componentInstance.setPosition).toBeCalledWith('-800%', true);
componentInstance.setPosition.mockClear();
});

it('should set slide position directly and trigger a reflow when doing last to first transition', () => {
renderDefaultComponent({
infiniteLoop: true,
selectedItem: 7
})

componentInstance.setPosition = jest.genMockFunction();
componentInstance.increment();
expect(componentInstance.setPosition).toHaveBeenCalled();
});

it('should not call setPosition if swiping with inifinite scrolling', () => {
componentInstance.setPosition = jest.genMockFunction();
componentInstance.decrement(1, true);
expect(componentInstance.setPosition).not.toHaveBeenCalled();
});

it('should work with minimal children', () => {
renderDefaultComponent({
children: [<img src="assets/1.jpeg" key="1" />, <img src="assets/2.jpeg" key="2" />],
infiniteLoop: true
});
componentInstance.decrement();
expect(componentInstance.state.selectedItem).toBe(lastItemIndex);

renderDefaultComponent({
children: [<img src="assets/1.jpeg" key="1" />],
infiniteLoop: true
});
componentInstance.decrement();
expect(componentInstance.state.selectedItem).toBe(lastItemIndex);
});
});

describe('Auto Play', () => {
@@ -79,9 +79,7 @@ class Carousel extends Component {
selectedItem: props.selectedItem,
hasMount: false,
isMouseEntered: false,
autoPlay: props.autoPlay,
loop: false,
swipeLoop: false
autoPlay: props.autoPlay
};
}

@@ -343,29 +341,13 @@ class Carousel extends Component {
this.setState({
swiping: true,
});
if (this.props.infiniteLoop) {
this.setState({
swipeLoop: true,
});
}
this.clearAutoPlay();
}

onSwipeEnd = () => {
this.setState({
swiping: false
}, () => {
if (this.props.infiniteLoop) {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
this.setState({
swipeLoop: false
});
});
});
}
});

this.autoPlay();
}

@@ -376,7 +358,7 @@ class Carousel extends Component {
const initialBoundry = 0;

const currentPosition = this.getPosition(this.state.selectedItem);
const finalBoundry = this.getPosition(childrenLength - 1, true);
const finalBoundry = this.props.infiniteLoop ? this.getPosition(childrenLength - 1) - 100 : this.getPosition(childrenLength - 1);

const axisDelta = isHorizontal ? delta.x : delta.y;
let handledDelta = axisDelta;
@@ -393,6 +375,8 @@ class Carousel extends Component {

let position = currentPosition + (100 / (this.state.itemSize / handledDelta));
if (this.props.infiniteLoop) {
// When allowing infinite loop, if we slide left from position 0 we reveal the cloned last slide that appears before it
// if we slide even further we need to jump to other side so it can continue - and vice versa for the last slide
if (this.state.selectedItem === 0 && position > -100) {
position -= childrenLength * 100;
} else if (this.state.selectedItem === childrenLength - 1 && position < - childrenLength * 100) {
@@ -414,13 +398,17 @@ class Carousel extends Component {
return hasMoved;
}

getPosition(index, swiping) {
getPosition(index) {
if (this.props.infiniteLoop) {
// index has to be added by 1 because of the first cloned slide
++index;
}
const childrenLength = Children.count(this.props.children);
if (this.props.centerMode && this.props.axis === 'horizontal') {
let currentPosition = - index * this.props.centerSlidePercentage;
const lastPosition = childrenLength - 1;

if (index && index !== lastPosition) {
if (index && (index !== lastPosition || this.props.infiniteLoop)) {
currentPosition += (100 - this.props.centerSlidePercentage) / 2;
} else if (index === lastPosition) {
currentPosition += (100 - this.props.centerSlidePercentage);
@@ -429,20 +417,10 @@ class Carousel extends Component {
return currentPosition;
}

if (this.props.infiniteLoop) {
if (this.state.loop && index === 0) {
return 0;
}
if ((this.state.loop || swiping) && index === childrenLength - 1) {
return - (childrenLength + 1) * 100;
}
return - (index + 1) * 100;
}

return - index * 100;
}

setPosition = (position) => {
setPosition = (position, forceReflow) => {
const list = ReactDOM.findDOMNode(this.listRef);
[
'WebkitTransform',
@@ -454,24 +432,28 @@ class Carousel extends Component {
].forEach((prop) => {
list.style[prop] = CSSTranslate(position, this.props.axis);
});
if (forceReflow) {
list.offsetLeft;
}
}

resetPosition = () => {
const currentPosition = this.getPosition(this.state.selectedItem) + '%';
this.setPosition(currentPosition);
}

decrement = (positions) => {
this.moveTo(this.state.selectedItem - (typeof positions === 'Number' ? positions : 1));
decrement = (positions, fromSwipe) => {
this.moveTo(this.state.selectedItem - (typeof positions === 'Number' ? positions : 1), fromSwipe);
}

increment = (positions) => {
this.moveTo(this.state.selectedItem + (typeof positions === 'Number' ? positions : 1));
increment = (positions, fromSwipe) => {
this.moveTo(this.state.selectedItem + (typeof positions === 'Number' ? positions : 1), fromSwipe);
}

moveTo = (position) => {
moveTo = (position, fromSwipe) => {
const lastPosition = Children.count(this.props.children) - 1;
const needClonedSlide = this.props.infiniteLoop && !this.state.swipeLoop && (position < 0 || position > lastPosition);
const needClonedSlide = this.props.infiniteLoop && !fromSwipe && (position < 0 || position > lastPosition);
const oldPosition = position;

if (position < 0 ) {
position = this.props.infiniteLoop ? lastPosition : 0;
@@ -482,19 +464,26 @@ class Carousel extends Component {
}

if (needClonedSlide) {
this.selectItem({
selectedItem: position,
loop: true
// set swiping true would disable transition time, then we set slider to cloned position and force a reflow
// this is only needed for non-swiping situation
this.setState({
swiping: true
}, () => {
requestAnimationFrame(() => {
requestAnimationFrame(() => {
this.selectItem({
loop: false
});
});
if (oldPosition < 0) {
if (this.props.centerMode && this.props.axis === 'horizontal') {
this.setPosition(`-${(lastPosition + 2) * this.props.centerSlidePercentage - (100 - this.props.centerSlidePercentage) / 2}%`, true);
} else {
this.setPosition(`-${(lastPosition + 2) * 100}%`, true);
}
} else if (oldPosition > lastPosition) {
this.setPosition(0, true);
}

this.selectItem({
selectedItem: position,
swiping: false
});
});

} else {
this.selectItem({
// if it's not a slider, we don't need to set position here
@@ -630,7 +619,7 @@ class Carousel extends Component {
// if 3d is available, let's take advantage of the performance of transform
const transformProp = CSSTranslate(currentPosition + '%', this.props.axis);

const transitionTime = this.state.loop ? '0ms' : this.props.transitionTime + 'ms';
const transitionTime = this.props.transitionTime + 'ms';

itemListStyles = {
'WebkitTransform': transformProp,
@@ -670,8 +659,8 @@ class Carousel extends Component {
const containerStyles = {};

if (isHorizontal) {
swiperProps.onSwipeLeft = this.increment;
swiperProps.onSwipeRight = this.decrement;
swiperProps.onSwipeLeft = this.increment.bind(this, 1, true);
swiperProps.onSwipeRight = this.decrement.bind(this, 1, true);

if (this.props.dynamicHeight) {
const itemHeight = this.getVariableImageHeight(this.state.selectedItem);

0 comments on commit ce23364

Please sign in to comment.
You can’t perform that action at this time.