Ui 2 mui to sui conversion (#5633)

* Split chip rendering from input

* Slider component

* Render Chip without MUI

* Adjust InputChip styling

* Remove mui chip input

* Remove mui-chip-input from build

* Convert input to sui
This commit is contained in:
Jaco Greeff 2017-05-16 12:25:47 +02:00 committed by GitHub
parent c27d96a4f1
commit 665998e797
16 changed files with 317 additions and 243 deletions

View File

@ -16,12 +16,14 @@
*/
.container {
display: flex;
flex-direction: row;
align-items: baseline;
position: relative;
}
.copy {
margin-right: 0.5em;
}
.input {
input[readonly] {
cursor: text;
}
}

View File

@ -15,36 +15,18 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { TextField } from 'material-ui';
import { noop } from 'lodash';
import keycode from 'keycode';
import { Input as SemanticInput } from 'semantic-ui-react';
import { nodeOrStringProptype } from '@parity/shared/util/proptypes';
import { parseI18NString } from '@parity/shared/util/messages';
import CopyToClipboard from '~/ui/CopyToClipboard';
import LabelComponent from '~/ui/Form/LabelComponent';
import styles from './input.css';
// TODO: duplicated in Select
const UNDERLINE_DISABLED = {
borderBottom: 'dotted 2px',
borderColor: 'rgba(255, 255, 255, 0.125)' // 'transparent' // 'rgba(255, 255, 255, 0.298039)'
};
const UNDERLINE_READONLY = {
...UNDERLINE_DISABLED,
cursor: 'text'
};
const UNDERLINE_NORMAL = {
borderBottom: 'solid 2px'
};
const UNDERLINE_FOCUSED = {
transform: 'scaleX(1.0)'
};
const NAME_ID = ' ';
export default class Input extends Component {
@ -54,8 +36,8 @@ export default class Input extends Component {
static propTypes = {
allowCopy: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool
PropTypes.bool,
PropTypes.string
]),
autoFocus: PropTypes.bool,
children: PropTypes.node,
@ -70,11 +52,9 @@ export default class Input extends Component {
focused: PropTypes.bool,
readOnly: PropTypes.bool,
hint: nodeOrStringProptype(),
hideUnderline: PropTypes.bool,
label: nodeOrStringProptype(),
max: PropTypes.any,
min: PropTypes.any,
multiLine: PropTypes.bool,
onBlur: PropTypes.func,
onChange: PropTypes.func,
onClick: PropTypes.func,
@ -82,12 +62,11 @@ export default class Input extends Component {
onFocus: PropTypes.func,
onKeyDown: PropTypes.func,
onSubmit: PropTypes.func,
rows: PropTypes.number,
tabIndex: PropTypes.number,
type: PropTypes.string,
submitOnBlur: PropTypes.bool,
step: PropTypes.number,
style: PropTypes.object,
tabIndex: PropTypes.number,
type: PropTypes.string,
value: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
@ -98,13 +77,13 @@ export default class Input extends Component {
static defaultProps = {
allowCopy: false,
escape: 'initial',
hideUnderline: false,
onBlur: noop,
onFocus: noop,
onChange: noop,
readOnly: false,
submitOnBlur: true,
style: {}
style: {},
type: 'text'
}
state = {
@ -127,49 +106,25 @@ export default class Input extends Component {
}
}
// TODO: autoFocus not being used (yet)
// TODO: multiLine not part of the implementation (need TextArea input)
render () {
const { children, className, defaultValue, disabled, error, hint, label, max, min, onClick, readOnly, step, style, tabIndex, type } = this.props;
const { value } = this.state;
const { autoFocus, children, className, defaultValue, hideUnderline, disabled, error } = this.props;
const { focused, label, hint, onClick, multiLine, rows, type, min, max, step, style, tabIndex } = this.props;
const readOnly = this.props.readOnly || disabled;
const inputStyle = { overflow: 'hidden' };
const textFieldStyle = {};
if (readOnly) {
inputStyle.cursor = 'text';
}
if (hideUnderline && !hint) {
textFieldStyle.height = 'initial';
}
const underlineStyle = readOnly ? UNDERLINE_READONLY : UNDERLINE_NORMAL;
const underlineFocusStyle = focused
? UNDERLINE_FOCUSED
: readOnly && typeof focused !== 'boolean' ? { display: 'none' } : null;
const textValue = parseI18NString(this.context, value);
return (
<div className={ styles.container } style={ style }>
{ this.renderCopyButton() }
<TextField
autoComplete='off'
autoFocus={ autoFocus }
className={ className }
defaultValue={ defaultValue }
errorText={ error }
floatingLabelFixed
floatingLabelText={ label }
fullWidth
hintText={ hint }
<LabelComponent
className={ styles.container }
label={ label }
>
<SemanticInput
className={ `${styles.input} ${className}` }
disabled={ disabled }
error={ !!error }
fluid
id={ NAME_ID }
inputStyle={ inputStyle }
max={ max }
min={ min }
multiLine={ multiLine }
name={ NAME_ID }
onBlur={ this.onBlur }
onChange={ this.onChange }
@ -178,27 +133,25 @@ export default class Input extends Component {
onKeyUp={ this.onKeyUp }
onFocus={ this.onFocus }
onPaste={ this.onPaste }
placeholder={ parseI18NString(this.context, hint) }
readOnly={ readOnly }
ref='input'
rows={ rows }
step={ step }
style={ textFieldStyle }
style={ style }
tabIndex={ tabIndex }
type={ type || 'text' }
underlineDisabledStyle={ UNDERLINE_DISABLED }
underlineStyle={ underlineStyle }
underlineFocusStyle={ underlineFocusStyle }
underlineShow={ !hideUnderline }
value={ textValue }
type={ type }
value={ parseI18NString(this.context, value || defaultValue) }
>
{ this.renderCopyButton() }
<input />
{ children }
</TextField>
</div>
</SemanticInput>
</LabelComponent>
);
}
renderCopyButton () {
const { allowCopy, hideUnderline } = this.props;
const { allowCopy } = this.props;
const { value } = this.state;
if (!allowCopy) {
@ -209,18 +162,14 @@ export default class Input extends Component {
? allowCopy
: value.toString();
const style = hideUnderline
? {}
: { position: 'relative', top: '2px' };
return (
<div className={ styles.copy } style={ style }>
<div className={ styles.copy }>
<CopyToClipboard data={ text } />
</div>
);
}
onChange = (event, value) => {
onChange = (event, { value }) => {
event.persist();
this.setValue(value, () => {

View File

@ -0,0 +1,49 @@
/* 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/>.
*/
$bgNormal: rgba(50, 50, 50, 0.7);
$bgFocus: rgba(50, 50, 200, 0.7);
$bgDisabled: rgba(150, 150, 150, 0.7);
.chip {
background: $bgNormal;
border-radius: 1em;
color: white;
cursor: pointer;
display: inline-block;
margin: 0.5em 0.25em 0 0;
padding: 0.125em 0.25em;
&.disabled {
background: $bgDisabled;
}
&.focus {
background: $bgFocus;
}
.label {
display: inline-block;
padding: 0 1em;
font-size: 0.75em;
}
.delete {
border-radius: 1em;
font-size: 0.75em;
}
}

View File

@ -0,0 +1,49 @@
// 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, { PropTypes } from 'react';
import { nodeOrStringProptype } from '@parity/shared/util/proptypes';
import { CloseIcon } from '~/ui/Icons';
import styles from './chip.css';
export default function Chip ({ className, isDisabled, isFocused, label, onClick, onDelete }) {
return (
<div
className={ `${styles.chip} ${isDisabled && styles.disabled} ${isFocused && styles.focus} ${className}` }
onTouchTap={ onClick }
>
<div className={ styles.label }>
{ label }
</div>
<CloseIcon
className={ styles.delete }
onTouchTap={ onDelete }
/>
</div>
);
}
Chip.propTypes = {
className: PropTypes.string,
isDisabled: PropTypes.bool,
isFocused: PropTypes.bool,
label: nodeOrStringProptype(),
onClick: PropTypes.func,
onDelete: PropTypes.func
};

View 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 './chip';

View File

@ -15,16 +15,22 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import React, { Component, PropTypes } from 'react';
import { Chip } from 'material-ui';
import ChipInput from 'material-ui-chip-input';
import { blue300 } from 'material-ui/styles/colors';
import keycode from 'keycode';
import { uniq } from 'lodash';
import { Input as SemanticInput } from 'semantic-ui-react';
import { nodeOrStringProptype } from '@parity/shared/util/proptypes';
import { parseI18NString } from '@parity/shared/util/messages';
import { arrayOrObjectProptype, nodeOrStringProptype } from '@parity/shared/util/proptypes';
import styles from './inputChip.css';
import LabelComponent from '~/ui/Form/LabelComponent';
import Chip from './Chip';
export default class InputChip extends Component {
static contextTypes = {
intl: PropTypes.object
};
static propTypes = {
addOnBlur: PropTypes.bool,
clearOnBlur: PropTypes.bool,
@ -32,175 +38,125 @@ export default class InputChip extends Component {
hint: nodeOrStringProptype(),
label: nodeOrStringProptype(),
onTokensChange: PropTypes.func,
onInputChange: PropTypes.func,
onBlur: PropTypes.func,
tokens: PropTypes.oneOfType([
PropTypes.array,
PropTypes.object
]).isRequired
}
tokens: arrayOrObjectProptype().isRequired
};
static defaultProps = {
clearOnBlur: false,
addOnBlur: false
}
};
state = {
focused: false
}
textValue: ''
};
render () {
const { clearOnBlur, className, hint, label, tokens } = this.props;
const { focused } = this.state;
const textFieldStyle = {
height: 55
};
if (!focused) {
textFieldStyle.width = 0;
}
const { className, hint, label, tokens } = this.props;
const { textValue } = this.state;
return (
<ChipInput
<LabelComponent
className={ className }
ref='chipInput'
label={ label }
>
<SemanticInput
fluid
onBlur={ this.onBlur }
onChange={ this.onChange }
onKeyDown={ this.onKeyDown }
placeholder={ parseI18NString(this.context, hint) }
ref='chipInput'
value={ textValue }
>
<input />
</SemanticInput>
<div>
{ tokens.map(this.renderChip) }
</div>
</LabelComponent>
);
}
value={ tokens }
clearOnBlur={ clearOnBlur }
floatingLabelText={ label }
hintText={ hint }
renderChip = (chip) => {
const onDelete = (event) => this.handleTokenDelete(chip);
chipRenderer={ this.chipRenderer }
onFocus={ this.handleFocus }
onBlur={ this.handleBlur }
onRequestAdd={ this.handleTokenAdd }
onRequestDelete={ this.handleTokenDelete }
onUpdateInput={ this.handleInputChange }
floatingLabelFixed
fullWidth
hintStyle={ {
bottom: 13,
left: 0,
transition: 'none'
} }
inputStyle={ {
marginBottom: 18,
width: 'initial'
} }
textFieldStyle={ textFieldStyle }
underlineStyle={ {
borderWidth: 2
} }
return (
<Chip
key={ chip }
label={ chip }
onDelete={ onDelete }
/>
);
}
chipRenderer = (state, key) => {
const { value, isFocused, isDisabled, handleClick, handleRequestDelete } = state;
const { isDisabled, isFocused, handleClick, handleRequestDelete, value } = state;
return (
<Chip
isDisabled={ isDisabled }
isFocused={ isFocused }
key={ key }
className={ styles.chip }
style={ {
margin: '15px 8px 0 0',
float: 'left',
pointerEvents: isDisabled ? 'none' : undefined,
alignItems: 'center'
} }
labelStyle={ {
paddingRight: 6,
fontSize: '0.9rem',
lineHeight: 'initial'
} }
backgroundColor={ isFocused ? blue300 : 'rgba(50, 50, 50, 0.73)' }
onTouchTap={ handleClick }
onRequestDelete={ handleRequestDelete }
>
{ value }
</Chip>
label={ value }
onClick={ handleClick }
onDelete={ handleRequestDelete }
/>
);
}
handleFocus = () => {
this.setState({ focused: true });
}
handleBlur = () => {
const { onBlur, addOnBlur } = this.props;
this.setState({ focused: false });
if (addOnBlur) {
const { inputValue } = this.refs.chipInput.state;
this.handleTokenAdd(inputValue);
}
if (typeof onBlur === 'function') {
onBlur();
}
}
handleTokenAdd = (value) => {
const { tokens, onInputChange } = this.props;
const { tokens } = this.props;
const newTokens = uniq([].concat(tokens, value));
this.handleTokensChange(newTokens);
if (value === this.refs.chipInput.state.inputValue) {
if (typeof onInputChange === 'function') {
onInputChange('');
}
this.refs.chipInput.setState({ inputValue: '' });
}
this.setState({ textValue: '' });
}
handleTokenDelete = (value) => {
const { tokens } = this.props;
const newTokens = uniq([]
.concat(tokens)
.filter(v => v !== value));
this.handleTokensChange(
uniq(
[]
.concat(tokens)
.filter((token) => token !== value)
)
);
this.handleTokensChange(newTokens);
this.focus();
}
focus = () => {
this.refs.chipInput.focus();
}
handleInputChange = (value) => {
const { onInputChange } = this.props;
const splitTokens = value.split(/[\s,;]/);
const inputValue = (splitTokens.length <= 1)
? value
: splitTokens.slice(-1)[0].trim();
this.refs.chipInput.setState({ inputValue });
if (splitTokens.length > 1) {
const tokensToAdd = splitTokens.slice(0, -1);
tokensToAdd.forEach(token => this.handleTokenAdd(token));
}
if (typeof onInputChange === 'function') {
onInputChange(inputValue);
}
}
handleTokensChange = (tokens) => {
const { onTokensChange } = this.props;
onTokensChange(tokens.filter(token => token && token.length > 0));
onTokensChange(tokens.filter((token) => token && token.length > 0));
}
onBlur = () => {
const { onBlur, addOnBlur } = this.props;
if (addOnBlur) {
const { textValue } = this.state;
this.handleTokenAdd(textValue);
}
onBlur && onBlur();
}
onChange = (event, data) => {
this.setState({ textValue: data.value.trim() });
}
onKeyDown = (event, data) => {
const { textValue } = this.state;
switch (keycode(event)) {
case 'enter':
case 'space':
this.handleTokenAdd(textValue);
break;
}
}
}

View 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 './slider';

View File

@ -15,12 +15,6 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.chip {
& > svg {
width: 1rem !important;
height: 1rem !important;
margin: initial !important;
margin-right: 4px !important;
padding: 2px 0 !important;
}
.slider {
width: 100%;
}

View File

@ -0,0 +1,44 @@
// 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, { PropTypes } from 'react';
import styles from './slider.css';
export default function Slider ({ className, max, min = 0, onChange, step = 1, value }) {
const _onChange = (event) => onChange && onChange(event, event.target.value);
return (
<input
className={ `${styles.slider} ${className}` }
max={ max }
min={ min }
onChange={ _onChange }
step={ step }
type='range'
value={ value }
/>
);
}
Slider.propTypes = {
className: PropTypes.string,
max: PropTypes.number,
min: PropTypes.number,
onChange: PropTypes.func,
step: PropTypes.number,
value: PropTypes.number
};

View File

@ -27,5 +27,8 @@
}
.chartRow {
margin-bottom: -24px;
}
.slider {
margin-bottom: 1em;
}

View File

@ -15,10 +15,11 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
import BigNumber from 'bignumber.js';
import { Slider } from 'material-ui';
import React, { Component, PropTypes } from 'react';
import { Bar, BarChart, ResponsiveContainer, Scatter, ScatterChart, Tooltip, XAxis, YAxis } from 'recharts';
import Slider from '~/ui/Form/Slider';
import CustomBar from './CustomBar';
import CustomCursor from './CustomCursor';
import CustomShape from './CustomShape';
@ -195,17 +196,12 @@ export default class GasPriceSelector extends Component {
return (
<div className={ styles.sliderRow }>
<Slider
min={ 0 }
max={ 1 }
className={ styles.slider }
min={ 0.0 }
max={ 1.0 }
step={ 0.01 }
value={ sliderValue }
onChange={ this.onEditpriceSlider }
style={ {
flex: 1,
padding: '0 0.3em'
} }
sliderStyle={ {
marginBottom: 12
} }
/>
</div>
);

View File

@ -33,7 +33,7 @@ export DappIcon from './DappIcon';
export DappLink from './DappLink';
export Errors from './Errors';
export Features, { FEATURES, FeaturesStore } from './Features';
export Form, { AddressSelect, Checkbox, DappUrlInput, Dropdown, FileSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputDate, InputInline, InputTime, Label, RadioButtons, Toggle, TypedInput, VaultSelect } from './Form';
export Form, { AddressSelect, Checkbox, DappUrlInput, Dropdown, FileSelect, FormWrap, Input, InputAddress, InputAddressSelect, InputChip, InputDate, InputInline, InputTime, Label, RadioButtons, Slider, Toggle, TypedInput, VaultSelect } from './Form';
export GasPriceEditor from './GasPriceEditor';
export GasPriceSelector from './GasPriceSelector';
export IconCache from './IconCache';

View File

@ -27,7 +27,6 @@
"keycode": "2.1.8",
"lodash": "4.17.2",
"material-ui": "0.16.5",
"material-ui-chip-input": "0.11.1",
"moment": "2.17.0",
"react-ace": "4.1.0",
"react-copy-to-clipboard": "4.2.3",

View File

@ -43,7 +43,7 @@ export default class Store {
this.description = this.meta.description || '';
this.passwordHint = this.meta.passwordHint || '';
this.tags = this.meta.tags && this.meta.tags.peek() || [];
this.tags = this.meta.tags && this.meta.tags.slice() || [];
this.vaultName = this.meta.vault;
});
}

View File

@ -16,6 +16,6 @@
module.exports = {
test: /\.js$/,
include: /node_modules\/(get-own-enumerable-property-symbols|material-chip-input|ethereumjs-tx|stringify-object)/,
include: /node_modules\/(get-own-enumerable-property-symbols|ethereumjs-tx|stringify-object)/,
use: 'babel-loader'
};

View File

@ -31,7 +31,6 @@ let modules = [
'ethereumjs-tx',
'lodash',
'material-ui',
'material-ui-chip-input',
'mobx',
'mobx-react',
'moment',