Skip to content

Commit

Permalink
reworks transitions (decred#820)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jascha-Sundaresan authored and alexlyp committed Oct 21, 2017
1 parent 4cf589d commit a18a49e
Show file tree
Hide file tree
Showing 22 changed files with 308 additions and 422 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ module.exports = {
"react/jsx-uses-react":1,
},
"globals": {
"Uint8Array": true
"Uint8Array": true,
"Map": true,
"React": true,
"PropTypes": true,
"autobind": true,
}
};
50 changes: 0 additions & 50 deletions app/components/PageTransitions.js

This file was deleted.

84 changes: 0 additions & 84 deletions app/components/TabbedPage/Header.js

This file was deleted.

11 changes: 0 additions & 11 deletions app/components/TabbedPage/TabContent.js

This file was deleted.

29 changes: 0 additions & 29 deletions app/components/TabbedPage/index.js

This file was deleted.

51 changes: 51 additions & 0 deletions app/components/shared/RouteTransition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createElement as h } from "react";
import { spring, TransitionMotion } from "react-motion";
import { object, string, func, bool } from "prop-types";

const ensureSpring = (styles, options) => (
Object.keys(styles).reduce((acc, key) => {
const value = styles[key];
acc[key] = typeof value === "number" ? spring(value, options) : value;
return acc;
}, {})
);

const RouteTransition = props => {
const base = { data: props.children, key: props.pathname };
const defaultStyles =
!props.runOnMount ? null :
!props.children ? [] :
[{...base, style: props.atEnter }];

const styles =
!props.children ? [] :
[{...base, style: ensureSpring(props.atActive, props.opts) }];

const willEnter = () => props.atEnter;
const willLeave = () => ensureSpring(props.atLeave, props.opts);
const tmProps = { willEnter, willLeave, defaultStyles, styles };
const route = ({ key, style, data }) => {
const routeProps = {...{key}, style: props.mapStyles(style) };
return h("div", routeProps, data);
};
const routes = routes => h("div", null, routes.map(route));
return h(TransitionMotion, tmProps, routes);
};

RouteTransition.defaultProps = {
runOnMount: true,
mapStyles: val => val,
opts: { stiffness: 40, damping: 26 }
};

RouteTransition.propTypes = {
atEnter: object.isRequired,
atActive: object.isRequired,
atLeave: object.isRequired,
pathname: string.isRequired,
mapStyles: func,
runOnMount: bool,
opts: object
};

export default RouteTransition;
1 change: 1 addition & 0 deletions app/components/shared/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as RouteTransition } from "./RouteTransition";
export { default as Tooltip } from "./Tooltip";
94 changes: 94 additions & 0 deletions app/components/views/TransactionsPage/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { spring, Motion } from "react-motion";
import { Link } from "react-router";
import { injectIntl, defineMessages, intlShape } from "react-intl";
import "style/Header.less";
import headerConnector from "connectors/header";

const opts = { stiffness: 150, damping: 20 };

const messages = defineMessages({
"transactions.title": { id: "transactions.title", defaultMessage: "Transactions" },
"transactions.description.testnet": { id: "transactions.description.testnet", defaultMessage: "Testnet Decred addresses always begin with letter T and contain 26-35 alphanumeric characters (e.g. TxxXXXXXxXXXxXXXXxxx0XxXXXxxXxXxX0)." },
"transactions.description.mainnet": { id: "transactions.description.mainnet", defaultMessage: "Mainnet Decred addresses always begin with letter D and contain 26-35 alphanumeric characters (e.g. DxxXXXXXxXXXxXXXXxxx0XxXXXxxXxXxX0X)." },
"transactions.tab.send": { id: "transactions.tab.send", defaultMessage: "Send" },
"transactions.tab.receive": { id: "transactions.tab.receive", defaultMessage: "Receive" },
});

