Introduce InputClickToEdit component

Now is a decent time to make this pattern a component for easier re-use
and consistency
pull/2755/head
Alex P 2017-11-09 18:35:01 -08:00 committed by Jared Scheib
parent 0b89623db8
commit 4551f4ff2e
3 changed files with 136 additions and 0 deletions

View File

@ -0,0 +1,82 @@
import React, {Component, PropTypes} from 'react'
class InputClickToEdit extends Component {
constructor(props) {
super(props)
this.state = {
reset: false,
isEditing: null,
value: this.props.value,
}
}
handleInputClick = () => {
this.setState({isEditing: true})
}
handleInputBlur = reset => e => {
const {onUpdate, value} = this.props
if (!reset && value !== e.target.value) {
onUpdate(e.target.value)
}
this.setState({reset: false, isEditing: false})
}
handleKeyDown = e => {
if (e.key === 'Enter') {
this.inputRef.blur()
}
if (e.key === 'Escape') {
this.setState({reset: true, value: this.props.value}, () =>
this.inputRef.blur()
)
}
}
handleFocus = e => {
e.target.select()
}
render() {
const {reset, isEditing, value} = this.state
const {wrapperClass, disabled} = this.props
return disabled
? <div className={wrapperClass}>
<div className="input-cte__disabled">
{value}
</div>
</div>
: <div className={wrapperClass}>
{isEditing
? <input
type="text"
className="form-control input-sm provider--input"
defaultValue={value}
onBlur={this.handleInputBlur(reset)}
onKeyDown={this.handleKeyDown}
autoFocus={true}
onFocus={this.handleFocus}
ref={r => (this.inputRef = r)}
/>
: <div className="input-cte" onClick={this.handleInputClick}>
{value}
<span className="icon pencil" />
</div>}
</div>
}
}
const {func, bool, string} = PropTypes
InputClickToEdit.propTypes = {
wrapperClass: string.isRequired,
value: string,
onUpdate: func.isRequired,
disabled: bool,
}
export default InputClickToEdit

View File

@ -39,6 +39,7 @@
@import 'components/function-selector';
@import 'components/graph-tips';
@import 'components/graph';
@import 'components/input-click-to-edit';
@import 'components/input-tag-list';
@import 'components/newsfeed';
@import 'components/opt-in';

View File

@ -0,0 +1,53 @@
/*
Click to Edit Input Styles
------------------------------------------------------------------------------
*/
.input-cte,
.input-cte__disabled {
@include no-user-select();
height: 30px;
width: 100%;
font-weight: 600;
font-size: 13px;
line-height: 28px;
padding: 0 11px;
border-radius: 4px;
border-style: solid;
border-width: 2px;
}
.input-cte {
border-color: $g2-kevlar;
background-color: $g2-kevlar;
color: $g13-mist;
position: relative;
transition:
color 0.4s ease,
background-color 0.4s ease,
border-color 0.4s ease;
> span.icon {
position: absolute;
top: 50%;
right: 11px;
transform: translateY(-50%);
color: $g8-storm;
opacity: 0;
transition: opacity 0.25s ease;
}
&:hover {
color: $g20-white;
background-color: $g5-pepper;
border-color: $g5-pepper;
cursor: text;
> span.icon {opacity: 1;}
}
}
.input-cte__disabled {
border-color: $g4-onyx;
background-color: $g4-onyx;
font-style: italic;
color: $g9-mountain;
}