From 01c0c98501c02623b0cd650483d14c99566ce0af Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Wed, 18 Jul 2018 17:47:01 -0700 Subject: Add tabs support for PageContainer --- test/e2e/beta/metamask-beta-ui.spec.js | 2 +- ui/app/components/page-container/index.scss | 2 +- .../page-container-header.component.js | 28 +++++-- .../page-container/page-container.component.js | 95 ++++++++++++++++++---- .../pages/add-token/add-token.component.js | 82 ++++++------------- ui/app/components/tabs/tab/tab.component.js | 8 +- 6 files changed, 133 insertions(+), 84 deletions(-) diff --git a/test/e2e/beta/metamask-beta-ui.spec.js b/test/e2e/beta/metamask-beta-ui.spec.js index dd327accb..40ef90506 100644 --- a/test/e2e/beta/metamask-beta-ui.spec.js +++ b/test/e2e/beta/metamask-beta-ui.spec.js @@ -665,7 +665,7 @@ describe('MetaMask', function () { }) it('picks the newly created Test token', async () => { - const addCustomToken = await findElement(driver, By.xpath("//div[contains(text(), 'Custom Token')]")) + const addCustomToken = await findElement(driver, By.xpath("//li[contains(text(), 'Custom Token')]")) await addCustomToken.click() await delay(regularDelayMs) diff --git a/ui/app/components/page-container/index.scss b/ui/app/components/page-container/index.scss index 06c3ef709..14cdbacd3 100644 --- a/ui/app/components/page-container/index.scss +++ b/ui/app/components/page-container/index.scss @@ -109,7 +109,7 @@ &--selected { color: $curious-blue; - border-bottom: 3px solid $curious-blue; + border-bottom: 2px solid $curious-blue; } } diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js index 5a5de1e5a..338598e5f 100644 --- a/ui/app/components/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js @@ -1,8 +1,8 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' +import classnames from 'classnames' export default class PageContainerHeader extends Component { - static propTypes = { title: PropTypes.string, subtitle: PropTypes.string, @@ -11,8 +11,18 @@ export default class PageContainerHeader extends Component { onBackButtonClick: PropTypes.func, backButtonStyles: PropTypes.object, backButtonString: PropTypes.string, - children: PropTypes.node, - }; + tabs: PropTypes.node, + } + + renderTabs () { + const { tabs } = this.props + + return tabs && ( + + ) + } renderHeaderRow () { const { showBackButton, onBackButtonClick, backButtonStyles, backButtonString } = this.props @@ -31,15 +41,18 @@ export default class PageContainerHeader extends Component { } render () { - const { title, subtitle, onClose, children } = this.props + const { title, subtitle, onClose, tabs } = this.props return ( -
+
{ this.renderHeaderRow() } - { children } - { title &&
{ title } @@ -59,6 +72,7 @@ export default class PageContainerHeader extends Component { /> } + { this.renderTabs() }
) } diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js index 9bfb99ade..10923d2fd 100644 --- a/ui/app/components/page-container/page-container.component.js +++ b/ui/app/components/page-container/page-container.component.js @@ -5,26 +5,93 @@ import PageContainerHeader from './page-container-header' import PageContainerFooter from './page-container-footer' export default class PageContainer extends Component { - static propTypes = { // PageContainerHeader props - title: PropTypes.string.isRequired, - subtitle: PropTypes.string, + backButtonString: PropTypes.string, + backButtonStyles: PropTypes.object, + onBackButtonClick: PropTypes.func, onClose: PropTypes.func, showBackButton: PropTypes.bool, - onBackButtonClick: PropTypes.func, - backButtonStyles: PropTypes.object, - backButtonString: PropTypes.string, + subtitle: PropTypes.string, + title: PropTypes.string.isRequired, + // Tabs-related props + defaultActiveTabIndex: PropTypes.number, + tabsComponent: PropTypes.node, // Content props - ContentComponent: PropTypes.func, - contentComponentProps: PropTypes.object, + contentComponent: PropTypes.node, // PageContainerFooter props - onCancel: PropTypes.func, cancelText: PropTypes.string, + disabled: PropTypes.bool, + onCancel: PropTypes.func, onSubmit: PropTypes.func, submitText: PropTypes.string, - disabled: PropTypes.bool, - }; + } + + state = { + activeTabIndex: 0, + } + + componentDidMount () { + const { defaultActiveTabIndex } = this.props + + if (defaultActiveTabIndex) { + this.setState({ activeTabIndex: defaultActiveTabIndex }) + } + } + + handleTabClick (tabIndex) { + const { activeTabIndex } = this.state + + if (tabIndex !== activeTabIndex) { + this.setState({ + activeTabIndex: tabIndex, + }) + } + } + + renderTabs () { + const { tabsComponent } = this.props + + if (!tabsComponent) { + return + } + + const numberOfTabs = React.Children.count(tabsComponent.props.children) + + return React.Children.map(tabsComponent.props.children, (child, index) => { + return child && React.cloneElement(child, { + onClick: index => this.handleTabClick(index), + tabIndex: index, + isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, + key: index, + className: 'page-container__tab', + activeClassName: 'page-container__tab--selected', + }) + }) + } + + renderActiveTabContent () { + const { tabsComponent } = this.props + const { children } = tabsComponent.props + const { activeTabIndex } = this.state + + return children[activeTabIndex] + ? children[activeTabIndex].props.children + : children.props.children + } + + renderContent () { + const { contentComponent, tabsComponent } = this.props + + switch (true) { + case Boolean(contentComponent): + return contentComponent + case Boolean(tabsComponent): + return this.renderActiveTabContent() + default: + return null + } + } render () { const { @@ -35,8 +102,6 @@ export default class PageContainer extends Component { onBackButtonClick, backButtonStyles, backButtonString, - ContentComponent, - contentComponentProps, onCancel, cancelText, onSubmit, @@ -54,9 +119,10 @@ export default class PageContainer extends Component { onBackButtonClick={onBackButtonClick} backButtonStyles={backButtonStyles} backButtonString={backButtonString} + tabs={this.renderTabs()} />
- + { this.renderContent() }
) } - } diff --git a/ui/app/components/pages/add-token/add-token.component.js b/ui/app/components/pages/add-token/add-token.component.js index bcb93d401..59748ff46 100644 --- a/ui/app/components/pages/add-token/add-token.component.js +++ b/ui/app/components/pages/add-token/add-token.component.js @@ -1,14 +1,14 @@ import React, { Component } from 'react' -import classnames from 'classnames' import PropTypes from 'prop-types' import ethUtil from 'ethereumjs-util' import { checkExistingAddresses } from './util' import { tokenInfoGetter } from '../../../token-util' import { DEFAULT_ROUTE, CONFIRM_ADD_TOKEN_ROUTE } from '../../../routes' -import Button from '../../button' import TextField from '../../text-field' import TokenList from './token-list' import TokenSearch from './token-search' +import PageContainer from '../../page-container' +import { Tabs, Tab } from '../../tabs' const emptyAddr = '0x0000000000000000000000000000000000000000' const SEARCH_TAB = 'SEARCH' @@ -285,65 +285,33 @@ class AddToken extends Component { ) } + renderTabs () { + return ( + + + { this.renderSearchToken() } + + + { this.renderCustomTokenForm() } + + + ) + } + render () { - const { displayedTab } = this.state const { history, clearPendingTokens } = this.props return ( -
-
-
- { this.context.t('addTokens') } -
-
-
this.setState({ displayedTab: SEARCH_TAB })} - > - { this.context.t('search') } -
-
this.setState({ displayedTab: CUSTOM_TOKEN_TAB })} - > - { this.context.t('customToken') } -
-
-
-
- { - displayedTab === CUSTOM_TOKEN_TAB - ? this.renderCustomTokenForm() - : this.renderSearchToken() - } -
-
- - -
-
+ this.handleNext()} + disabled={this.hasError() || !this.hasSelected()} + onCancel={() => { + clearPendingTokens() + history.push(DEFAULT_ROUTE) + }} + /> ) } } diff --git a/ui/app/components/tabs/tab/tab.component.js b/ui/app/components/tabs/tab/tab.component.js index a59da8904..481513233 100644 --- a/ui/app/components/tabs/tab/tab.component.js +++ b/ui/app/components/tabs/tab/tab.component.js @@ -3,13 +3,13 @@ import PropTypes from 'prop-types' import classnames from 'classnames' const Tab = props => { - const { name, onClick, isActive, tabIndex } = props + const { name, onClick, isActive, tabIndex, className, activeClassName } = props return (
  • { event.preventDefault() @@ -26,6 +26,8 @@ Tab.propTypes = { onClick: PropTypes.func, isActive: PropTypes.bool, tabIndex: PropTypes.number, + className: PropTypes.string, + activeClassName: PropTypes.string, } export default Tab -- cgit From d7d141cea54ba7bbeb2e7db9fb7ed54ce0733d4b Mon Sep 17 00:00:00 2001 From: Alexander Tseung Date: Fri, 20 Jul 2018 15:42:28 -0700 Subject: Fix code readability, use PureComponent over Component --- .../page-container-header.component.js | 2 +- .../page-container/page-container.component.js | 45 ++++++++-------------- ui/app/components/tabs/tab/tab.component.js | 9 ++++- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/ui/app/components/page-container/page-container-header/page-container-header.component.js b/ui/app/components/page-container/page-container-header/page-container-header.component.js index 338598e5f..a8458604e 100644 --- a/ui/app/components/page-container/page-container-header/page-container-header.component.js +++ b/ui/app/components/page-container/page-container-header/page-container-header.component.js @@ -47,7 +47,7 @@ export default class PageContainerHeader extends Component {
    diff --git a/ui/app/components/page-container/page-container.component.js b/ui/app/components/page-container/page-container.component.js index 10923d2fd..3a2274a29 100644 --- a/ui/app/components/page-container/page-container.component.js +++ b/ui/app/components/page-container/page-container.component.js @@ -1,10 +1,10 @@ -import React, { Component } from 'react' +import React, { PureComponent } from 'react' import PropTypes from 'prop-types' import PageContainerHeader from './page-container-header' import PageContainerFooter from './page-container-footer' -export default class PageContainer extends Component { +export default class PageContainer extends PureComponent { static propTypes = { // PageContainerHeader props backButtonString: PropTypes.string, @@ -28,25 +28,11 @@ export default class PageContainer extends Component { } state = { - activeTabIndex: 0, + activeTabIndex: this.props.defaultActiveTabIndex || 0, } - componentDidMount () { - const { defaultActiveTabIndex } = this.props - - if (defaultActiveTabIndex) { - this.setState({ activeTabIndex: defaultActiveTabIndex }) - } - } - - handleTabClick (tabIndex) { - const { activeTabIndex } = this.state - - if (tabIndex !== activeTabIndex) { - this.setState({ - activeTabIndex: tabIndex, - }) - } + handleTabClick (activeTabIndex) { + this.setState({ activeTabIndex }) } renderTabs () { @@ -58,12 +44,12 @@ export default class PageContainer extends Component { const numberOfTabs = React.Children.count(tabsComponent.props.children) - return React.Children.map(tabsComponent.props.children, (child, index) => { + return React.Children.map(tabsComponent.props.children, (child, tabIndex) => { return child && React.cloneElement(child, { onClick: index => this.handleTabClick(index), - tabIndex: index, - isActive: numberOfTabs > 1 && index === this.state.activeTabIndex, - key: index, + tabIndex, + isActive: numberOfTabs > 1 && tabIndex === this.state.activeTabIndex, + key: tabIndex, className: 'page-container__tab', activeClassName: 'page-container__tab--selected', }) @@ -83,13 +69,12 @@ export default class PageContainer extends Component { renderContent () { const { contentComponent, tabsComponent } = this.props - switch (true) { - case Boolean(contentComponent): - return contentComponent - case Boolean(tabsComponent): - return this.renderActiveTabContent() - default: - return null + if (contentComponent) { + return contentComponent + } else if (tabsComponent) { + return this.renderActiveTabContent() + } else { + return null } } diff --git a/ui/app/components/tabs/tab/tab.component.js b/ui/app/components/tabs/tab/tab.component.js index 481513233..9e590391c 100644 --- a/ui/app/components/tabs/tab/tab.component.js +++ b/ui/app/components/tabs/tab/tab.component.js @@ -8,8 +8,8 @@ const Tab = props => { return (
  • { event.preventDefault() @@ -30,4 +30,9 @@ Tab.propTypes = { activeClassName: PropTypes.string, } +Tab.defaultProps = { + className: 'tab', + activeClassName: 'tab--active', +} + export default Tab -- cgit