1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-10-22 19:26:13 +02:00

Add tabs support for PageContainer

This commit is contained in:
Alexander Tseung 2018-07-18 17:47:01 -07:00
parent f30b726df7
commit 01c0c98501
6 changed files with 133 additions and 84 deletions

View File

@ -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)

View File

@ -109,7 +109,7 @@
&--selected {
color: $curious-blue;
border-bottom: 3px solid $curious-blue;
border-bottom: 2px solid $curious-blue;
}
}

View File

@ -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 && (
<ul className="page-container__tabs">
{ tabs }
</ul>
)
}
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 (
<div className="page-container__header">
<div className={
classnames(
'page-container__header',
tabs && 'page-container__header--no-padding-bottom'
)
}>
{ this.renderHeaderRow() }
{ children }
{
title && <div className="page-container__title">
{ title }
@ -59,6 +72,7 @@ export default class PageContainerHeader extends Component {
/>
}
{ this.renderTabs() }
</div>
)
}

View File

@ -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()}
/>
<div className="page-container__content">
<ContentComponent { ...contentComponentProps } />
{ this.renderContent() }
</div>
<PageContainerFooter
onCancel={onCancel}
@ -68,5 +134,4 @@ export default class PageContainer extends Component {
</div>
)
}
}

View File

@ -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 (
<Tabs>
<Tab name={this.context.t('search')}>
{ this.renderSearchToken() }
</Tab>
<Tab name={this.context.t('customToken')}>
{ this.renderCustomTokenForm() }
</Tab>
</Tabs>
)
}
render () {
const { displayedTab } = this.state
const { history, clearPendingTokens } = this.props
return (
<div className="page-container">
<div className="page-container__header page-container__header--no-padding-bottom">
<div className="page-container__title">
{ this.context.t('addTokens') }
</div>
<div className="page-container__tabs">
<div
className={classnames('page-container__tab', {
'page-container__tab--selected': displayedTab === SEARCH_TAB,
})}
onClick={() => this.setState({ displayedTab: SEARCH_TAB })}
>
{ this.context.t('search') }
</div>
<div
className={classnames('page-container__tab', {
'page-container__tab--selected': displayedTab === CUSTOM_TOKEN_TAB,
})}
onClick={() => this.setState({ displayedTab: CUSTOM_TOKEN_TAB })}
>
{ this.context.t('customToken') }
</div>
</div>
</div>
<div className="page-container__content">
{
displayedTab === CUSTOM_TOKEN_TAB
? this.renderCustomTokenForm()
: this.renderSearchToken()
}
</div>
<div className="page-container__footer">
<Button
type="default"
large
className="page-container__footer-button"
onClick={() => {
clearPendingTokens()
history.push(DEFAULT_ROUTE)
}}
>
{ this.context.t('cancel') }
</Button>
<Button
type="primary"
large
className="page-container__footer-button"
onClick={() => this.handleNext()}
disabled={this.hasError() || !this.hasSelected()}
>
{ this.context.t('next') }
</Button>
</div>
</div>
<PageContainer
title={this.context.t('addTokens')}
tabsComponent={this.renderTabs()}
onSubmit={() => this.handleNext()}
disabled={this.hasError() || !this.hasSelected()}
onCancel={() => {
clearPendingTokens()
history.push(DEFAULT_ROUTE)
}}
/>
)
}
}

View File

@ -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 (
<li
className={classnames(
'tab',
isActive && 'tab--active',
className || 'tab',
isActive && (activeClassName || 'tab--active'),
)}
onClick={event => {
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