@autobind
class Header extends React.Component {
constructor(props) {
super(props);
this._nodes = new Map();
this.state = { caretLeft: null, caretWidth: null, selectedTab: null };
}
componentDidMount() {
this.updateCaretPosition(this.props.pathname);
}

componentDidUpdate() {
if (this.state.selectedTab != this.props.pathname) {
const caretPosition = this.neededCaretPosition(this.props.pathname);
this.setState({ selectedTab: this.props.pathname, ...caretPosition });
}
}

updateCaretPosition(tab) {
const caretPosition = this.neededCaretPosition(tab);
if (caretPosition) this.setState(caretPosition);
}
neededCaretPosition(tab) {
const tabForRoute = this._nodes.get(tab);
if (!tabForRoute) return null;
const tabRect = tabForRoute.getBoundingClientRect();
const caretLeft = tabForRoute.offsetLeft;
const caretWidth = tabRect.width;
return {caretLeft, caretWidth};
}
render () {
const { isTestNet, page, tabs, intl } = this.props;
const { caretLeft, caretWidth } = this.state;
const description = [page, "description", isTestNet ? "testnet" : "mainnet"].join(".");
const headerIcon = ["header-icon", page].join("-");
const title = [page, "title"].join(".");
return (
<div className="header">
<div className="header-top"></div>

<div className="tabbedheader-title">
<span className={ "tabbedheader-icon " + headerIcon } />
{ intl.formatMessage(messages[title]) }
</div>

<div className="tabbedheader-description">
{ intl.formatMessage(messages[description]) }
</div>

<div className="tabbedheader-tabs">
{ tabs.map((tab) => {
const title = [page, "tab", tab].join(".");
const route = ["", page, tab].join("/");
return (
<div className="tabbedheader-ref" ref={ ref => this._nodes.set(tab, ref) } key={ tab }>
<Link to={ route } onClick={() => this.updateCaretPosition(tab) } className="tabbedheader-tab" >
{ intl.formatMessage(messages[title]) }
</Link>
</div>
);
})}
<Motion style={{ left: spring(caretLeft, opts), width: spring(caretWidth, opts) }}>
{ style => <div className="tabbedheader-active-tab-caret" style={ style }/> }
</Motion>
</div>
</div>
);
}
}

Header.propTypes = {
isTestNet: PropTypes.bool,
page: PropTypes.string.isRequired,
tabs: PropTypes.arrayOf(PropTypes.string),
intl: intlShape
};

export default injectIntl(headerConnector(Header));
17 changes: 8 additions & 9 deletions app/components/views/TransactionsPage/ReceiveTab/Page.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import React from "react";
import TabContent from "../../../TabbedPage/TabContent";
import ReactTooltip from "react-tooltip";
import ReceiveAccountsSelect from "../../../ReceiveAccountsSelect";
import ReceiveAccountsSelect from "ReceiveAccountsSelect";
import { Link } from "react-router";
import KeyBlueButton from "../../../KeyBlueButton";
import CopyToClipboardButton from "../../../CopyToClipboardButton";
import KeyBlueButton from "KeyBlueButton";
import CopyToClipboardButton from "CopyToClipboardButton";
import QRCode from "./QRCode";
import { defineMessages, FormattedMessage as T, injectIntl } from "react-intl";
import "../../../../style/Layout.less";
import "../../../../style/ReceivePage.less";
import "../../../../style/MiscComponents.less";
import "style/Layout.less";
import "style/ReceivePage.less";
import "style/MiscComponents.less";

const messages = defineMessages({
accountsTip: {
Expand All @@ -23,7 +22,7 @@ const ReceivePage = ({
intl,
onRequestAddress,
}) => (
<TabContent>
<div className="tab-content-wrapper">
<div className="receive-content-nest">
<div className="receive-content-nest-for-address">
<Link
Expand Down Expand Up @@ -61,7 +60,7 @@ const ReceivePage = ({
</KeyBlueButton>
</div>
<ReactTooltip />
</TabContent>
</div>
);

export default injectIntl(ReceivePage);
7 changes: 3 additions & 4 deletions app/components/views/TransactionsPage/ReceiveTab/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ class Receive extends Component{
const { walletService } = this.props;
const { onRequestAddress } = this;

return walletService
? <ReceivePage {...{
return !walletService ? <ErrorScreen /> :
<ReceivePage {...{
...this.props,
...this.state,
onRequestAddress
}} />
: <ErrorScreen />;
}} />;
}

onRequestAddress () {
Expand Down
Loading

0 comments on commit a18a49e

Please sign in to comment.