Introduce InputClickToEdit component
Now is a decent time to make this pattern a component for easier re-use and consistencypull/2755/head
parent
0b89623db8
commit
4551f4ff2e
|
@ -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
|
|
@ -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';
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue