Trigger accounts/contracts search on search input change (#2838)

* Styling Chips in search bar (#2766)

* Styling search chips // Add chip on space/comma/... (#2766)

* Update search on input (#2766)

* Fixing search triggers bugs (#2766)

* removed console logs

* Use props instead of weird CSS selectors for Search Bar

* Add tags on space and commas in EditMeta modal (#2766)

* Fixed empty input in EditMeta modal ; tokens input
This commit is contained in:
Nicolas Gotchac 2016-10-24 16:35:43 +02:00 committed by Gav Wood
parent 24fa2888ab
commit 487da9c9c6
6 changed files with 149 additions and 46 deletions

View File

@ -36,7 +36,7 @@ export default class EditMeta extends Component {
} }
state = { state = {
meta: this.props.account.meta, meta: Object.assign({}, this.props.account.meta),
metaErrors: {}, metaErrors: {},
name: this.props.account.name, name: this.props.account.name,
nameError: null nameError: null
@ -102,20 +102,55 @@ export default class EditMeta extends Component {
renderTags () { renderTags () {
const { meta } = this.state; const { meta } = this.state;
const { tags } = meta || []; const { tags } = meta || [];
const onChange = (chips) => this.onMetaChange('tags', chips);
return ( return (
<ChipInput <ChipInput
defaultValue={ tags } ref='tagsInput'
onChange={ onChange } value={ tags }
onRequestAdd={ this.onAddTag }
onRequestDelete={ this.onDeleteTag }
floatingLabelText='(optional) tags' floatingLabelText='(optional) tags'
hintText='press <Enter> to add a tag' hintText='press <Enter> to add a tag'
onUpdateInput={ this.onTagsInputChange }
floatingLabelFixed floatingLabelFixed
fullWidth fullWidth
/> />
); );
} }
onAddTag = (tag) => {
const { meta } = this.state;
const { tags } = meta || [];
this.onMetaChange('tags', [].concat(tags, tag));
}
onDeleteTag = (tag) => {
const { meta } = this.state;
const { tags } = meta || [];
const newTags = tags
.filter(t => t !== tag);
this.onMetaChange('tags', newTags);
}
onTagsInputChange = (value) => {
const { meta } = this.state;
const { tags } = meta || [];
const tokens = value.split(/[\s,;]+/);
const newTokens = tokens
.slice(0, -1)
.filter(t => t.length > 0);
const inputValue = tokens.slice(-1)[0].trim();
this.onMetaChange('tags', [].concat(tags, newTokens));
this.refs.tagsInput.setState({ inputValue });
}
onNameChange = (name) => { onNameChange = (name) => {
this.setState(validateName(name)); this.setState(validateName(name));
} }

View File

@ -41,3 +41,11 @@
width: 0; width: 0;
height: 0; height: 0;
} }
.chip > svg {
width: 1.2rem !important;
height: 1.2rem !important;
margin: initial !important;
margin-right: 4px !important;
padding: 4px 0 !important;
}

View File

@ -15,6 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import { Chip } from 'material-ui';
import { blue300 } from 'material-ui/styles/colors';
// import ChipInput from 'material-ui-chip-input'; // import ChipInput from 'material-ui-chip-input';
import ChipInput from 'material-ui-chip-input/src/ChipInput'; import ChipInput from 'material-ui-chip-input/src/ChipInput';
import ActionSearch from 'material-ui/svg-icons/action/search'; import ActionSearch from 'material-ui/svg-icons/action/search';
@ -43,6 +45,10 @@ export default class ActionbarSearch extends Component {
if (tokens.length > 0 && this.props.tokens.length === 0) { if (tokens.length > 0 && this.props.tokens.length === 0) {
this.handleOpenSearch(true, true); this.handleOpenSearch(true, true);
} }
if (tokens.length !== this.props.tokens.length) {
this.handleSearchChange(tokens);
}
} }
componentWillUnmount () { componentWillUnmount () {
@ -71,16 +77,26 @@ export default class ActionbarSearch extends Component {
<ChipInput <ChipInput
clearOnBlur={ false } clearOnBlur={ false }
className={ styles.input } className={ styles.input }
chipRenderer={ this.chipRenderer }
hintText='Enter search input...' hintText='Enter search input...'
hintStyle={ {
transition: 'none'
} }
ref='searchInput' ref='searchInput'
value={ tokens } value={ tokens }
onBlur={ this.handleSearchBlur } onBlur={ this.handleSearchBlur }
onRequestAdd={ this.handleTokenAdd } onRequestAdd={ this.handleTokenAdd }
onRequestDelete={ this.handleTokenDelete } onRequestDelete={ this.handleTokenDelete }
onUpdateInput={ this.handleInputChange } /> onUpdateInput={ this.handleInputChange }
hintStyle={ {
bottom: 16,
left: 2,
transition: 'none'
} }
inputStyle={ {
marginBottom: 18
} }
textFieldStyle={ {
height: 42
} }
/>
</div> </div>
<Button <Button
@ -92,42 +108,83 @@ export default class ActionbarSearch extends Component {
); );
} }
chipRenderer = (state, key) => {
const { value, isFocused, isDisabled, handleClick, handleRequestDelete } = state;
return (
<Chip
key={ key }
className={ styles.chip }
style={ {
margin: '8px 8px 0 0',
float: 'left',
pointerEvents: isDisabled ? 'none' : undefined,
alignItems: 'center'
} }
labelStyle={ {
paddingRight: 6,
fontSize: '0.9rem',
lineHeight: 'initial'
} }
backgroundColor={ isFocused ? blue300 : 'rgba(0, 0, 0, 0.73)' }
onTouchTap={ handleClick }
onRequestDelete={ handleRequestDelete }
>
{ value }
</Chip>
);
}
handleTokenAdd = (value) => { handleTokenAdd = (value) => {
const { tokens } = this.props; const { tokens } = this.props;
const newSearchValues = uniq([].concat(tokens, value)); const newSearchTokens = uniq([].concat(tokens, value));
this.setState({ this.handleSearchChange(newSearchTokens);
inputValue: ''
});
this.handleSearchChange(newSearchValues);
} }
handleTokenDelete = (value) => { handleTokenDelete = (value) => {
const { tokens } = this.props; const { tokens } = this.props;
const newSearchValues = [] const newSearchTokens = []
.concat(tokens) .concat(tokens)
.filter(v => v !== value); .filter(v => v !== value);
this.setState({ this.handleSearchChange(newSearchTokens);
inputValue: ''
});
this.handleSearchChange(newSearchValues);
this.refs.searchInput.focus(); this.refs.searchInput.focus();
} }
handleInputChange = (value) => { handleInputChange = (value) => {
this.setState({ inputValue: value }); const splitTokens = value.split(/[\s,;]/);
const inputValue = (splitTokens.length <= 1)
? value
: splitTokens.slice(-1)[0].trim();
this.refs.searchInput.setState({ inputValue });
this.setState({ inputValue }, () => {
if (splitTokens.length > 1) {
const tokensToAdd = splitTokens.slice(0, -1);
tokensToAdd.forEach(token => this.handleTokenAdd(token));
} else {
this.handleSearchChange();
}
});
} }
handleSearchChange = (searchValues) => { handleSearchChange = (searchTokens) => {
const { onChange } = this.props; const { onChange, tokens } = this.props;
const newSearchValues = searchValues.filter(v => v.length > 0); const { inputValue } = this.state;
onChange(newSearchValues); const newSearchTokens = []
.concat(searchTokens || tokens)
.filter(v => v.length > 0);
const newSearchValues = []
.concat(searchTokens || tokens, inputValue)
.filter(v => v.length > 0);
onChange(newSearchTokens, newSearchValues);
} }
handleSearchClick = () => { handleSearchClick = () => {

View File

@ -41,7 +41,8 @@ class Accounts extends Component {
addressBook: false, addressBook: false,
newDialog: false, newDialog: false,
sortOrder: '', sortOrder: '',
searchValues: [] searchValues: [],
searchTokens: []
} }
render () { render () {
@ -69,14 +70,14 @@ class Accounts extends Component {
} }
renderSearchButton () { renderSearchButton () {
const onChange = (searchValues) => { const onChange = (searchTokens, searchValues) => {
this.setState({ searchValues }); this.setState({ searchTokens, searchValues });
}; };
return ( return (
<ActionbarSearch <ActionbarSearch
key='searchAccount' key='searchAccount'
tokens={ this.state.searchValues } tokens={ this.state.searchTokens }
onChange={ onChange } /> onChange={ onChange } />
); );
} }
@ -136,9 +137,9 @@ class Accounts extends Component {
} }
onAddSearchToken = (token) => { onAddSearchToken = (token) => {
const { searchValues } = this.state; const { searchTokens } = this.state;
const newSearchValues = uniq([].concat(searchValues, token)); const newSearchTokens = uniq([].concat(searchTokens, token));
this.setState({ searchValues: newSearchValues }); this.setState({ searchTokens: newSearchTokens });
} }
onNewAccountClick = () => { onNewAccountClick = () => {

View File

@ -40,7 +40,8 @@ class Addresses extends Component {
state = { state = {
showAdd: false, showAdd: false,
sortOrder: '', sortOrder: '',
searchValues: [] searchValues: [],
searchTokens: []
} }
render () { render () {
@ -79,14 +80,14 @@ class Addresses extends Component {
} }
renderSearchButton () { renderSearchButton () {
const onChange = (searchValues) => { const onChange = (searchTokens, searchValues) => {
this.setState({ searchValues }); this.setState({ searchTokens, searchValues });
}; };
return ( return (
<ActionbarSearch <ActionbarSearch
key='searchAddress' key='searchAddress'
tokens={ this.state.searchValues } tokens={ this.state.searchTokens }
onChange={ onChange } /> onChange={ onChange } />
); );
} }
@ -127,9 +128,9 @@ class Addresses extends Component {
} }
onAddSearchToken = (token) => { onAddSearchToken = (token) => {
const { searchValues } = this.state; const { searchTokens } = this.state;
const newSearchValues = uniq([].concat(searchValues, token)); const newSearchTokens = uniq([].concat(searchTokens, token));
this.setState({ searchValues: newSearchValues }); this.setState({ searchTokens: newSearchTokens });
} }
onOpenAdd = () => { onOpenAdd = () => {

View File

@ -43,7 +43,8 @@ class Contracts extends Component {
addContract: false, addContract: false,
deployContract: false, deployContract: false,
sortOrder: '', sortOrder: '',
searchValues: [] searchValues: [],
searchTokens: []
} }
render () { render () {
@ -84,14 +85,14 @@ class Contracts extends Component {
} }
renderSearchButton () { renderSearchButton () {
const onChange = (searchValues) => { const onChange = (searchTokens, searchValues) => {
this.setState({ searchValues }); this.setState({ searchTokens, searchValues });
}; };
return ( return (
<ActionbarSearch <ActionbarSearch
key='searchContract' key='searchContract'
tokens={ this.state.searchValues } tokens={ this.state.searchTokens }
onChange={ onChange } /> onChange={ onChange } />
); );
} }
@ -152,9 +153,9 @@ class Contracts extends Component {
} }
onAddSearchToken = (token) => { onAddSearchToken = (token) => {
const { searchValues } = this.state; const { searchTokens } = this.state;
const newSearchValues = uniq([].concat(searchValues, token)); const newSearchTokens = uniq([].concat(searchTokens, token));
this.setState({ searchValues: newSearchValues }); this.setState({ searchTokens: newSearchTokens });
} }
onDeployContractClose = () => { onDeployContractClose = () => {