dispatch/client/js/components/ui/Editable.js

112 lines
2.6 KiB
JavaScript
Raw Normal View History

import React, { PureComponent, createRef } from 'react';
2019-01-25 02:57:58 +00:00
import cn from 'classnames';
import { stringWidth } from 'utils';
export default class Editable extends PureComponent {
static defaultProps = {
editable: true
};
inputEl = createRef();
state = {
editing: false
};
componentDidUpdate(prevProps, prevState) {
if (!prevState.editing && this.state.editing) {
// eslint-disable-next-line react/no-did-update-set-state
2018-05-25 02:12:02 +00:00
this.updateInputWidth(this.props.value);
this.inputEl.current.focus();
2018-11-29 12:06:37 +00:00
} else if (this.state.editing && prevProps.value !== this.props.value) {
this.updateInputWidth(this.props.value);
}
}
2018-05-25 02:12:02 +00:00
updateInputWidth = value => {
if (this.inputEl.current) {
const style = window.getComputedStyle(this.inputEl.current);
2018-05-25 02:12:02 +00:00
const padding = parseInt(style.paddingRight, 10);
2018-06-18 13:47:51 +00:00
// Make sure the width is at least 1px so the caret always shows
2018-05-06 19:36:05 +00:00
const width =
stringWidth(value, `${style.fontSize} ${style.fontFamily}`) || 1;
2018-05-25 02:12:02 +00:00
this.setState({
width: width + padding * 2,
indent: padding
});
}
2018-05-25 02:12:02 +00:00
};
startEditing = () => {
if (this.props.editable) {
this.initialValue = this.props.value;
this.setState({ editing: true });
}
};
stopEditing = () => {
const { validate, value, onChange } = this.props;
if (validate && !validate(value)) {
onChange(this.initialValue);
}
this.setState({ editing: false });
};
handleBlur = e => {
const { onBlur } = this.props;
this.stopEditing();
if (onBlur) {
onBlur(e.target.value);
}
};
handleChange = e => this.props.onChange(e.target.value);
handleKey = e => {
if (e.key === 'Enter') {
this.handleBlur(e);
}
};
2018-05-06 19:36:05 +00:00
handleFocus = e => {
const val = e.target.value;
e.target.value = '';
e.target.value = val;
};
render() {
2019-01-25 02:57:58 +00:00
const { children, className, editable, value } = this.props;
const style = {
2018-05-25 02:12:02 +00:00
width: this.state.width,
textIndent: this.state.indent,
paddingLeft: 0
};
2018-04-05 23:46:22 +00:00
return this.state.editing ? (
<input
ref={this.inputEl}
2019-01-25 02:57:58 +00:00
className={`editable-wrap ${className}`}
2018-04-05 23:46:22 +00:00
type="text"
value={value}
onBlur={this.handleBlur}
onChange={this.handleChange}
onKeyDown={this.handleKey}
2018-05-06 19:36:05 +00:00
onFocus={this.handleFocus}
2018-04-05 23:46:22 +00:00
style={style}
spellCheck={false}
/>
) : (
2019-01-25 02:57:58 +00:00
<div
className={cn('editable-wrap', {
'editable-wrap-editable': editable
})}
onClick={this.startEditing}
>
{children}
</div>
);
}
}