EditableInput component

This commit is contained in:
Andrew Nicolaou 2019-09-08 18:57:57 +02:00
parent dcf65c6f46
commit 1c97152533
3 changed files with 130 additions and 0 deletions

View file

@ -0,0 +1,92 @@
import PropTypes from 'prop-types';
import React from 'react';
import InlineSVG from 'react-inlinesvg';
const editIconUrl = require('../../../images/pencil.svg');
function EditIcon() {
return <InlineSVG className="editable-input__icon" src={editIconUrl} alt="Edit" />;
}
function EditableInput({
validate, value, emptyPlaceholder, InputComponent, inputProps, onChange
}) {
const [isEditing, setIsEditing] = React.useState(false);
const [currentValue, setCurrentValue] = React.useState(value || '');
const displayValue = currentValue || emptyPlaceholder;
const classes = `editable-input editable-input--${isEditing ? 'is-editing' : 'is-not-editing'}`;
const inputRef = React.createRef();
React.useEffect(() => {
if (isEditing) {
inputRef.current.focus();
}
}, [isEditing]);
function beginEditing() {
setIsEditing(true);
}
function doneEditing() {
setIsEditing(false);
const isValid = typeof validate === 'function' && validate(currentValue);
if (isValid) {
onChange(currentValue);
} else {
setCurrentValue(value);
}
}
function updateValue(event) {
setCurrentValue(event.target.value);
}
function checkForKeyAction(event) {
if (event.key === 'Enter') {
doneEditing();
}
}
return (
<span className={classes}>
<button className="editable-input__label" onClick={beginEditing}>
<span>{displayValue}</span>
<EditIcon />
</button>
<InputComponent
className="editable-input__input"
type="text"
{...inputProps}
disabled={!isEditing}
onBlur={doneEditing}
onChange={updateValue}
onKeyPress={checkForKeyAction}
ref={inputRef}
value={currentValue}
/>
</span >
);
}
EditableInput.defaultProps = {
emptyPlaceholder: 'No value',
InputComponent: 'input',
inputProps: {},
validate: () => true,
value: '',
};
EditableInput.propTypes = {
emptyPlaceholder: PropTypes.string,
InputComponent: PropTypes.elementType,
// eslint-disable-next-line react/forbid-prop-types
inputProps: PropTypes.object,
onChange: PropTypes.func.isRequired,
validate: PropTypes.func,
value: PropTypes.string,
};
export default EditableInput;

View file

@ -0,0 +1,37 @@
.editable-input {
height: 70%;
display: flex;
align-items: center;
}
.editable-input__label {
@include themify() {
color: getThemifyVariable('inactive-text-color');
&:hover {
color: getThemifyVariable('primary-text-color');
& .editable-input__icon path {
fill: getThemifyVariable('primary-text-color');
}
}
}
cursor: pointer;
line-height: #{18 / $base-font-size}rem;
font-size: unset;
font-weight: unset;
}
.editable-input__icon svg {
width: 1.5rem;
height: 1.5rem;
}
.editable-input--is-not-editing .editable-input__input,
.editable-input--is-editing .editable-input__label {
display: none;
}
.editable-input--is-editing .editable-input__input,
.editable-input--is-not-editing .editable-input__label {
display: block;
}

View file

@ -47,6 +47,7 @@
@import 'components/uploader'; @import 'components/uploader';
@import 'components/tabs'; @import 'components/tabs';
@import 'components/dashboard-header'; @import 'components/dashboard-header';
@import 'components/editable-input';
@import 'layout/dashboard'; @import 'layout/dashboard';
@import 'layout/ide'; @import 'layout/ide';