react-awesome-slider
Version:
React Awesome Slider is a 60fps performant, extendable, highly customisable, production ready React Component that renders a media (image/video) gallery slider carousel.
256 lines (238 loc) • 7.19 kB
JavaScript
import React, { Component } from 'react';
import { onceNextCssLayout, onceTransitionEnd } from 'web-animation-club';
import PropTypes from 'prop-types';
import { getClassName } from '../../helpers/components';
import { mergeStyles, getAnyClassName } from '../../core/helpers';
const ROOTELM = 'awssld';
export default function AutoplayHoc(WrappedComponent) {
return class extends Component {
static propTypes = {
interval: PropTypes.number,
cssModule: PropTypes.any,
play: PropTypes.bool,
cancelOnInteraction: PropTypes.bool,
timerHeight: PropTypes.string,
timerBackgroundColor: PropTypes.string,
showTimer: PropTypes.bool,
onTransitionStart: PropTypes.func,
onTransitionEnd: PropTypes.func,
onTransitionRequest: PropTypes.func,
rootElement: PropTypes.string,
};
static defaultProps = {
interval: 2000,
play: false,
cancelOnInteraction: false,
timerHeight: '6px',
cssModule: null,
timerBackgroundColor: 'rgba(0, 0, 0, 0.15)',
showTimer: true,
onTransitionStart: null,
onTransitionEnd: null,
onTransitionRequest: null,
rootElement: ROOTELM,
};
constructor(props) {
super(props);
this.forceStop = false;
this.rootElement = props.rootElement || ROOTELM;
this.mergedStyles = mergeStyles(props.cssModule);
this.state = {
selected: 0,
};
}
componentWillReceiveProps(newProps) {
this.mergedStyles = mergeStyles(newProps.cssModule);
this.checkStartStatus(newProps);
}
setInfo(info) {
this.currentInfo = info;
if (info.currentIndex !== this.state.selected) {
this.setState({ selected: info.currentIndex });
}
}
setTimer(element) {
if (this.forceStop === true) {
return;
}
let bar = element.querySelector(
`.${getAnyClassName(
getClassName(`${this.rootElement}__timer`, this.mergedStyles)
)}`
);
const wrapper = element.querySelector('div');
if (!wrapper) {
return;
}
if (!bar) {
bar = this.createBarElement();
wrapper.appendChild(bar);
}
bar.classList.remove(
getClassName(`${this.rootElement}__timer--animated`, this.mergedStyles)
);
onceNextCssLayout().then(() => {
bar.classList.remove(
getClassName(`${this.rootElement}__timer--run`, this.mergedStyles)
);
bar.classList.remove(
getClassName(`${this.rootElement}__timer--fast`, this.mergedStyles)
);
onceNextCssLayout().then(() => {
bar.classList.add(
getClassName(
`${this.rootElement}__timer--animated`,
this.mergedStyles
)
);
onceNextCssLayout().then(() => {
bar.classList.add(
getClassName(`${this.rootElement}__timer--run`, this.mergedStyles)
);
onceTransitionEnd(bar).then(() => {
this.clearBarAnimation(bar);
if (this.forceStop === true || this.props.play === false) {
return;
}
this.goTonext();
});
});
});
});
}
getBarFromSlide(slider) {
const bar = slider.querySelector(
`.${getAnyClassName(
getClassName(`${this.rootElement}__timer`, this.mergedStyles)
)}`
);
return bar || null;
}
checkStartStatus(newProps) {
if (!this.currentInfo) {
return;
}
if (this.props.play !== newProps.play) {
if (newProps.play === true && this.currentInfo) {
this.setTimer(this.currentInfo.currentSlide);
}
if (newProps.play === false) {
this.forceClearBar(this.currentInfo);
}
}
}
createBarElement() {
const bar = document.createElement('div');
bar.classList.add(
getClassName(`${this.rootElement}__timer`, this.mergedStyles)
);
bar.style.setProperty('--timer-delay', `${this.props.interval}ms`);
bar.style.setProperty('--timer-height', this.props.timerHeight);
bar.style.setProperty(
'--timer-background-color',
this.props.timerBackgroundColor
);
return bar;
}
clearBar(info) {
const bar = this.getBarFromSlide(info.currentSlide);
if (bar) {
if (bar.clearCssEndEvent) {
bar.clearCssEndEvent();
}
bar.classList.add(
getClassName(`${this.rootElement}__timer--fast`, this.mergedStyles)
);
onceTransitionEnd(bar).then(() => {
this.clearBarAnimation(bar);
});
}
}
clearBarAnimation(bar) {
bar.classList.remove(
getClassName(`${this.rootElement}__timer--animated`, this.mergedStyles)
);
}
restartBarAnimation(bar) {
bar.classList.remove(
getClassName(`${this.rootElement}__timer--run`, this.mergedStyles)
);
bar.classList.remove(
getClassName(`${this.rootElement}__timer--fast`, this.mergedStyles)
);
}
forceClearBar(info) {
const bar = this.getBarFromSlide(info.currentSlide);
this.restartBarAnimation(bar);
}
goTonext() {
const { currentIndex, slides } = this.currentInfo;
const next = currentIndex + 1;
const selected = next > slides - 1 ? 0 : next;
if (selected === this.state.selected) {
this.forceClearBar(this.currentInfo);
return;
}
this.setState({ selected });
}
render() {
const {
inverval,
play,
cancelOnInteraction,
showTimer,
onTransitionStart,
onTransitionEnd,
onFirstMount,
onTransitionRequest,
...extra
} = this.props;
return (
<WrappedComponent
{...extra}
selected={this.state.selected}
onFirstMount={info => {
if (onFirstMount) {
onFirstMount(info);
}
if (extra.startupScreen) {
return;
}
this.setInfo(info);
if (play === true) {
this.setTimer(info.currentSlide);
}
}}
onTransitionStart={info => {
const bar = this.getBarFromSlide(info.nextSlide);
if (bar) {
this.restartBarAnimation(bar);
}
if (onTransitionStart) {
onTransitionStart(info);
}
}}
onTransitionRequest={info => {
this.clearBar(info);
this.currentInfo = info;
if (cancelOnInteraction === true) {
this.forceStop = true;
}
if (onTransitionRequest) {
onTransitionRequest(info);
}
}}
onTransitionEnd={info => {
this.setInfo(info);
if (play === true) {
this.setTimer(info.currentSlide);
}
if (onTransitionEnd) {
onTransitionEnd(info);
}
}}
/>
);
}
};
}