react-cm-ui
Version:
React UI for Healthy Church
310 lines (276 loc) • 8.24 kB
JSX
import {
Back,
Power1,
TimelineMax,
} from 'gsap';
import ClassNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react';
import {
UI_CLASS_NAME,
} from '../../global/constants';
import withTheme from '../../styles/withTheme';
const propTypes = {
className: PropTypes.string,
color: PropTypes.oneOf(['backgroundColorHighlight', 'backgroundColorStatic']),
dataTestId: PropTypes.string,
id: PropTypes.string,
size: PropTypes.number,
style: PropTypes.shape({}),
title: PropTypes.string,
theme: PropTypes.shape({
palette: PropTypes.shape({
cyan: PropTypes.shape({}),
grey: PropTypes.shape({}),
}),
}),
};
const BLOCK_CLASS = 'activity_indicator';
const defaultProps = {
className: undefined,
color: 'backgroundColorHighlight',
dataTestId: `${UI_CLASS_NAME}-${BLOCK_CLASS}`,
id: undefined,
size: 68,
style: {},
theme: undefined,
title: 'Loading',
};
const BAR_CLASS = `${BLOCK_CLASS}--bar`;
const BAR_HEIGHT = 68;
const CIRCLE_CLASS = `${BLOCK_CLASS}--circle`;
const DURATION_DOWN = 0.55;
const DURATION_UP = 0.3;
const CIRCLE_SIZE = 16;
const CIRCLE_UP_Y_POS = -(BAR_HEIGHT - CIRCLE_SIZE);
class ActivityIndicator extends React.PureComponent {
constructor() {
super();
this.barTweenLeft = new TimelineMax();
this.barTweenMiddle = new TimelineMax();
this.barTweenRight = new TimelineMax();
this.circleTweenLeft = new TimelineMax();
this.circleTweenMiddle = new TimelineMax();
this.circleTweenRight = new TimelineMax();
}
componentDidMount() {
// const principleDefaultEase = CustomEase.create('custom', 'M0,0 C0.302,0.116 0.302,1 1,1')
const barToUpOptions = {
ease: Power1.easeOut, // eslint-disable-line no-undef
height: BAR_HEIGHT,
opacity: 1,
};
const barToDownOptions = {
ease: Back.easeOut.config(1.5), // eslint-disable-line no-undef
height: CIRCLE_SIZE,
opacity: 0,
};
const circleToUpOptions = {
ease: Power1.easeOut, // eslint-disable-line no-undef
y: CIRCLE_UP_Y_POS,
};
const circleToDownOptions = {
ease: Back.easeOut.config(1.5), // eslint-disable-line no-undef
y: 0,
};
this.barTweenLeft.delay(0).set(
`.${BAR_CLASS}-left`,
{
height: CIRCLE_SIZE,
opacity: 0,
},
).to(
`.${BAR_CLASS}-left`,
DURATION_UP,
barToUpOptions,
).to(
`.${BAR_CLASS}-left`,
DURATION_DOWN,
barToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
this.barTweenMiddle.delay(0.45).set(
`.${BAR_CLASS}-middle`,
{
height: CIRCLE_SIZE,
opacity: 0,
},
).to(
`.${BAR_CLASS}-middle`,
DURATION_UP,
barToUpOptions,
).to(
`.${BAR_CLASS}-middle`,
DURATION_DOWN,
barToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
this.barTweenRight.delay(0.9).set(
`.${BAR_CLASS}-right`,
{
height: CIRCLE_SIZE,
opacity: 0,
},
).to(
`.${BAR_CLASS}-right`,
DURATION_UP,
barToUpOptions,
).to(
`.${BAR_CLASS}-right`,
DURATION_DOWN,
barToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
this.circleTweenLeft.delay(0).set(
`.${BAR_CLASS}-left`,
{
y: 0,
},
).to(
`.${CIRCLE_CLASS}-left`,
DURATION_UP,
circleToUpOptions,
).to(
`.${CIRCLE_CLASS}-left`,
DURATION_DOWN,
circleToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
this.circleTweenMiddle.delay(0.45).set(
`.${BAR_CLASS}-middle`,
{
y: 0,
},
).to(
`.${CIRCLE_CLASS}-middle`,
DURATION_UP,
circleToUpOptions,
).to(
`.${CIRCLE_CLASS}-middle`,
DURATION_DOWN,
circleToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
this.circleTweenRight.delay(0.9).set(
`.${BAR_CLASS}-right`,
{
y: 0,
},
).to(
`.${CIRCLE_CLASS}-right`,
DURATION_UP,
circleToUpOptions,
).to(
`.${CIRCLE_CLASS}-right`,
DURATION_DOWN,
circleToDownOptions,
)
.repeat(-1)
.repeatDelay(0.5);
}
render() {
const {
className,
color,
dataTestId,
id,
size,
style,
theme,
title,
} = this.props;
const {
palette: {
cyan,
grey,
},
} = theme;
const rootClasses = ClassNames(
'ui',
BLOCK_CLASS,
className,
);
const transformScaleDecimal = (1 / 68) * size;
let backgroundColorStyle;
switch (color) {
case 'backgroundColorStatic':
backgroundColorStyle = grey[400];
break;
case 'backgroundColorHighlight':
backgroundColorStyle = cyan[500];
break;
default:
break;
}
return (
<div
className={rootClasses}
data-testid={dataTestId}
id={id}
style={{
...style,
transform: `scale(${transformScaleDecimal})`,
transformOrigin: 0,
}}
title={title}
>
<div
className={`${BLOCK_CLASS}--left`}
>
<div
className={`${CIRCLE_CLASS} ${CIRCLE_CLASS}-left`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
<div
className={`${BAR_CLASS} ${BAR_CLASS}-left`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
</div>
<div
className={`${BLOCK_CLASS}--middle`}
>
<div
className={`${CIRCLE_CLASS} ${CIRCLE_CLASS}-middle`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
<div
className={`${BAR_CLASS} ${BAR_CLASS}-middle`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
</div>
<div
className={`${BLOCK_CLASS}--right`}
>
<div
className={`${CIRCLE_CLASS} ${CIRCLE_CLASS}-right`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
<div
className={`${BAR_CLASS} ${BAR_CLASS}-right`}
style={{
backgroundColor: backgroundColorStyle,
}}
/>
</div>
</div>
);
}
}
ActivityIndicator.propTypes = propTypes;
ActivityIndicator.defaultProps = defaultProps;
export default withTheme(ActivityIndicator);