diff --git a/js/src/ui/Form/AddressSelect/addressSelect.css b/js/src/ui/Form/AddressSelect/addressSelect.css
index 839c025b5..84afbd15a 100644
--- a/js/src/ui/Form/AddressSelect/addressSelect.css
+++ b/js/src/ui/Form/AddressSelect/addressSelect.css
@@ -146,4 +146,8 @@
margin: 1em 0;
}
+
+ .account {
+ margin: 0.5em 0;
+ }
}
diff --git a/js/src/ui/Form/AddressSelect/addressSelect.js b/js/src/ui/Form/AddressSelect/addressSelect.js
index 2f47484b2..07c133d7c 100644
--- a/js/src/ui/Form/AddressSelect/addressSelect.js
+++ b/js/src/ui/Form/AddressSelect/addressSelect.js
@@ -346,6 +346,7 @@ class AddressSelect extends Component {
.
+
+export default from './selectionList';
diff --git a/js/src/modals/VaultAccounts/vaultAccounts.css b/js/src/ui/SelectionList/selectionList.css
similarity index 75%
rename from js/src/modals/VaultAccounts/vaultAccounts.css
rename to js/src/ui/SelectionList/selectionList.css
index 1960376f3..eee61dbb5 100644
--- a/js/src/modals/VaultAccounts/vaultAccounts.css
+++ b/js/src/ui/SelectionList/selectionList.css
@@ -15,16 +15,25 @@
/* along with Parity. If not, see
.
*/
-/* TODO: These overlap with DappPermissions now, make DRY */
-/* (selection component or just styles?) */
-.iconDisabled {
- opacity: 0.15;
-}
-
.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;
@@ -33,16 +42,16 @@
}
}
-.selected,
-.unselected {
- margin-bottom: 0.25em;
- width: 100%;
-
- &:focus {
- outline: none;
- }
-}
-
.selected {
- background: rgba(255, 255, 255, 0.15) !important;
+ box-shadow: inset 0 0 0 2px rgb(255, 255, 255);
+ filter: none;
+}
+
+.unselected {
+ filter: grayscale(100%);
+ opacity: 0.5;
+}
+
+.iconDisabled {
+ opacity: 0.15;
}
diff --git a/js/src/ui/SelectionList/selectionList.js b/js/src/ui/SelectionList/selectionList.js
new file mode 100644
index 000000000..2293cf9c3
--- /dev/null
+++ b/js/src/ui/SelectionList/selectionList.js
@@ -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
.
+
+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 (
+
+ );
+ }
+
+ 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
+ ?
+ :
;
+ }
+
+ const classes = isSelected
+ ? [styles.item, styles.selected]
+ : [styles.item, styles.unselected];
+
+ return (
+
+
+ { renderItem(item, index) }
+
+
+ { defaultIcon }
+ {
+ isSelected
+ ?
+ :
+ }
+
+
+ );
+ }
+}
diff --git a/js/src/ui/SelectionList/selectionList.spec.js b/js/src/ui/SelectionList/selectionList.spec.js
new file mode 100644
index 000000000..4dfaed396
--- /dev/null
+++ b/js/src/ui/SelectionList/selectionList.spec.js
@@ -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
.
+
+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(
+
+ );
+ 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');
+ });
+ });
+ });
+});
diff --git a/js/src/ui/index.js b/js/src/ui/index.js
index 54d7ba5b8..db640b1a5 100644
--- a/js/src/ui/index.js
+++ b/js/src/ui/index.js
@@ -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';
diff --git a/js/src/views/ParityBar/accountStore.js b/js/src/views/ParityBar/accountStore.js
index 4c2736864..f13881df0 100644
--- a/js/src/views/ParityBar/accountStore.js
+++ b/js/src/views/ParityBar/accountStore.js
@@ -37,7 +37,7 @@ export default class AccountStore {
@action setDefaultAccount = (defaultAccount) => {
transaction(() => {
this.accounts = this.accounts.map((account) => {
- account.default = account.address === defaultAccount;
+ account.checked = account.address === defaultAccount;
return account;
});
@@ -90,7 +90,7 @@ export default class AccountStore {
const account = accounts[address];
account.address = address;
- account.default = address === this.defaultAccount;
+ account.checked = address === this.defaultAccount;
return account;
})
diff --git a/js/src/views/ParityBar/parityBar.js b/js/src/views/ParityBar/parityBar.js
index 7f95cd6d5..3d34f430f 100644
--- a/js/src/views/ParityBar/parityBar.js
+++ b/js/src/views/ParityBar/parityBar.js
@@ -24,7 +24,7 @@ import { connect } from 'react-redux';
import store from 'store';
import imagesEthcoreBlock from '~/../assets/images/parity-logo-white-no-text.svg';
-import { AccountCard, Badge, Button, ContainerTitle, IdentityIcon, ParityBackground, SectionList } from '~/ui';
+import { AccountCard, Badge, Button, ContainerTitle, IdentityIcon, ParityBackground, SelectionList } from '~/ui';
import { CancelIcon, FingerprintIcon } from '~/ui/Icons';
import DappsStore from '~/views/Dapps/dappsStore';
import { Embedded as Signer } from '~/views/Signer';
@@ -328,10 +328,11 @@ class ParityBar extends Component {
{
displayType === DISPLAY_ACCOUNTS
? (
-
)
@@ -344,31 +345,23 @@ class ParityBar extends Component {
);
}
+ onMakeDefault = (account) => {
+ this.toggleAccountsDisplay();
+
+ return this.accountStore
+ .makeDefaultAccount(account.address)
+ .then(() => this.accountStore.loadAccounts());
+ }
+
renderAccount = (account) => {
const { balances } = this.props;
const balance = balances[account.address];
- const makeDefaultAccount = () => {
- this.toggleAccountsDisplay();
- return this.accountStore
- .makeDefaultAccount(account.address)
- .then(() => this.accountStore.loadAccounts());
- };
return (
-
+
);
}