p5.js-web-editor/client/modules/IDE/components/EditableInput.jsx

108 lines
2.6 KiB
JavaScript

import PropTypes from 'prop-types';
import React from 'react';
import { withTranslation } from 'react-i18next';
import i18next from 'i18next';
import EditIcon from '../../../images/pencil.svg';
// TODO I think this needs a description prop so that it's accessible
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 hasValue = currentValue !== '';
const classes = `editable-input editable-input--${
isEditing ? 'is-editing' : 'is-not-editing'
} editable-input--${hasValue ? 'has-value' : 'has-placeholder'}`;
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}
aria-label={this.props.t('EditableInput.EditValue', { display: displayValue })}
>
<span>{displayValue}</span>
<EditIcon
className="editable-input__icon"
focusable="false"
aria-hidden="true"
/>
</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: i18next.t('EditableInput.EmptyPlaceholder'),
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, // eslint-disable-line
onChange: PropTypes.func.isRequired,
validate: PropTypes.func,
value: PropTypes.string,
t: PropTypes.func.isRequired
};
export default withTranslation()(EditableInput);