2016-02-13 20:58:47 +05:30
|
|
|
import React, { Component, PropTypes } from 'react';
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
import { connect } from 'react-redux';
|
2016-01-31 18:29:38 +05:30
|
|
|
import { TransitionMotion, spring } from 'react-motion';
|
|
|
|
|
|
|
|
import { Panel, PanelBody, PanelFooter, PanelHeader } from 'components/ui/Panel';
|
2016-05-02 12:45:42 +05:30
|
|
|
import { Form } from 'components/ui/form';
|
2016-05-02 22:55:14 +05:30
|
|
|
import MeasureHeight from 'components/MeasureHeight';
|
2016-05-15 03:21:28 +05:30
|
|
|
import { helpLinks as helpLinksStyles } from 'components/auth/helpLinks.scss';
|
2016-01-31 18:29:38 +05:30
|
|
|
import panelStyles from 'components/ui/panel.scss';
|
|
|
|
import icons from 'components/ui/icons.scss';
|
2016-03-02 02:06:14 +05:30
|
|
|
import authFlow from 'services/authFlow';
|
2016-03-13 14:06:31 +05:30
|
|
|
import { userShape } from 'components/user/User';
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
import * as actions from './actions';
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
const opacitySpringConfig = {stiffness: 300, damping: 20};
|
2016-03-28 09:53:45 +05:30
|
|
|
const transformSpringConfig = {stiffness: 500, damping: 50, precision: 0.5};
|
|
|
|
const changeContextSpringConfig = {stiffness: 500, damping: 20, precision: 0.5};
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-05-15 03:21:28 +05:30
|
|
|
/**
|
|
|
|
* Definition of relation between contexts and panels
|
|
|
|
*
|
|
|
|
* Each sub-array is context. Each sub-array item is panel
|
|
|
|
*
|
|
|
|
* This definition declares animations between panels:
|
|
|
|
* - The animation between panels from different contexts will be along Y axe (height toggling)
|
|
|
|
* - The animation between panels from the same context will be along X axe (sliding)
|
|
|
|
* - Panel index defines the direction of X transition of both panels
|
|
|
|
* (e.g. the panel with lower index will slide from left side, and with greater from right side)
|
|
|
|
*/
|
|
|
|
const contexts = [
|
|
|
|
['login', 'password', 'forgotPassword', 'recoverPassword'],
|
2016-05-23 00:28:43 +05:30
|
|
|
['register', 'activation', 'resendActivation'],
|
2016-05-15 03:21:28 +05:30
|
|
|
['changePassword'],
|
|
|
|
['permissions']
|
|
|
|
];
|
|
|
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') {
|
|
|
|
// test panel uniquenes between contexts
|
|
|
|
// TODO: it may be moved to tests in future
|
|
|
|
|
|
|
|
contexts.reduce((acc, context) => {
|
|
|
|
context.forEach((panel) => {
|
|
|
|
if (acc[panel]) {
|
|
|
|
throw new Error(`Panel ${panel} is already exists in context ${JSON.stringify(acc[panel])}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
acc[panel] = context;
|
|
|
|
});
|
|
|
|
|
|
|
|
return acc;
|
|
|
|
}, {});
|
|
|
|
}
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
class PanelTransition extends Component {
|
|
|
|
static displayName = 'PanelTransition';
|
|
|
|
|
|
|
|
static propTypes = {
|
2016-03-13 14:06:31 +05:30
|
|
|
// context props
|
2016-02-13 20:58:47 +05:30
|
|
|
auth: PropTypes.shape({
|
2016-05-22 19:31:31 +05:30
|
|
|
error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
|
|
|
|
type: PropTypes.string,
|
|
|
|
payload: PropTypes.object
|
|
|
|
})]),
|
2016-04-02 16:28:54 +05:30
|
|
|
isLoading: PropTypes.bool,
|
2016-02-13 20:58:47 +05:30
|
|
|
login: PropTypes.shape({
|
|
|
|
login: PropTypes.string,
|
|
|
|
password: PropTypes.string
|
|
|
|
})
|
|
|
|
}).isRequired,
|
2016-03-13 14:06:31 +05:30
|
|
|
user: userShape.isRequired,
|
2016-05-12 10:00:10 +05:30
|
|
|
setError: PropTypes.func.isRequired,
|
|
|
|
clearErrors: PropTypes.func.isRequired,
|
|
|
|
resolve: PropTypes.func.isRequired,
|
|
|
|
reject: PropTypes.func.isRequired,
|
2016-03-13 14:06:31 +05:30
|
|
|
|
|
|
|
// local props
|
2016-03-15 11:10:18 +05:30
|
|
|
Title: PropTypes.element,
|
|
|
|
Body: PropTypes.element,
|
|
|
|
Footer: PropTypes.element,
|
|
|
|
Links: PropTypes.element,
|
|
|
|
children: PropTypes.element
|
2016-02-13 20:58:47 +05:30
|
|
|
};
|
|
|
|
|
2016-03-13 14:06:31 +05:30
|
|
|
static childContextTypes = {
|
|
|
|
auth: PropTypes.shape({
|
2016-05-22 19:31:31 +05:30
|
|
|
error: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
|
|
|
|
type: PropTypes.string,
|
|
|
|
payload: PropTypes.object
|
|
|
|
})]),
|
2016-03-13 14:06:31 +05:30
|
|
|
login: PropTypes.shape({
|
|
|
|
login: PropTypes.string,
|
|
|
|
password: PropTypes.string
|
|
|
|
})
|
|
|
|
}),
|
|
|
|
user: userShape,
|
2016-05-22 18:37:51 +05:30
|
|
|
requestRedraw: PropTypes.func,
|
2016-05-12 10:00:10 +05:30
|
|
|
clearErrors: PropTypes.func,
|
2016-03-13 14:06:31 +05:30
|
|
|
resolve: PropTypes.func,
|
|
|
|
reject: PropTypes.func
|
|
|
|
};
|
|
|
|
|
2016-03-28 09:16:51 +05:30
|
|
|
state = {
|
2016-05-14 18:08:38 +05:30
|
|
|
contextHeight: 0,
|
|
|
|
panelId: this.props.Body && this.props.Body.type.panelId
|
2016-03-28 09:16:51 +05:30
|
|
|
};
|
|
|
|
|
2016-03-13 14:06:31 +05:30
|
|
|
getChildContext() {
|
|
|
|
return {
|
|
|
|
auth: this.props.auth,
|
|
|
|
user: this.props.user,
|
2016-05-22 18:37:51 +05:30
|
|
|
requestRedraw: () => this.setState({isHeightDirty: true}, () => this.setState({isHeightDirty: false})),
|
2016-03-13 14:06:31 +05:30
|
|
|
clearErrors: this.props.clearErrors,
|
|
|
|
resolve: this.props.resolve,
|
|
|
|
reject: this.props.reject
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-02-03 11:06:00 +05:30
|
|
|
componentWillReceiveProps(nextProps) {
|
2016-03-28 09:16:51 +05:30
|
|
|
const nextPanel = nextProps.Body && nextProps.Body.type.panelId;
|
2016-05-14 18:08:38 +05:30
|
|
|
const prevPanel = this.props.Body && this.props.Body.type.panelId;
|
2016-02-13 20:58:47 +05:30
|
|
|
|
2016-05-14 18:08:38 +05:30
|
|
|
if (nextPanel !== prevPanel) {
|
|
|
|
const direction = this.getDirection(nextPanel, prevPanel);
|
|
|
|
const forceHeight = direction === 'Y' && nextPanel !== prevPanel ? 1 : 0;
|
2016-02-13 20:58:47 +05:30
|
|
|
|
|
|
|
this.props.clearErrors();
|
|
|
|
this.setState({
|
|
|
|
direction,
|
2016-05-14 18:08:38 +05:30
|
|
|
panelId: nextPanel,
|
|
|
|
prevPanelId: prevPanel,
|
2016-03-28 09:16:51 +05:30
|
|
|
forceHeight
|
2016-02-13 20:58:47 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
if (forceHeight) {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.setState({forceHeight: 0});
|
|
|
|
}, 100);
|
|
|
|
}
|
2016-02-03 11:06:00 +05:30
|
|
|
}
|
2016-01-31 18:29:38 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2016-05-02 22:59:50 +05:30
|
|
|
const {contextHeight, forceHeight} = this.state;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-28 09:16:51 +05:30
|
|
|
const {Title, Body, Footer, Links} = this.props;
|
2016-03-27 13:22:00 +05:30
|
|
|
|
2016-03-15 11:10:18 +05:30
|
|
|
if (this.props.children) {
|
|
|
|
return this.props.children;
|
|
|
|
} else if (!Title || !Body || !Footer || !Links) {
|
|
|
|
throw new Error('Title, Body, Footer and Links are required');
|
|
|
|
}
|
|
|
|
|
2016-05-14 18:08:38 +05:30
|
|
|
const {panelId, hasGoBack} = Body.type;
|
2016-03-28 09:16:51 +05:30
|
|
|
|
|
|
|
const formHeight = this.state[`formHeight${panelId}`] || 0;
|
|
|
|
|
2016-05-02 22:59:50 +05:30
|
|
|
// a hack to disable height animation on first render
|
|
|
|
const isHeightMeasured = this.isHeightMeasured;
|
2016-05-02 23:22:37 +05:30
|
|
|
this.isHeightMeasured = isHeightMeasured || formHeight > 0;
|
2016-05-02 22:59:50 +05:30
|
|
|
|
2016-01-31 18:29:38 +05:30
|
|
|
return (
|
|
|
|
<TransitionMotion
|
2016-03-03 10:53:17 +05:30
|
|
|
styles={[
|
2016-03-28 09:16:51 +05:30
|
|
|
{key: panelId, data: {Title, Body, Footer, Links, hasBackButton: hasGoBack}, style: {
|
2016-02-03 11:06:00 +05:30
|
|
|
transformSpring: spring(0, transformSpringConfig),
|
|
|
|
opacitySpring: spring(1, opacitySpringConfig)
|
2016-03-03 10:53:17 +05:30
|
|
|
}},
|
|
|
|
{key: 'common', style: {
|
2016-05-02 22:59:50 +05:30
|
|
|
heightSpring: isHeightMeasured ? spring(forceHeight || formHeight, transformSpringConfig) : formHeight,
|
2016-02-06 15:32:23 +05:30
|
|
|
switchContextHeightSpring: spring(forceHeight || contextHeight, changeContextSpringConfig)
|
2016-03-03 10:53:17 +05:30
|
|
|
}}
|
|
|
|
]}
|
2016-01-31 18:29:38 +05:30
|
|
|
willEnter={this.willEnter}
|
|
|
|
willLeave={this.willLeave}
|
|
|
|
>
|
|
|
|
{(items) => {
|
2016-03-03 10:53:17 +05:30
|
|
|
const panels = items.filter(({key}) => key !== 'common');
|
|
|
|
const common = items.filter(({key}) => key === 'common')[0];
|
2016-02-13 20:58:47 +05:30
|
|
|
|
|
|
|
const contentHeight = {
|
|
|
|
overflow: 'hidden',
|
2016-03-12 19:53:55 +05:30
|
|
|
height: forceHeight ? common.style.switchContextHeightSpring : 'auto'
|
2016-02-13 20:58:47 +05:30
|
|
|
};
|
|
|
|
|
2016-03-28 10:35:18 +05:30
|
|
|
this.tryToAutoFocus(panels.length);
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
const bodyHeight = {
|
|
|
|
position: 'relative',
|
2016-05-02 22:59:50 +05:30
|
|
|
height: `${common.style.heightSpring}px`
|
2016-02-13 20:58:47 +05:30
|
|
|
};
|
2016-02-06 15:32:23 +05:30
|
|
|
|
2016-01-31 18:29:38 +05:30
|
|
|
return (
|
2016-04-02 16:28:54 +05:30
|
|
|
<Form
|
|
|
|
id={panelId}
|
|
|
|
onSubmit={this.onFormSubmit}
|
|
|
|
onInvalid={this.onFormInvalid}
|
|
|
|
isLoading={this.props.auth.isLoading}
|
|
|
|
>
|
2016-01-31 18:29:38 +05:30
|
|
|
<Panel>
|
|
|
|
<PanelHeader>
|
2016-03-03 10:53:17 +05:30
|
|
|
{panels.map((config) => this.getHeader(config))}
|
2016-01-31 18:29:38 +05:30
|
|
|
</PanelHeader>
|
2016-02-13 20:58:47 +05:30
|
|
|
<div style={contentHeight}>
|
2016-03-27 13:22:00 +05:30
|
|
|
<MeasureHeight
|
2016-05-22 18:37:51 +05:30
|
|
|
state={this.shouldMeasureHeight()}
|
2016-03-27 13:22:00 +05:30
|
|
|
onMeasure={this.onUpdateContextHeight}
|
|
|
|
>
|
2016-02-06 15:32:23 +05:30
|
|
|
<PanelBody>
|
2016-02-13 20:58:47 +05:30
|
|
|
<div style={bodyHeight}>
|
2016-03-03 10:53:17 +05:30
|
|
|
{panels.map((config) => this.getBody(config))}
|
2016-02-06 14:33:51 +05:30
|
|
|
</div>
|
|
|
|
</PanelBody>
|
|
|
|
<PanelFooter>
|
2016-03-03 10:53:17 +05:30
|
|
|
{panels.map((config) => this.getFooter(config))}
|
2016-02-06 14:33:51 +05:30
|
|
|
</PanelFooter>
|
2016-03-27 13:22:00 +05:30
|
|
|
</MeasureHeight>
|
2016-02-06 14:33:51 +05:30
|
|
|
</div>
|
2016-01-31 18:29:38 +05:30
|
|
|
</Panel>
|
2016-02-06 15:32:23 +05:30
|
|
|
<div className={helpLinksStyles}>
|
2016-03-03 10:53:17 +05:30
|
|
|
{panels.map((config) => this.getLinks(config))}
|
2016-01-31 18:29:38 +05:30
|
|
|
</div>
|
2016-02-13 20:58:47 +05:30
|
|
|
</Form>
|
2016-01-31 18:29:38 +05:30
|
|
|
);
|
|
|
|
}}
|
|
|
|
</TransitionMotion>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
onFormSubmit = () => {
|
2016-05-01 12:10:35 +05:30
|
|
|
this.props.clearErrors();
|
2016-02-13 20:58:47 +05:30
|
|
|
this.body.onFormSubmit();
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
|
|
|
|
2016-05-02 14:50:50 +05:30
|
|
|
onFormInvalid = (errors) => {
|
|
|
|
this.props.setError(Object.values(errors).shift());
|
2016-02-06 15:32:23 +05:30
|
|
|
};
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
willEnter = (config) => this.getTransitionStyles(config);
|
|
|
|
willLeave = (config) => this.getTransitionStyles(config, {isLeave: true});
|
2016-02-13 20:58:47 +05:30
|
|
|
|
2016-02-06 15:32:23 +05:30
|
|
|
/**
|
2016-03-03 10:53:17 +05:30
|
|
|
* @param {Object} config
|
2016-03-12 19:53:55 +05:30
|
|
|
* @param {string} config.key
|
2016-02-06 15:32:23 +05:30
|
|
|
* @param {Object} [options]
|
|
|
|
* @param {Object} [options.isLeave=false] - true, if this is a leave transition
|
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
2016-03-03 10:53:17 +05:30
|
|
|
getTransitionStyles({key}, options = {}) {
|
|
|
|
const {isLeave = false} = options;
|
2016-05-14 18:08:38 +05:30
|
|
|
const {panelId, prevPanelId} = this.state;
|
|
|
|
|
|
|
|
const fromLeft = -1;
|
|
|
|
const fromRight = 1;
|
2016-02-06 15:32:23 +05:30
|
|
|
|
2016-05-15 03:21:28 +05:30
|
|
|
const currentContext = contexts.find((context) => context.includes(key));
|
|
|
|
let sign = currentContext.indexOf(panelId) > currentContext.indexOf(prevPanelId)
|
|
|
|
? fromRight
|
|
|
|
: fromLeft;
|
|
|
|
if (prevPanelId === key) {
|
|
|
|
sign *= -1;
|
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
const transform = sign * 100;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
|
|
|
return {
|
2016-03-03 10:53:17 +05:30
|
|
|
transformSpring: isLeave ? spring(transform, transformSpringConfig) : transform,
|
|
|
|
opacitySpring: isLeave ? spring(0, opacitySpringConfig) : 1
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
2016-02-06 15:32:23 +05:30
|
|
|
}
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-01 00:06:23 +05:30
|
|
|
getDirection(next, prev) {
|
2016-05-15 03:21:28 +05:30
|
|
|
return contexts.find((context) => context.includes(prev)).includes(next) ? 'X' : 'Y';
|
2016-03-01 00:06:23 +05:30
|
|
|
}
|
|
|
|
|
2016-03-27 13:22:00 +05:30
|
|
|
onUpdateHeight = (height, key) => {
|
|
|
|
const heightKey = `formHeight${key}`;
|
|
|
|
|
2016-01-31 18:29:38 +05:30
|
|
|
this.setState({
|
2016-03-27 13:22:00 +05:30
|
|
|
[heightKey]: height
|
2016-01-31 18:29:38 +05:30
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
onUpdateContextHeight = (height) => {
|
2016-02-06 14:33:51 +05:30
|
|
|
this.setState({
|
|
|
|
contextHeight: height
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-01-31 18:29:38 +05:30
|
|
|
onGoBack = (event) => {
|
|
|
|
event.preventDefault();
|
|
|
|
|
2016-03-02 02:06:14 +05:30
|
|
|
authFlow.goBack();
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
|
|
|
|
2016-03-28 10:35:18 +05:30
|
|
|
/**
|
|
|
|
* Tries to auto focus form fields after transition end
|
|
|
|
*
|
|
|
|
* @param {number} length number of panels transitioned
|
|
|
|
*/
|
|
|
|
tryToAutoFocus(length) {
|
|
|
|
if (!this.body) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length === 1) {
|
|
|
|
if (!this.wasAutoFocused) {
|
|
|
|
this.body.autoFocus();
|
|
|
|
}
|
|
|
|
this.wasAutoFocused = true;
|
|
|
|
} else if (this.wasAutoFocused) {
|
|
|
|
this.wasAutoFocused = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-22 18:37:51 +05:30
|
|
|
shouldMeasureHeight() {
|
|
|
|
return '' + this.props.auth.error + this.state.isHeightDirty;
|
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
getHeader({key, style, data}) {
|
|
|
|
const {Title, hasBackButton} = data;
|
|
|
|
const {transformSpring} = style;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
style = {
|
|
|
|
...this.getDefaultTransitionStyles(key, style),
|
2016-02-06 15:32:23 +05:30
|
|
|
opacity: 1 // reset default
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
const scrollStyle = this.translate(transformSpring, 'Y');
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
const sideScrollStyle = {
|
2016-01-31 18:29:38 +05:30
|
|
|
position: 'relative',
|
|
|
|
zIndex: 2,
|
2016-02-06 15:32:23 +05:30
|
|
|
...this.translate(-Math.abs(transformSpring))
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
const backButton = (
|
2016-02-13 20:58:47 +05:30
|
|
|
<button style={sideScrollStyle} type="button" onClick={this.onGoBack} className={panelStyles.headerControl}>
|
2016-01-31 18:29:38 +05:30
|
|
|
<span className={icons.arrowLeft} />
|
|
|
|
</button>
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
2016-03-28 09:16:51 +05:30
|
|
|
<div key={`header/${key}`} style={style}>
|
2016-01-31 18:29:38 +05:30
|
|
|
{hasBackButton ? backButton : null}
|
|
|
|
<div style={scrollStyle}>
|
2016-03-13 14:06:31 +05:30
|
|
|
{Title}
|
2016-01-31 18:29:38 +05:30
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
getBody({key, style, data}) {
|
|
|
|
const {Body} = data;
|
|
|
|
const {transformSpring} = style;
|
|
|
|
const {direction} = this.state;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
let transform = this.translate(transformSpring, direction);
|
|
|
|
let verticalOrigin = 'top';
|
2016-02-06 14:33:51 +05:30
|
|
|
if (direction === 'Y') {
|
2016-02-02 23:32:00 +05:30
|
|
|
verticalOrigin = 'bottom';
|
2016-02-06 14:33:51 +05:30
|
|
|
transform = {};
|
2016-01-31 18:29:38 +05:30
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
style = {
|
|
|
|
...this.getDefaultTransitionStyles(key, style),
|
2016-02-06 15:32:23 +05:30
|
|
|
top: 'auto', // reset default
|
2016-02-02 23:32:00 +05:30
|
|
|
[verticalOrigin]: 0,
|
2016-02-06 14:33:51 +05:30
|
|
|
...transform
|
2016-01-31 18:29:38 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
2016-03-27 13:22:00 +05:30
|
|
|
<MeasureHeight
|
2016-03-28 09:16:51 +05:30
|
|
|
key={`body/${key}`}
|
2016-03-27 13:22:00 +05:30
|
|
|
style={style}
|
2016-05-22 18:37:51 +05:30
|
|
|
state={this.shouldMeasureHeight()}
|
2016-03-27 13:22:00 +05:30
|
|
|
onMeasure={(height) => this.onUpdateHeight(height, key)}
|
|
|
|
>
|
2016-02-13 20:58:47 +05:30
|
|
|
{React.cloneElement(Body, {
|
|
|
|
ref: (body) => {
|
|
|
|
this.body = body;
|
|
|
|
}
|
|
|
|
})}
|
2016-03-27 13:22:00 +05:30
|
|
|
</MeasureHeight>
|
2016-01-31 18:29:38 +05:30
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
getFooter({key, style, data}) {
|
|
|
|
const {Footer} = data;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
style = this.getDefaultTransitionStyles(key, style);
|
2016-01-31 18:29:38 +05:30
|
|
|
|
|
|
|
return (
|
2016-03-28 09:16:51 +05:30
|
|
|
<div key={`footer/${key}`} style={style}>
|
2016-03-13 14:06:31 +05:30
|
|
|
{Footer}
|
2016-01-31 18:29:38 +05:30
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
getLinks({key, style, data}) {
|
|
|
|
const {Links} = data;
|
2016-01-31 18:29:38 +05:30
|
|
|
|
2016-03-03 10:53:17 +05:30
|
|
|
style = this.getDefaultTransitionStyles(key, style);
|
2016-01-31 18:29:38 +05:30
|
|
|
|
|
|
|
return (
|
2016-03-28 09:16:51 +05:30
|
|
|
<div key={`links/${key}`} style={style}>
|
2016-03-13 14:06:31 +05:30
|
|
|
{Links}
|
2016-01-31 18:29:38 +05:30
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2016-02-06 15:32:23 +05:30
|
|
|
|
|
|
|
/**
|
2016-03-03 10:53:17 +05:30
|
|
|
* @param {string} key
|
2016-03-12 19:53:55 +05:30
|
|
|
* @param {Object} style
|
|
|
|
* @param {number} style.opacitySpring
|
2016-02-06 15:32:23 +05:30
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
2016-03-03 10:53:17 +05:30
|
|
|
getDefaultTransitionStyles(key, {opacitySpring}) {
|
2016-02-06 15:32:23 +05:30
|
|
|
return {
|
|
|
|
position: 'absolute',
|
|
|
|
top: 0,
|
|
|
|
left: 0,
|
|
|
|
width: '100%',
|
|
|
|
opacity: opacitySpring,
|
2016-05-14 18:08:38 +05:30
|
|
|
pointerEvents: key === this.state.panelId ? 'auto' : 'none'
|
2016-02-06 15:32:23 +05:30
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {number} value
|
|
|
|
* @param {string} direction='X' - X|Y
|
|
|
|
* @param {string} unit='%' - %|px etc
|
|
|
|
*
|
|
|
|
* @return {Object}
|
|
|
|
*/
|
|
|
|
translate(value, direction = 'X', unit = '%') {
|
|
|
|
return {
|
|
|
|
WebkitTransform: `translate${direction}(${value}${unit})`,
|
|
|
|
transform: `translate${direction}(${value}${unit})`
|
|
|
|
};
|
|
|
|
}
|
2016-01-31 18:29:38 +05:30
|
|
|
}
|
|
|
|
|
2016-02-13 20:58:47 +05:30
|
|
|
export default connect((state) => ({
|
|
|
|
user: state.user,
|
|
|
|
auth: state.auth,
|
2016-03-02 02:06:14 +05:30
|
|
|
resolve: authFlow.resolve.bind(authFlow),
|
|
|
|
reject: authFlow.reject.bind(authFlow)
|
2016-02-13 20:58:47 +05:30
|
|
|
}), {
|
|
|
|
clearErrors: actions.clearErrors,
|
|
|
|
setError: actions.setError
|
|
|
|
})(PanelTransition);
|