summaryrefslogtreecommitdiffhomepage
path: root/app/components
diff options
context:
space:
mode:
authoranderklander <anderklander@gmail.com>2018-02-21 14:46:07 +0100
committerAndrej Mihajlov <and@mullvad.net>2018-02-26 16:15:52 +0100
commit608029ca1c403101a88ec45d52e44dc1f22e434f (patch)
treef2f7bb91c19f6d01d259e785242dbd967bc6392f /app/components
parent47a78129cd2f953fe4dca33a04c138ac2093a52e (diff)
downloadmullvadvpn-608029ca1c403101a88ec45d52e44dc1f22e434f.tar.xz
mullvadvpn-608029ca1c403101a88ec45d52e44dc1f22e434f.zip
Add TransitionContainer using ReactXP animations
Diffstat (limited to 'app/components')
-rw-r--r--app/components/TransitionContainer.js201
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