Исправлен баг с не правильным определением высоты панели в том случае, если путь меняется раньше чем компоненты

This commit is contained in:
SleepWalker 2016-03-28 06:46:51 +03:00
parent a17c70fcc1
commit 8501430387
9 changed files with 60 additions and 56 deletions

View File

@ -2,6 +2,7 @@ import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
export default class MeasureHeight extends Component { export default class MeasureHeight extends Component {
static displayName = 'MeasureHeight';
static propTypes = { static propTypes = {
shouldMeasure: PropTypes.func, shouldMeasure: PropTypes.func,
onMeasure: PropTypes.func onMeasure: PropTypes.func

View File

@ -37,7 +37,6 @@ class PanelTransition extends Component {
reject: React.PropTypes.func.isRequired, reject: React.PropTypes.func.isRequired,
// local props // local props
path: PropTypes.string.isRequired,
Title: PropTypes.element, Title: PropTypes.element,
Body: PropTypes.element, Body: PropTypes.element,
Footer: PropTypes.element, Footer: PropTypes.element,
@ -59,6 +58,10 @@ class PanelTransition extends Component {
reject: PropTypes.func reject: PropTypes.func
}; };
state = {
contextHeight: 0
};
getChildContext() { getChildContext() {
return { return {
auth: this.props.auth, auth: this.props.auth,
@ -69,23 +72,18 @@ class PanelTransition extends Component {
}; };
} }
state = {
contextHeight: 0
};
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
var nextPath = nextProps.path; const nextPanel = nextProps.Body && nextProps.Body.type.panelId;
var previousPath = this.props.path; const previousPanel = this.props.Body && this.props.Body.type.panelId;
if (nextPath !== previousPath) { if (nextPanel !== previousPanel) {
var direction = this.getDirection(nextPath, previousPath); const direction = this.getDirection(nextPanel, previousPanel);
var forceHeight = direction === 'Y' && nextPath !== previousPath ? 1 : 0; const forceHeight = direction === 'Y' && nextPanel !== previousPanel ? 1 : 0;
this.props.clearErrors(); this.props.clearErrors();
this.setState({ this.setState({
direction, direction,
forceHeight, forceHeight
previousPath
}); });
if (forceHeight) { if (forceHeight) {
@ -99,9 +97,7 @@ class PanelTransition extends Component {
render() { render() {
const {canAnimateHeight, contextHeight, forceHeight} = this.state; const {canAnimateHeight, contextHeight, forceHeight} = this.state;
const {path, Title, Body, Footer, Links} = this.props; const {Title, Body, Footer, Links} = this.props;
const formHeight = this.state[`formHeight${path}`] || 0;
if (this.props.children) { if (this.props.children) {
return this.props.children; return this.props.children;
@ -109,10 +105,15 @@ class PanelTransition extends Component {
throw new Error('Title, Body, Footer and Links are required'); throw new Error('Title, Body, Footer and Links are required');
} }
const panelId = Body.type.panelId;
const hasGoBack = Body.type.hasGoBack;
const formHeight = this.state[`formHeight${panelId}`] || 0;
return ( return (
<TransitionMotion <TransitionMotion
styles={[ styles={[
{key: path, data: {Title, Body, Footer, Links, hasBackButton: Title.type.goBack}, style: { {key: panelId, data: {Title, Body, Footer, Links, hasBackButton: hasGoBack}, style: {
transformSpring: spring(0, transformSpringConfig), transformSpring: spring(0, transformSpringConfig),
opacitySpring: spring(1, opacitySpringConfig) opacitySpring: spring(1, opacitySpringConfig)
}}, }},
@ -139,7 +140,7 @@ class PanelTransition extends Component {
}; };
return ( return (
<Form id={path} onSubmit={this.onFormSubmit} onInvalid={this.onFormInvalid}> <Form id={panelId} onSubmit={this.onFormSubmit} onInvalid={this.onFormInvalid}>
<Panel> <Panel>
<PanelHeader> <PanelHeader>
{panels.map((config) => this.getHeader(config))} {panels.map((config) => this.getHeader(config))}
@ -193,13 +194,13 @@ class PanelTransition extends Component {
const {isLeave = false} = options; const {isLeave = false} = options;
const map = { const map = {
'/login': -1, login: -1,
'/register': -1, register: -1,
'/password': 1, password: 1,
'/activation': 1, activation: 1,
'/oauth/permissions': -1, permissions: -1,
'/change-password': 1, changePassword: 1,
'/forgot-password': 1 forgotPassword: 1
}; };
const sign = map[key]; const sign = map[key];
@ -212,16 +213,16 @@ class PanelTransition extends Component {
} }
getDirection(next, prev) { getDirection(next, prev) {
var not = (path) => prev !== path && next !== path; const not = (panelId) => prev !== panelId && next !== panelId;
var map = { const map = {
'/login': not('/password') && not('/forgot-password') ? 'Y' : 'X', login: not('password') && not('forgotPassword') ? 'Y' : 'X',
'/password': not('/login') && not('/forgot-password') ? 'Y' : 'X', password: not('login') && not('forgotPassword') ? 'Y' : 'X',
'/register': not('/activation') ? 'Y' : 'X', register: not('activation') ? 'Y' : 'X',
'/activation': not('/register') ? 'Y' : 'X', activation: not('register') ? 'Y' : 'X',
'/oauth/permissions': 'Y', permissions: 'Y',
'/change-password': 'Y', changePassword: 'Y',
'/forgot-password': not('/password') && not('/login') ? 'Y' : 'X' forgotPassword: not('password') && not('login') ? 'Y' : 'X'
}; };
return map[next]; return map[next];
@ -232,7 +233,7 @@ class PanelTransition extends Component {
// we need to skip first render, because there is no panel to make transition from // we need to skip first render, because there is no panel to make transition from
// const canAnimateHeight = Object.keys(this.state.height).length > 1 || this.state[heightKey]; // const canAnimateHeight = Object.keys(this.state.height).length > 1 || this.state[heightKey];
const canAnimateHeight = true; const canAnimateHeight = true; // NOTE: lets try to always animate
this.setState({ this.setState({
canAnimateHeight, canAnimateHeight,
@ -276,7 +277,7 @@ class PanelTransition extends Component {
); );
return ( return (
<div key={`header${key}`} style={style}> <div key={`header/${key}`} style={style}>
{hasBackButton ? backButton : null} {hasBackButton ? backButton : null}
<div style={scrollStyle}> <div style={scrollStyle}>
{Title} {Title}
@ -306,7 +307,7 @@ class PanelTransition extends Component {
return ( return (
<MeasureHeight <MeasureHeight
key={`body${key}`} key={`body/${key}`}
style={style} style={style}
state={this.props.auth.error} state={this.props.auth.error}
onMeasure={(height) => this.onUpdateHeight(height, key)} onMeasure={(height) => this.onUpdateHeight(height, key)}
@ -326,7 +327,7 @@ class PanelTransition extends Component {
style = this.getDefaultTransitionStyles(key, style); style = this.getDefaultTransitionStyles(key, style);
return ( return (
<div key={`footer${key}`} style={style}> <div key={`footer/${key}`} style={style}>
{Footer} {Footer}
</div> </div>
); );
@ -338,7 +339,7 @@ class PanelTransition extends Component {
style = this.getDefaultTransitionStyles(key, style); style = this.getDefaultTransitionStyles(key, style);
return ( return (
<div key={`links${key}`} style={style}> <div key={`links/${key}`} style={style}>
{Links} {Links}
</div> </div>
); );
@ -358,7 +359,7 @@ class PanelTransition extends Component {
left: 0, left: 0,
width: '100%', width: '100%',
opacity: opacitySpring, opacity: opacitySpring,
pointerEvents: key === this.props.path ? 'auto' : 'none' pointerEvents: key === this.props.Body.type.panelId ? 'auto' : 'none'
}; };
} }
@ -380,7 +381,6 @@ class PanelTransition extends Component {
export default connect((state) => ({ export default connect((state) => ({
user: state.user, user: state.user,
auth: state.auth, auth: state.auth,
path: state.routing.location.pathname,
resolve: authFlow.resolve.bind(authFlow), resolve: authFlow.resolve.bind(authFlow),
reject: authFlow.reject.bind(authFlow) reject: authFlow.reject.bind(authFlow)
}), { }), {

View File

@ -12,6 +12,7 @@ import messages from './Activation.messages';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'ActivationBody'; static displayName = 'ActivationBody';
static panelId = 'activation';
render() { render() {
return ( return (

View File

@ -13,6 +13,7 @@ import styles from './changePassword.scss';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'ChangePasswordBody'; static displayName = 'ChangePasswordBody';
static panelId = 'changePassword';
render() { render() {
return ( return (

View File

@ -13,6 +13,8 @@ import styles from './forgotPassword.scss';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'ForgotPasswordBody'; static displayName = 'ForgotPasswordBody';
static panelId = 'forgotPassword';
static hasGoBack = true;
// Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить? // Если юзер вводил своё мыло во время попытки авторизации, то почему бы его сюда автоматически не подставить?
render() { render() {
@ -45,15 +47,12 @@ class Body extends BaseAuthBody {
} }
export default function ForgotPassword() { export default function ForgotPassword() {
var Title = () => ( // TODO: separate component for PageTitle
<Message {...messages.forgotPasswordTitle}>
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
</Message>
);
Title.goBack = true;
return { return {
Title, Title: () => ( // TODO: separate component for PageTitle
<Message {...messages.forgotPasswordTitle}>
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
</Message>
),
Body, Body,
Footer: () => ( Footer: () => (
<button className={buttons.lightViolet} type="submit"> <button className={buttons.lightViolet} type="submit">

View File

@ -13,6 +13,7 @@ import messages from './Login.messages';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'LoginBody'; static displayName = 'LoginBody';
static panelId = 'login';
render() { render() {
return ( return (

View File

@ -14,6 +14,8 @@ import messages from './Password.messages';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'PasswordBody'; static displayName = 'PasswordBody';
static panelId = 'password';
static hasGoBack = true;
render() { render() {
const {user} = this.context; const {user} = this.context;
@ -49,15 +51,12 @@ class Body extends BaseAuthBody {
} }
export default function Password() { export default function Password() {
var Title = () => ( // TODO: separate component for PageTitle
<Message {...messages.passwordTitle}>
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
</Message>
);
Title.goBack = true;
return { return {
Title, Title: () => ( // TODO: separate component for PageTitle
<Message {...messages.passwordTitle}>
{(msg) => <span>{msg}<Helmet title={msg} /></span>}
</Message>
),
Body, Body,
Footer: () => ( Footer: () => (
<button className={buttons.green} type="submit"> <button className={buttons.green} type="submit">

View File

@ -13,6 +13,7 @@ import messages from './Permissions.messages';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'PermissionsBody'; static displayName = 'PermissionsBody';
static panelId = 'permissions';
render() { render() {
const {user} = this.context; const {user} = this.context;

View File

@ -14,6 +14,7 @@ import messages from './Register.messages';
class Body extends BaseAuthBody { class Body extends BaseAuthBody {
static displayName = 'RegisterBody'; static displayName = 'RegisterBody';
static panelId = 'register';
render() { render() {
return ( return (