Select Git revision
TextEditor.js 3.72 KiB
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Editor, EditorState, RichUtils } from 'draft-js';
import ToggleButton from '@material-ui/lab/ToggleButton';
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup';
import BoldIcon from '@material-ui/icons/FormatBold';
import ItalicIcon from '@material-ui/icons/FormatItalic';
import { withStyles } from '@material-ui/core/styles';
import { stateToHTML } from 'draft-js-export-html';
import { stateFromHTML } from 'draft-js-import-html';
/** */
class TextEditor extends Component {
/** */
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createWithContent(stateFromHTML(props.annoHtml)),
};
this.onChange = this.onChange.bind(this);
this.handleKeyCommand = this.handleKeyCommand.bind(this);
this.handleFormating = this.handleFormating.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.editorRef = React.createRef();
}
/**
* This is a kinda silly hack (but apparently recommended approach) to
* making sure the whole visible editor area is clickable, not just the first line.
*/
handleFocus() {
if (this.editorRef.current) this.editorRef.current.focus();
}
/** */
handleFormating(e, newFormat) {
const { editorState } = this.state;
this.onChange(RichUtils.toggleInlineStyle(editorState, newFormat));
}
/** */
handleKeyCommand(command, editorState) {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onChange(newState);
return 'handled';
}
return 'not-handled';
}
/** */
onChange(editorState) {
const { updateAnnotationBody } = this.props;
this.setState({ editorState });
if (updateAnnotationBody) {
const options = {
inlineStyles: {
BOLD: { element: 'b' },
ITALIC: { element: 'i' },
},
};
updateAnnotationBody(stateToHTML(editorState.getCurrentContent(), options).toString());
}
}
/** */
render() {
const { classes } = this.props;
const { editorState } = this.state;
const currentStyle = editorState.getCurrentInlineStyle();
return (
<div>
<div className={classes.editorRoot} onClick={this.handleFocus}>
<Editor
editorState={editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onChange}
ref={this.editorRef}
/>
</div>
<ToggleButtonGroup
size="small"
value={currentStyle.toArray()}
>
<ToggleButton
onClick={this.handleFormating}
value="BOLD"
>
<BoldIcon/>
</ToggleButton>
<ToggleButton
onClick={this.handleFormating}
value="ITALIC"
>
<ItalicIcon/>
</ToggleButton>
</ToggleButtonGroup>
</div>
);
}
}
/** */
const styles = (theme) => ({
editorRoot: {
borderColor: theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)',
borderRadius: theme.shape.borderRadius,
borderStyle: 'solid',
borderWidth: 1,
fontFamily: theme.typography.fontFamily,
marginBottom: theme.spacing(1),
marginTop: theme.spacing(1),
minHeight: theme.typography.fontSize * 6,
padding: theme.spacing(1),
},
});
TextEditor.propTypes = {
annoHtml: PropTypes.string,
classes: PropTypes.shape({
editorRoot: PropTypes.string,
}).isRequired,
updateAnnotationBody: PropTypes.func,
};
TextEditor.defaultProps = {
annoHtml: '',
updateAnnotationBody: () => {},
};
export default withStyles(styles)(TextEditor);