diff --git a/js/src/modals/Transfer/transfer.css b/js/src/modals/Transfer/transfer.css
index 645f813f5..cd084a368 100644
--- a/js/src/modals/Transfer/transfer.css
+++ b/js/src/modals/Transfer/transfer.css
@@ -73,10 +73,6 @@
position: relative;
}
-.address input {
- padding-left: 48px !important;
-}
-
.from {
padding: 25px 0 0 48px !important;
line-height: 32px;
diff --git a/js/src/ui/Form/AddressSelect/addressSelect.css b/js/src/ui/Form/AddressSelect/addressSelect.css
index a5df06b97..af95c55f0 100644
--- a/js/src/ui/Form/AddressSelect/addressSelect.css
+++ b/js/src/ui/Form/AddressSelect/addressSelect.css
@@ -36,3 +36,13 @@
vertical-align: top;
text-transform: uppercase;
}
+
+.icon {
+ position: absolute;
+ left: 0;
+ top: 35px;
+}
+
+.paddedInput input {
+ padding-left: 46px !important;
+}
diff --git a/js/src/ui/Form/AddressSelect/addressSelect.js b/js/src/ui/Form/AddressSelect/addressSelect.js
index 617d02481..9be422571 100644
--- a/js/src/ui/Form/AddressSelect/addressSelect.js
+++ b/js/src/ui/Form/AddressSelect/addressSelect.js
@@ -17,9 +17,9 @@
import React, { Component, PropTypes } from 'react';
import { MenuItem } from 'material-ui';
+import AutoComplete from '../AutoComplete';
import IdentityIcon from '../../IdentityIcon';
import IdentityName from '../../IdentityName';
-import Select from '../Select';
import styles from './addressSelect.css';
@@ -36,31 +36,66 @@ export default class AddressSelect extends Component {
onChange: PropTypes.func.isRequired
}
+ state = {
+ entries: {}
+ }
+
+ componentWillMount () {
+ const { accounts, contacts } = this.props;
+ const entries = Object.assign({}, accounts || {}, contacts || {});
+ this.setState({ entries });
+ }
+
+ componentWillReceiveProps (newProps) {
+ const { accounts, contacts } = newProps;
+ const entries = Object.assign({}, accounts || {}, contacts || {});
+ this.setState({ entries });
+ }
+
render () {
- const { disabled, error, hint, label, value } = this.props;
+ const { disabled, error, hint, label } = this.props;
+ const { entries } = this.state;
return (
-
+
+
+
+ { this.renderIdentityIcon() }
+
);
}
- renderSelectEntries () {
- const { accounts, contacts } = this.props;
- const entries = Object.values(Object.assign({}, accounts || {}, contacts || {}));
-
- if (!entries.length) {
+ renderIdentityIcon () {
+ if (this.props.error) {
return null;
}
- return entries.map(this.renderSelectEntry);
+ const { value } = this.props;
+
+ return (
+
+ );
+ }
+
+ renderItem = (entry) => {
+ return {
+ text: entry.address,
+ value: this.renderSelectEntry(entry)
+ };
}
renderSelectEntry = (entry) => {
@@ -89,7 +124,27 @@ export default class AddressSelect extends Component {
);
}
- onChange = (event, idx, value) => {
- this.props.onChange(event, value);
+ getSearchText () {
+ const { value } = this.props;
+ if (!value) return '';
+
+ const { entries } = this.state;
+ const entry = entries[value];
+ if (!entry) return '';
+
+ return entry.name ? entry.name.toUpperCase() : '';
+ }
+
+ handleFilter = (searchText, address) => {
+ const entry = this.state.entries[address];
+ const lowCaseSearch = searchText.toLowerCase();
+
+ return [ entry.name, entry.address ]
+ .some(text => text.toLowerCase().indexOf(lowCaseSearch) !== -1);
+ }
+
+ onChange = (entry) => {
+ const address = entry ? entry.address : '';
+ this.props.onChange(null, address);
}
}
diff --git a/js/src/ui/Form/AutoComplete/autocomplete.js b/js/src/ui/Form/AutoComplete/autocomplete.js
new file mode 100644
index 000000000..c5d405eaa
--- /dev/null
+++ b/js/src/ui/Form/AutoComplete/autocomplete.js
@@ -0,0 +1,95 @@
+// Copyright 2015, 2016 Ethcore (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 { MenuItem, AutoComplete as MUIAutoComplete } from 'material-ui';
+
+export default class AutoComplete extends Component {
+ static propTypes = {
+ onChange: PropTypes.func.isRequired,
+ disabled: PropTypes.bool,
+ label: PropTypes.string,
+ hint: PropTypes.string,
+ error: PropTypes.string,
+ value: PropTypes.string,
+ className: PropTypes.string,
+ filter: PropTypes.func,
+ renderItem: PropTypes.func,
+ entries: PropTypes.oneOfType([
+ PropTypes.array,
+ PropTypes.object
+ ])
+ }
+
+ render () {
+ const { disabled, error, hint, label, value, className, filter } = this.props;
+
+ return (
+
+ );
+ }
+
+ getDataSource () {
+ const { renderItem, entries } = this.props;
+ const entriesArray = (entries instanceof Array)
+ ? entries
+ : Object.values(entries);
+
+ if (renderItem && typeof renderItem === 'function') {
+ return entriesArray.map(entry => renderItem(entry));
+ }
+
+ return entriesArray.map(entry => ({
+ text: entry,
+ value: (
+
+ )
+ }));
+ }
+
+ onChange = (item, idx) => {
+ const { onChange, entries } = this.props;
+ const entriesArray = (entries instanceof Array)
+ ? entries
+ : Object.values(entries);
+
+ const entry = (idx === -1) ? null : entriesArray[idx];
+
+ onChange(entry);
+ }
+
+ onFocus = () => {
+ this.props.onChange(null);
+ }
+
+}
diff --git a/js/src/ui/Form/AutoComplete/index.js b/js/src/ui/Form/AutoComplete/index.js
new file mode 100644
index 000000000..509a99444
--- /dev/null
+++ b/js/src/ui/Form/AutoComplete/index.js
@@ -0,0 +1,17 @@
+// Copyright 2015, 2016 Ethcore (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 .
+
+export default from './autocomplete';
diff --git a/js/src/ui/Form/InputAddress/inputAddress.css b/js/src/ui/Form/InputAddress/inputAddress.css
index d3ac9678e..2f65476dc 100644
--- a/js/src/ui/Form/InputAddress/inputAddress.css
+++ b/js/src/ui/Form/InputAddress/inputAddress.css
@@ -22,6 +22,10 @@
padding-left: 48px !important;
}
+.inputEmpty input {
+ padding-left: 0 !important;
+}
+
.icon {
position: absolute;
top: 35px;
diff --git a/js/src/ui/Form/InputAddress/inputAddress.js b/js/src/ui/Form/InputAddress/inputAddress.js
index 37025c1c8..c3e2bb4ab 100644
--- a/js/src/ui/Form/InputAddress/inputAddress.js
+++ b/js/src/ui/Form/InputAddress/inputAddress.js
@@ -38,22 +38,40 @@ class InputAddress extends Component {
onSubmit: PropTypes.func
};
+ state = {
+ isEmpty: false
+ }
+
+ componentWillMount () {
+ const { value, text, accountsInfo, tokens } = this.props;
+ const account = accountsInfo[value] || tokens[value];
+ const hasAccount = account && !account.meta.deleted;
+ const inputValue = text && hasAccount ? account.name : value;
+ const isEmpty = (inputValue.length === 0);
+
+ this.setState({ isEmpty });
+ }
+
render () {
- const { className, disabled, error, label, hint, value, text, onChange, onSubmit, accountsInfo, tokens } = this.props;
- const classes = `${styles.input} ${className}`;
+ const { className, disabled, error, label, hint, value, text, onSubmit, accountsInfo, tokens } = this.props;
+ const { isEmpty } = this.state;
+
+ const classes = [ className ];
+ classes.push(isEmpty ? styles.inputEmpty : styles.input);
+
const account = accountsInfo[value] || tokens[value];
const hasAccount = account && !account.meta.deleted;
return (
{ this.renderIcon() }
@@ -75,6 +93,13 @@ class InputAddress extends Component {
);
}
+
+ handleInputChange = (event, value) => {
+ const isEmpty = (value.length === 0);
+
+ this.setState({ isEmpty });
+ this.props.onChange(event, value);
+ }
}
function mapStateToProps (state) {