accounts-frontend/packages/app/components/ui/motion/SlideMotion.tsx

100 lines
2.4 KiB
TypeScript
Raw Normal View History

2019-12-07 16:58:52 +05:30
import React from 'react';
2017-07-22 21:27:38 +05:30
import { Motion, spring } from 'react-motion';
import MeasureHeight from 'app/components/MeasureHeight';
2017-07-22 21:27:38 +05:30
2017-11-19 23:46:15 +05:30
import styles from './slide-motion.scss';
2017-07-22 21:27:38 +05:30
2019-12-07 16:58:52 +05:30
interface State {
[stepHeight: string]: number;
version: number;
}
class SlideMotion extends React.Component<
{
2019-12-07 16:58:52 +05:30
activeStep: number;
children: React.ReactNode;
},
2019-12-07 16:58:52 +05:30
State
> {
2019-12-07 16:58:52 +05:30
state: State = {
version: 0,
};
2017-07-22 21:27:38 +05:30
isHeightMeasured: boolean;
2017-07-22 21:27:38 +05:30
componentWillReceiveProps() {
// mark this view as dirty to re-measure height
this.setState({
version: this.state.version + 1,
});
}
2017-07-22 21:27:38 +05:30
render() {
const { activeStep, children } = this.props;
2017-07-22 21:27:38 +05:30
const { version } = this.state;
2017-07-22 21:27:38 +05:30
const activeStepHeight = this.state[`step${activeStep}Height`] || 0;
2017-07-22 21:27:38 +05:30
// a hack to disable height animation on first render
const { isHeightMeasured } = this;
this.isHeightMeasured = isHeightMeasured || activeStepHeight > 0;
2017-07-22 21:27:38 +05:30
const motionStyle = {
transform: spring(activeStep * 100, {
stiffness: 500,
damping: 50,
precision: 0.5,
}),
height: isHeightMeasured
? spring(activeStepHeight, {
stiffness: 500,
damping: 20,
precision: 0.5,
})
: activeStepHeight,
};
2017-07-22 21:27:38 +05:30
return (
<Motion style={motionStyle}>
2019-12-07 16:58:52 +05:30
{(interpolatingStyle: { height: number; transform: string }) => (
<div
style={{
overflow: 'hidden',
height: `${interpolatingStyle.height}px`,
}}
>
<div
className={styles.container}
style={{
WebkitTransform: `translateX(-${interpolatingStyle.transform}%)`,
transform: `translateX(-${interpolatingStyle.transform}%)`,
}}
>
{React.Children.map(children, (child, index) => (
<MeasureHeight
className={styles.item}
onMeasure={this.onStepMeasure(index)}
state={version}
key={index}
>
{child}
</MeasureHeight>
))}
</div>
</div>
)}
</Motion>
);
}
2017-07-22 21:27:38 +05:30
onStepMeasure(step: number) {
return (height: number) =>
this.setState({
[`step${step}Height`]: height,
});
}
2017-07-22 21:27:38 +05:30
}
2019-12-07 16:58:52 +05:30
export default SlideMotion;