From 665998e7979fe7b19d4ef2752da8fc034d2d3674 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 16 May 2017 12:25:47 +0200 Subject: [PATCH] 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 --- js/src/ui/Form/Input/input.css | 10 +- js/src/ui/Form/Input/input.js | 113 +++------ js/src/ui/Form/InputChip/Chip/chip.css | 49 ++++ js/src/ui/Form/InputChip/Chip/chip.js | 49 ++++ js/src/ui/Form/InputChip/Chip/index.js | 17 ++ js/src/ui/Form/InputChip/inputChip.js | 222 +++++++----------- js/src/ui/Form/Slider/index.js | 17 ++ .../inputChip.css => Slider/slider.css} | 10 +- js/src/ui/Form/Slider/slider.js | 44 ++++ .../ui/GasPriceSelector/gasPriceSelector.css | 5 +- .../ui/GasPriceSelector/gasPriceSelector.js | 16 +- js/src/ui/index.js | 2 +- js/src/ui/package.json | 1 - js/src/views/Account/EditMeta/store.js | 2 +- js/webpack/rules/es6.js | 2 +- js/webpack/vendor.js | 1 - 16 files changed, 317 insertions(+), 243 deletions(-) create mode 100644 js/src/ui/Form/InputChip/Chip/chip.css create mode 100644 js/src/ui/Form/InputChip/Chip/chip.js create mode 100644 js/src/ui/Form/InputChip/Chip/index.js create mode 100644 js/src/ui/Form/Slider/index.js rename js/src/ui/Form/{InputChip/inputChip.css => Slider/slider.css} (80%) create mode 100644 js/src/ui/Form/Slider/slider.js diff --git a/js/src/ui/Form/Input/input.css b/js/src/ui/Form/Input/input.css index be8a6ec0a..167a0cfbe 100644 --- a/js/src/ui/Form/Input/input.css +++ b/js/src/ui/Form/Input/input.css @@ -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; + } +} diff --git a/js/src/ui/Form/Input/input.js b/js/src/ui/Form/Input/input.js index 497f7ebc0..57b7512a2 100644 --- a/js/src/ui/Form/Input/input.js +++ b/js/src/ui/Form/Input/input.js @@ -15,36 +15,18 @@ // along with Parity. If not, see . 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 ( -
- { this.renderCopyButton() } - + + { this.renderCopyButton() } + { children } - -
+ + ); } 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 ( -
+
); } - onChange = (event, value) => { + onChange = (event, { value }) => { event.persist(); this.setValue(value, () => { diff --git a/js/src/ui/Form/InputChip/Chip/chip.css b/js/src/ui/Form/InputChip/Chip/chip.css new file mode 100644 index 000000000..7afbc64c5 --- /dev/null +++ b/js/src/ui/Form/InputChip/Chip/chip.css @@ -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 . +*/ + +$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; + } +} diff --git a/js/src/ui/Form/InputChip/Chip/chip.js b/js/src/ui/Form/InputChip/Chip/chip.js new file mode 100644 index 000000000..dd5c1b3da --- /dev/null +++ b/js/src/ui/Form/InputChip/Chip/chip.js @@ -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 . + +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 ( +
+
+ { label } +
+ +
+ ); +} + +Chip.propTypes = { + className: PropTypes.string, + isDisabled: PropTypes.bool, + isFocused: PropTypes.bool, + label: nodeOrStringProptype(), + onClick: PropTypes.func, + onDelete: PropTypes.func +}; diff --git a/js/src/ui/Form/InputChip/Chip/index.js b/js/src/ui/Form/InputChip/Chip/index.js new file mode 100644 index 000000000..2ce753c5f --- /dev/null +++ b/js/src/ui/Form/InputChip/Chip/index.js @@ -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 . + +export default from './chip'; diff --git a/js/src/ui/Form/InputChip/inputChip.js b/js/src/ui/Form/InputChip/inputChip.js index ed039f4bc..864dffe9c 100644 --- a/js/src/ui/Form/InputChip/inputChip.js +++ b/js/src/ui/Form/InputChip/inputChip.js @@ -15,16 +15,22 @@ // along with Parity. If not, see . 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 ( - + + + +
+ { tokens.map(this.renderChip) } +
+ + ); + } - 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 ( + ); } chipRenderer = (state, key) => { - const { value, isFocused, isDisabled, handleClick, handleRequestDelete } = state; + const { isDisabled, isFocused, handleClick, handleRequestDelete, value } = state; return ( - { value } - + 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; + } } } diff --git a/js/src/ui/Form/Slider/index.js b/js/src/ui/Form/Slider/index.js new file mode 100644 index 000000000..f97b28506 --- /dev/null +++ b/js/src/ui/Form/Slider/index.js @@ -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 . + +export default from './slider'; diff --git a/js/src/ui/Form/InputChip/inputChip.css b/js/src/ui/Form/Slider/slider.css similarity index 80% rename from js/src/ui/Form/InputChip/inputChip.css rename to js/src/ui/Form/Slider/slider.css index 599286698..732fe4d9a 100644 --- a/js/src/ui/Form/InputChip/inputChip.css +++ b/js/src/ui/Form/Slider/slider.css @@ -15,12 +15,6 @@ /* along with Parity. If not, see . */ -.chip { - & > svg { - width: 1rem !important; - height: 1rem !important; - margin: initial !important; - margin-right: 4px !important; - padding: 2px 0 !important; - } +.slider { + width: 100%; } diff --git a/js/src/ui/Form/Slider/slider.js b/js/src/ui/Form/Slider/slider.js new file mode 100644 index 000000000..3bc3c3456 --- /dev/null +++ b/js/src/ui/Form/Slider/slider.js @@ -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 . + +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 ( + + ); +} + +Slider.propTypes = { + className: PropTypes.string, + max: PropTypes.number, + min: PropTypes.number, + onChange: PropTypes.func, + step: PropTypes.number, + value: PropTypes.number +}; diff --git a/js/src/ui/GasPriceSelector/gasPriceSelector.css b/js/src/ui/GasPriceSelector/gasPriceSelector.css index a313be90c..2bc1b0ea2 100644 --- a/js/src/ui/GasPriceSelector/gasPriceSelector.css +++ b/js/src/ui/GasPriceSelector/gasPriceSelector.css @@ -27,5 +27,8 @@ } .chartRow { - margin-bottom: -24px; +} + +.slider { + margin-bottom: 1em; } diff --git a/js/src/ui/GasPriceSelector/gasPriceSelector.js b/js/src/ui/GasPriceSelector/gasPriceSelector.js index 588c4c7c2..da7f011ef 100644 --- a/js/src/ui/GasPriceSelector/gasPriceSelector.js +++ b/js/src/ui/GasPriceSelector/gasPriceSelector.js @@ -15,10 +15,11 @@ // along with Parity. If not, see . 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 (
); diff --git a/js/src/ui/index.js b/js/src/ui/index.js index b8c8747e4..9bd916f7e 100644 --- a/js/src/ui/index.js +++ b/js/src/ui/index.js @@ -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'; diff --git a/js/src/ui/package.json b/js/src/ui/package.json index efe13752c..3c6df8aa9 100644 --- a/js/src/ui/package.json +++ b/js/src/ui/package.json @@ -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", diff --git a/js/src/views/Account/EditMeta/store.js b/js/src/views/Account/EditMeta/store.js index 55e1d3633..e408fc7a1 100644 --- a/js/src/views/Account/EditMeta/store.js +++ b/js/src/views/Account/EditMeta/store.js @@ -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; }); } diff --git a/js/webpack/rules/es6.js b/js/webpack/rules/es6.js index 4e6edd2c9..8488472a0 100644 --- a/js/webpack/rules/es6.js +++ b/js/webpack/rules/es6.js @@ -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' }; diff --git a/js/webpack/vendor.js b/js/webpack/vendor.js index 4bee5cacd..897358a14 100644 --- a/js/webpack/vendor.js +++ b/js/webpack/vendor.js @@ -31,7 +31,6 @@ let modules = [ 'ethereumjs-tx', 'lodash', 'material-ui', - 'material-ui-chip-input', 'mobx', 'mobx-react', 'moment',