Add SelectionList component to DRY up (#4639)
* Added SelectionList component for selections * Use SelectionList in DappPermisions * AddDapps uses SelectionList * Fix AccountCard to consistent height * Convert Signer defaults to SelectionList * Subtle selection border * Convert VaultAccounts to SelectionList * Add tests for SectionList component * Apply scroll fixes from lates commit in #4621 * Remove unneeded logs * Remove extra div, fixing ParityBar overflow
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: 0.5em 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
transition: transform ease-out 0.1s;
|
||||
transform: scale(1);
|
||||
|
||||
@@ -39,7 +39,7 @@ export default class AccountCard extends Component {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { account, balance, className } = this.props;
|
||||
const { account, balance, className, onFocus } = this.props;
|
||||
const { copied } = this.state;
|
||||
const { address, description, meta = {}, name } = account;
|
||||
const { tags = [] } = meta;
|
||||
@@ -49,14 +49,18 @@ export default class AccountCard extends Component {
|
||||
classes.push(styles.copied);
|
||||
}
|
||||
|
||||
const props = onFocus
|
||||
? { tabIndex: 0 }
|
||||
: {};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={ address }
|
||||
tabIndex={ 0 }
|
||||
className={ classes.join(' ') }
|
||||
onClick={ this.onClick }
|
||||
onFocus={ this.onFocus }
|
||||
onKeyDown={ this.handleKeyDown }
|
||||
{ ...props }
|
||||
>
|
||||
<div className={ styles.mainContainer }>
|
||||
<div className={ styles.infoContainer }>
|
||||
|
||||
@@ -146,4 +146,8 @@
|
||||
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.account {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +346,7 @@ class AddressSelect extends Component {
|
||||
<AccountCard
|
||||
account={ account }
|
||||
balance={ balance }
|
||||
className={ styles.account }
|
||||
key={ `account_${index}` }
|
||||
onClick={ this.handleClick }
|
||||
onFocus={ this.focusItem }
|
||||
|
||||
17
js/src/ui/SelectionList/index.js
Normal file
17
js/src/ui/SelectionList/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export default from './selectionList';
|
||||
57
js/src/ui/SelectionList/selectionList.css
Normal file
57
js/src/ui/SelectionList/selectionList.css
Normal file
@@ -0,0 +1,57 @@
|
||||
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
/* This file is part of Parity.
|
||||
/*
|
||||
/* Parity is free software: you can redistribute it and/or modify
|
||||
/* it under the terms of the GNU General Public License as published by
|
||||
/* the Free Software Foundation, either version 3 of the License, or
|
||||
/* (at your option) any later version.
|
||||
/*
|
||||
/* Parity is distributed in the hope that it will be useful,
|
||||
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
/* GNU General Public License for more details.
|
||||
/*
|
||||
/* You should have received a copy of the GNU General Public License
|
||||
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
box-shadow: inset 0 0 0 2px rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.content {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: absolute;
|
||||
right: 0.5em;
|
||||
top: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.selected {
|
||||
box-shadow: inset 0 0 0 2px rgb(255, 255, 255);
|
||||
filter: none;
|
||||
}
|
||||
|
||||
.unselected {
|
||||
filter: grayscale(100%);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.iconDisabled {
|
||||
opacity: 0.15;
|
||||
}
|
||||
93
js/src/ui/SelectionList/selectionList.js
Normal file
93
js/src/ui/SelectionList/selectionList.js
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
|
||||
import { CheckIcon, StarIcon, StarOutlineIcon } from '~/ui/Icons';
|
||||
import SectionList from '~/ui/SectionList';
|
||||
import { arrayOrObjectProptype } from '~/util/proptypes';
|
||||
|
||||
import styles from './selectionList.css';
|
||||
|
||||
export default class SelectionList extends Component {
|
||||
static propTypes = {
|
||||
isChecked: PropTypes.func,
|
||||
items: arrayOrObjectProptype().isRequired,
|
||||
noStretch: PropTypes.bool,
|
||||
onDefaultClick: PropTypes.func,
|
||||
onSelectClick: PropTypes.func.isRequired,
|
||||
renderItem: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
render () {
|
||||
const { items, noStretch } = this.props;
|
||||
|
||||
return (
|
||||
<SectionList
|
||||
items={ items }
|
||||
noStretch={ noStretch }
|
||||
renderItem={ this.renderItem }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
renderItem = (item, index) => {
|
||||
const { isChecked, onDefaultClick, onSelectClick, renderItem } = this.props;
|
||||
const isSelected = isChecked
|
||||
? isChecked(item)
|
||||
: item.checked;
|
||||
|
||||
const makeDefault = () => {
|
||||
onDefaultClick(item);
|
||||
return false;
|
||||
};
|
||||
const selectItem = () => {
|
||||
onSelectClick(item);
|
||||
return false;
|
||||
};
|
||||
|
||||
let defaultIcon = null;
|
||||
|
||||
if (onDefaultClick) {
|
||||
defaultIcon = isSelected && item.default
|
||||
? <StarIcon />
|
||||
: <StarOutlineIcon className={ styles.iconDisabled } onClick={ makeDefault } />;
|
||||
}
|
||||
|
||||
const classes = isSelected
|
||||
? [styles.item, styles.selected]
|
||||
: [styles.item, styles.unselected];
|
||||
|
||||
return (
|
||||
<div className={ classes.join(' ') }>
|
||||
<div
|
||||
className={ styles.content }
|
||||
onClick={ selectItem }
|
||||
>
|
||||
{ renderItem(item, index) }
|
||||
</div>
|
||||
<div className={ styles.overlay }>
|
||||
{ defaultIcon }
|
||||
{
|
||||
isSelected
|
||||
? <CheckIcon onClick={ selectItem } />
|
||||
: <CheckIcon className={ styles.iconDisabled } onClick={ selectItem } />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
100
js/src/ui/SelectionList/selectionList.spec.js
Normal file
100
js/src/ui/SelectionList/selectionList.spec.js
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import SelectionList from './';
|
||||
|
||||
const ITEMS = ['A', 'B', 'C'];
|
||||
|
||||
let component;
|
||||
let instance;
|
||||
let renderItem;
|
||||
let onDefaultClick;
|
||||
let onSelectClick;
|
||||
|
||||
function render (props = {}) {
|
||||
renderItem = sinon.stub();
|
||||
onDefaultClick = sinon.stub();
|
||||
onSelectClick = sinon.stub();
|
||||
|
||||
component = shallow(
|
||||
<SelectionList
|
||||
items={ ITEMS }
|
||||
noStretch='testNoStretch'
|
||||
onDefaultClick={ onDefaultClick }
|
||||
onSelectClick={ onSelectClick }
|
||||
renderItem={ renderItem }
|
||||
/>
|
||||
);
|
||||
instance = component.instance();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
describe('ui/SelectionList', () => {
|
||||
beforeEach(() => {
|
||||
render();
|
||||
});
|
||||
|
||||
it('renders defaults', () => {
|
||||
expect(component).to.be.ok;
|
||||
});
|
||||
|
||||
describe('SectionList', () => {
|
||||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = component.find('SectionList');
|
||||
});
|
||||
|
||||
it('renders the SectionList', () => {
|
||||
expect(section.get(0)).to.be.ok;
|
||||
});
|
||||
|
||||
it('passes the items through', () => {
|
||||
expect(section.props().items).to.deep.equal(ITEMS);
|
||||
});
|
||||
|
||||
it('passes internal render method', () => {
|
||||
expect(section.props().renderItem).to.equal(instance.renderItem);
|
||||
});
|
||||
|
||||
it('passes noStretch prop through', () => {
|
||||
expect(section.props().noStretch).to.equal('testNoStretch');
|
||||
});
|
||||
});
|
||||
|
||||
describe('instance methods', () => {
|
||||
describe('renderItem', () => {
|
||||
let result;
|
||||
|
||||
beforeEach(() => {
|
||||
result = instance.renderItem('testItem', 'testIndex');
|
||||
});
|
||||
|
||||
it('renders', () => {
|
||||
expect(result).to.be.ok;
|
||||
});
|
||||
|
||||
it('calls into parent renderItem', () => {
|
||||
expect(renderItem).to.have.been.calledWith('testItem', 'testIndex');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -46,6 +46,7 @@ export ParityBackground from './ParityBackground';
|
||||
export Portal from './Portal';
|
||||
export QrCode from './QrCode';
|
||||
export SectionList from './SectionList';
|
||||
export SelectionList from './SelectionList';
|
||||
export ShortenedHash from './ShortenedHash';
|
||||
export SignerIcon from './SignerIcon';
|
||||
export Tags from './Tags';
|
||||
|
||||
Reference in New Issue
Block a user