Add read-only inputs to UI plus Copy to Clipboard buttons (#3095)

* Adds readOnly prop to Input, convert disabled props to it (#3066)

* WIP

* Adds copy icon to readOnly Input (#3009)

* Added Copy to Clipboard buttons on the UI (#3009)

* copiable to allowCopy props #3095

* Padded copy icons (#3095)

* Fixed password width in account creation

* Copyable value in MethodDecoding
This commit is contained in:
Nicolas Gotchac
2016-11-02 17:25:34 +01:00
committed by Jaco Greeff
parent f3d4aa43f3
commit e4c75bde4c
23 changed files with 314 additions and 95 deletions

View File

@@ -15,7 +15,6 @@
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
*/
.byline {
color: #aaa;
overflow: hidden;
position: relative;
line-height: 1.2em;
@@ -24,6 +23,12 @@
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
color: #aaa;
* {
color: #aaa !important;
}
}
.title {

View File

@@ -24,7 +24,9 @@ export default class Title extends Component {
title: PropTypes.oneOfType([
PropTypes.string, PropTypes.node
]),
byline: PropTypes.string
byline: PropTypes.oneOfType([
PropTypes.string, PropTypes.node
])
}
state = {
@@ -34,15 +36,21 @@ export default class Title extends Component {
render () {
const { className, title, byline } = this.props;
const byLine = typeof byline === 'string'
? (
<span title={ byline }>
{ byline }
</span>
)
: byline;
return (
<div className={ className }>
<h3 className={ styles.title }>
{ title }
</h3>
<div className={ styles.byline }>
<span title={ byline }>
{ byline }
</span>
{ byLine }
</div>
</div>
);

View File

@@ -0,0 +1,31 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
.container {
display: flex;
flex-direction: row;
align-items: flex-end;
position: relative;
}
.copy {
margin-right: 0.5em;
svg {
transition: all .5s ease-in-out;
}
}

View File

@@ -16,11 +16,22 @@
import React, { Component, PropTypes } from 'react';
import { TextField } from 'material-ui';
import CopyToClipboard from 'react-copy-to-clipboard';
import CopyIcon from 'material-ui/svg-icons/content/content-copy';
import { TextField, IconButton } from 'material-ui';
import { lightWhite, fullWhite } from 'material-ui/styles/colors';
import styles from './input.css';
// TODO: duplicated in Select
const UNDERLINE_DISABLED = {
borderColor: 'rgba(255, 255, 255, 0.298039)' // 'transparent' // 'rgba(255, 255, 255, 0.298039)'
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 = {
@@ -34,6 +45,12 @@ export default class Input extends Component {
children: PropTypes.node,
className: PropTypes.string,
disabled: PropTypes.bool,
readOnly: PropTypes.bool,
allowCopy: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool
]),
floatCopy: PropTypes.bool,
error: PropTypes.string,
hint: PropTypes.string,
label: PropTypes.string,
@@ -45,17 +62,24 @@ export default class Input extends Component {
rows: PropTypes.number,
type: PropTypes.string,
submitOnBlur: PropTypes.bool,
hideUnderline: PropTypes.bool,
value: PropTypes.oneOfType([
PropTypes.number, PropTypes.string
])
}
};
static defaultProps = {
submitOnBlur: true
submitOnBlur: true,
readOnly: false,
allowCopy: false,
hideUnderline: false,
floatCopy: false
}
state = {
value: this.props.value || ''
value: this.props.value || '',
timeoutId: null,
copied: false
}
componentWillReceiveProps (newProps) {
@@ -64,36 +88,145 @@ export default class Input extends Component {
}
}
componentWillUnmount () {
const { timeoutId } = this.state;
if (timeoutId) {
window.clearTimeout(timeoutId);
}
}
render () {
const { value } = this.state;
const { children, className, disabled, error, label, hint, multiLine, rows, type } = this.props;
const { children, className, hideUnderline, disabled, error, label, hint, multiLine, rows, type } = 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';
}
return (
<TextField
autoComplete='off'
className={ className }
disabled={ disabled }
errorText={ error }
floatingLabelFixed
floatingLabelText={ label }
fullWidth
hintText={ hint }
multiLine={ multiLine }
name={ NAME_ID }
id={ NAME_ID }
rows={ rows }
type={ type || 'text' }
underlineDisabledStyle={ UNDERLINE_DISABLED }
underlineStyle={ UNDERLINE_NORMAL }
value={ value }
onBlur={ this.onBlur }
onChange={ this.onChange }
onKeyDown={ this.onKeyDown }>
{ children }
</TextField>
<div className={ styles.container }>
{ this.renderCopyButton() }
<TextField
autoComplete='off'
className={ className }
style={ textFieldStyle }
readOnly={ readOnly }
errorText={ error }
floatingLabelFixed
floatingLabelText={ label }
fullWidth
hintText={ hint }
multiLine={ multiLine }
name={ NAME_ID }
id={ NAME_ID }
rows={ rows }
type={ type || 'text' }
underlineDisabledStyle={ UNDERLINE_DISABLED }
underlineStyle={ readOnly ? UNDERLINE_READONLY : UNDERLINE_NORMAL }
underlineFocusStyle={ readOnly ? { display: 'none' } : null }
underlineShow={ !hideUnderline }
value={ value }
onBlur={ this.onBlur }
onChange={ this.onChange }
onKeyDown={ this.onKeyDown }
inputStyle={ inputStyle }
>
{ children }
</TextField>
</div>
);
}
renderCopyButton () {
const { allowCopy, hideUnderline, label, hint, floatCopy } = this.props;
const { copied, value } = this.state;
if (!allowCopy) {
return null;
}
const style = {
marginBottom: 13
};
const text = typeof allowCopy === 'string'
? allowCopy
: value;
const scale = copied ? 'scale(1.15)' : 'scale(1)';
if (hideUnderline && !label) {
style.marginBottom = 2;
} else if (label && !hint) {
style.marginBottom = 4;
} else if (label && hint) {
style.marginBottom = 10;
}
if (floatCopy) {
style.position = 'absolute';
style.left = -24;
style.bottom = style.marginBottom;
style.marginBottom = 0;
}
return (
<div className={ styles.copy } style={ style }>
<CopyToClipboard
onCopy={ this.handleCopy }
text={ text } >
<IconButton
tooltip={ `${copied ? 'Copied' : 'Copy'} to clipboard` }
tooltipPosition='bottom-right'
style={ {
width: 16,
height: 16,
padding: 0
} }
iconStyle={ {
width: 16,
height: 16,
transform: scale
} }
tooltipStyles={ {
top: 16
} }
>
<CopyIcon
color={ copied ? lightWhite : fullWhite }
/>
</IconButton>
</CopyToClipboard>
</div>
);
}
handleCopy = () => {
if (this.state.timeoutId) {
window.clearTimeout(this.state.timeoutId);
}
this.setState({ copied: true }, () => {
const timeoutId = window.setTimeout(() => {
this.setState({ copied: false });
}, 500);
this.setState({ timeoutId });
});
}
onChange = (event, value) => {
this.setValue(value);
@@ -130,8 +263,6 @@ export default class Input extends Component {
}
setValue (value) {
this.setState({
value
});
this.setState({ value });
}
}

View File

@@ -29,4 +29,5 @@
.icon {
position: absolute;
top: 35px;
left: 24px;
}

View File

@@ -60,7 +60,9 @@ class InputAddress extends Component {
error={ error }
value={ text && hasAccount ? account.name : value }
onChange={ this.handleInputChange }
onSubmit={ onSubmit } />
onSubmit={ onSubmit }
allowCopy={ disabled ? value : false }
/>
{ icon }
</div>
);

View File

@@ -268,7 +268,8 @@ class MethodDecoding extends Component {
default:
return (
<Input
disabled
readOnly
allowCopy
key={ index }
className={ styles.input }
value={ this.renderValue(input.value) }

View File

@@ -49,7 +49,6 @@ class Tooltips extends Component {
redirect (props = this.props) {
const { currentId } = props;
console.log('c', { currentId });
if (currentId !== undefined && currentId !== -1) {
const viewLink = '/accounts/';
this.context.router.push(viewLink);