diff options
| author | anderklander <anderklander@gmail.com> | 2018-02-21 14:46:07 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-02-26 16:15:52 +0100 |
| commit | 608029ca1c403101a88ec45d52e44dc1f22e434f (patch) | |
| tree | f2f7bb91c19f6d01d259e785242dbd967bc6392f /app/components | |
| parent | 47a78129cd2f953fe4dca33a04c138ac2093a52e (diff) | |
| download | mullvadvpn-608029ca1c403101a88ec45d52e44dc1f22e434f.tar.xz mullvadvpn-608029ca1c403101a88ec45d52e44dc1f22e434f.zip | |
Add TransitionContainer using ReactXP animations
Diffstat (limited to 'app/components')
| -rw-r--r-- | app/components/TransitionContainer.js | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/app/components/TransitionContainer.js b/app/components/TransitionContainer.js new file mode 100644 index 0000000000..c4a011a978 --- /dev/null +++ b/app/components/TransitionContainer.js @@ -0,0 +1,201 @@ +// @flow +import * as React from 'react'; +import { Styles, Component, Animated, View, Types, UserInterface } from 'reactxp'; +import type { TransitionGroupProps } from '../transitions'; + +type TransitionContainerProps = { + children: React.Node, + ...TransitionGroupProps +}; + +type State = { + previousChildren: ?React.Node, + childrenAnimation: Types.AnimatedViewStyleRuleSet, + previousChildrenAnimation: Types.AnimatedViewStyleRuleSet, + animationStyles: Types.AnimatedViewStyleRuleSet, + dimensions: Types.Dimensions, +}; + +export default class TransitionContainer extends Component<TransitionContainerProps, State> { + + constructor(props: TransitionContainerProps) { + super(props); + + const dimensions = UserInterface.measureWindow(); + + this.state = { + dimensions, + animationStyles: { + style: Styles.createAnimatedViewStyle({ + position: 'absolute', + width: dimensions.width, + height: dimensions.height, + }), + allowPointerEvents: Styles.createAnimatedViewStyle({ + pointerEvents: 'auto', + }) + } + }; + } + + componentWillReceiveProps(nextProps: TransitionContainerProps) { + switch (nextProps.name){ + case 'slide-up': + this.slideUpTransition(nextProps); + break; + case 'slide-down': + this.slideDownTransition(nextProps); + break; + case 'push': + this.pushTransition(nextProps); + break; + case 'pop': + this.popTransition(nextProps); + break; + default: + break; + } + } + + onFinishedAnimation() { + this.setState({ + childrenAnimation: this.state.animationStyles.allowPointerEvents, + previousChildren: null + }); + } + + slideUpTransition(nextProps: TransitionContainerProps) { + const currentTranslationValue = Animated.createValue(this.state.dimensions.height); + this.setState({ + previousChildren: this.props.children, + childrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 1, + transform: [{ translateY: currentTranslationValue }] + }), + previousChildrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 0, + transform: [{ translateY: 0 }] + }), + }, () => { + Animated.timing(currentTranslationValue, { + toValue: 0, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }).start(() => this.onFinishedAnimation()); + }); + } + + slideDownTransition(nextProps: TransitionContainerProps) { + const previousTranslationValue = Animated.createValue(0); + this.setState({ + previousChildren: this.props.children, + childrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 0, + transform: [{ translateY: 0 }] + }), + previousChildrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 1, + transform: [{ translateY: previousTranslationValue }] + }), + }, () => { + Animated.timing(previousTranslationValue, { + toValue: this.state.dimensions.height, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }).start(() => this.onFinishedAnimation()); + }); + } + + pushTransition(nextProps: TransitionContainerProps) { + const currentTranslationValue = Animated.createValue(this.state.dimensions.width); + const previousTranslationValue = Animated.createValue(0); + this.setState({ + previousChildren: this.props.children, + childrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 1, + transform: [{ translateX: currentTranslationValue }] + }), + previousChildrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 0, + transform: [{ translateX: previousTranslationValue }] + }), + }, () => { + const compositeAnimation = Animated.parallel([ + Animated.timing(currentTranslationValue, { + toValue: 0, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }), + Animated.timing(previousTranslationValue, { + toValue: - this.state.dimensions.width / 2, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }) + ]); + compositeAnimation.start(() => this.onFinishedAnimation()); + }); + } + + popTransition(nextProps: TransitionContainerProps) { + const currentTranslationValue = Animated.createValue(- this.state.dimensions.width / 2 ); + const previousTranslationValue = Animated.createValue(0); + this.setState({ + previousChildren: this.props.children, + childrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 0, + transform: [{ translateX: currentTranslationValue }] + }), + previousChildrenAnimation: Styles.createAnimatedViewStyle({ + pointerEvents: 'none', + zIndex: 1, + transform: [{ translateX: previousTranslationValue }] + }), + }, () => { + const compositeAnimation = Animated.parallel([ + Animated.timing(currentTranslationValue, { + toValue: 0, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }), + Animated.timing(previousTranslationValue, { + toValue: this.state.dimensions.width, + easing: Animated.Easing.InOut(), + duration: nextProps.duration, + useNativeDriver: true, + }) + ]); + compositeAnimation.start(() => this.onFinishedAnimation()); + }); + } + + render() { + const { children } = this.props; + const { previousChildren, childrenAnimation, previousChildrenAnimation } = this.state; + return ( + <View style={{flex:1}}> + + { previousChildren && + (<Animated.View style={[this.state.animationStyles.style, previousChildrenAnimation]}> + { previousChildren } + </Animated.View>) } + + <Animated.View style={[this.state.animationStyles.style, childrenAnimation]}> + { children } + </Animated.View> + + </View> + ); + } +}
\ No newline at end of file |
