Skip to content

Instantly share code, notes, and snippets.

@dg92
Created May 22, 2017 05:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dg92/a8aefebdc5173d3c03e0544f5831eab7 to your computer and use it in GitHub Desktop.
Save dg92/a8aefebdc5173d3c03e0544f5831eab7 to your computer and use it in GitHub Desktop.
import React from 'react'
import {
bool,
number,
object,
string,
} from 'prop-types'
export const ANIMATION_TIME = 200 * 4;
const initialState = {
endingAnimationTimeout: null,
percent: 0,
progressInterval: null,
}
export class ProgressBar extends React.Component {
constructor(props) {
super(props)
this.state = {
...initialState,
hasMounted: false,
}
this.boundSimulateProgress = this.simulateProgress.bind(this)
this.boundResetProgress = this.resetProgress.bind(this)
}
componentWillReceiveProps(nextProps) {
if (this.props.loading === 0 && nextProps.loading > 0) {
this.start()
} else if (this.state.progressInterval && nextProps.loading === 0) {
if (this.state.percent === 0 && !this.props.showFastActions) {
clearInterval(this.state.progressInterval)
this.resetProgress()
} else {
this.setState({ percent: 100 })
}
}
}
componentDidMount() {
this.setState({hasMounted: true});
if (this.props.loading > 0) {
this.start()
}
}
componentWillUnmount() {
clearInterval(this.state.progressInterval)
clearTimeout(this.state.endingAnimationTimeout)
}
start() {
let { progressInterval, percent } = this.state
const { endingAnimationTimeout } = this.state
const loadingBarNotShown = !progressInterval
const endingAnimationGoing = percent === 100
if (loadingBarNotShown) {
progressInterval = setInterval(
this.boundSimulateProgress,
this.props.updateTime,
)
}
if (endingAnimationGoing) {
clearTimeout(endingAnimationTimeout)
}
percent = 0
this.setState({ progressInterval, percent })
}
newPercent() {
const { percent } = this.state
const { progressIncrease } = this.props
return percent + smoothedProgressIncrease;
}
simulateProgress() {
let { progressInterval, percent, endingAnimationTimeout } = this.state
const { maxProgress } = this.props
if (percent === 100) {
clearInterval(progressInterval)
endingAnimationTimeout = setTimeout(
this.boundResetProgress,
ANIMATION_TIME,
)
progressInterval = null
} else if (this.newPercent() <= maxProgress) {
percent = this.newPercent()
}
this.setState({ percent, progressInterval, endingAnimationTimeout })
}
resetProgress() {
this.setState(initialState)
}
buildStyle() {
const style = {
opacity: '1',
transform: `scaleX(${this.state.percent / 100})`,
transformOrigin: 'left',
transition: `transform ${ANIMATION_TIME}ms linear`,
width: '100%',
willChange: 'transform, opacity',
}
if (!this.props.className) {
style.height = '3px'
style.backgroundColor = 'red'
style.position = 'absolute'
}
if (this.shouldShow()) {
style.opacity = '1'
} else {
style.opacity = '0'
}
return { ...style, ...this.props.style }
}
render() {
if (!this.state.hasMounted) {
return <div />
}
return (
<div>
<div style={this.buildStyle()} className={this.props.className} />
<div style={{clear: 'both'}} />
</div>
)
}
}
ProgressBar.propTypes = {
className: string,
loading: number,
maxProgress: number,
progressIncrease: number,
showFastActions: bool,
style: object,
updateTime: number,
}
ProgressBar.defaultProps = {
className: undefined,
loading: 0,
maxProgress: 99,
progressIncrease: 10,
showFastActions: false,
style: {},
updateTime: 200,
}
export default ProgressBar;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment