rb-carrousel
Version:
react-basics carrousel component
145 lines (123 loc) • 4.12 kB
JSX
// @flow
import React, { Component } from 'react';
import Hammer from 'hammerjs';
import './carrousel.css';
type PropsType = {
data: Array<{
alt: string,
src: string,
onClick: ?() => any,
}>,
position: number,
onClick: ?(position: number) => any,
};
class Thumbnails extends Component<PropsType> {
componentDidMount() {
if (this.thumbnailsContainer) this.hammerHandler = new Hammer(this.thumbnailsContainer);
if (this.hammerHandler) {
this.hammerHandler.on('panleft panright panend', (event) => {
if (event.type === 'panend') {
this.startLeft = Number(this.thumbnails[0].style.left.replace('px', ''));
this.startPosition = undefined;
this.thumbnails.forEach((element) => {
const thumbnail = element;
thumbnail.style.transition = 'all 0.3s cubic-bezier(.25, .8, .25, 1)';
thumbnail.style.pointerEvents = 'auto';
});
} else if (this.startPosition === undefined) {
this.startPosition = event.center.x;
this.thumbnails.forEach((element) => {
const thumbnail = element;
thumbnail.style.transition = 'initial';
thumbnail.style.pointerEvents = 'none';
});
} else {
this.thumbnails.forEach((element) => {
const thumbnail = element;
thumbnail.style.left = `${this.startLeft + (event.center.x - (this.startPosition || 0))}px`;
});
}
});
}
}
componentDidUpdate() {
this.fixLeft();
}
totalWidth(position: number): number {
let total:number = 0;
if (position !== undefined) {
this.thumbnails.forEach((element, index) => {
if (index <= position) total += element.offsetWidth;
});
} else {
this.thumbnails.forEach((element) => {
total += element.offsetWidth;
});
}
return total;
}
fixLeft(): void {
if (this.thumbnailsContainer) {
const { data, position } = this.props;
const width: number = this.thumbnailsContainer.offsetWidth;
const pos: number = (position || 0) >= 0 ?
(position || 0) % data.length :
(data.length - 1) - ((Math.abs(position || 0) - 1) % data.length);
this.thumbnails.forEach((element) => {
const thumbnail = element;
thumbnail.style.left = `${(((width / 2) - this.totalWidth(pos)) - (pos * 16)) + (this.thumbnails[pos].offsetWidth / 6)}px`;
});
this.startLeft = Number(this.thumbnails[0].style.left.replace('px', '')) || 0;
}
}
startLeft: ?number;
startPosition: ?number;
hammerHandler: ?Hammer;
thumbnailsContainer: ?HTMLDivElement;
thumbnails: Array<HTMLDivElement> = [];
render() {
const {
data,
position,
onClick,
} = this.props;
return (
<div
className="rbcarrousel__thumbnails"
ref={(ref) => { this.thumbnailsContainer = ref; }}
>
{data.map((element, index) => {
const pos = (position || 0) >= 0 ?
(position || 0) % data.length :
(data.length - 1) - ((Math.abs(position || 0) - 1) % data.length);
return (
<div
className={`rbcarrousel__thumbnail${pos === index ? ' rbcarrousel__thumbnail--current' : ''}`}
key={element.alt}
onClick={() => {
if (onClick) onClick(index);
}}
onKeyDown={(event) => {
const { keyCode } = event;
if (keyCode === 8) {
if (onClick) onClick(index);
}
}}
ref={(ref) => { this.thumbnails[index] = ref || document.createElement('div'); }}
role="button"
tabIndex={index}
>
<img
src={element.src}
alt={element.alt}
onLoad={() => this.fixLeft.bind(this)()}
onError={() => this.fixLeft.bind(this)()}
/>
</div>
);
})}
</div>
);
}
}
export default Thumbnails;