I’m making a rich text editor widget for netlifyCMS. I’ve already tried react-draftjs-wysiwyg but netlifyCMS doesn’t seem to be able to handle styling through classNames. So I figured I would try my hand at figuring out draftjs.
On the left is my draftJS rich text editor. And at the very top right is the draftjs-to-html conversion. As you can see, the first line is bold, so that works fine. So at least I know that I am handling state somewhat correctly.
When I change font size, the editor seems to be able to preview that properly. But when I take the editorState and convert it to html it loses the fontSize. When I log the editorState converted html it just comes out as a normal p tag with no fontSize styling.
Here is my custom netlifyCMS widget
import React, { Component } from "react"
import MarkdownContent from "../page-blocks/MarkdownContent"
import {Editor, EditorState,convertToRaw, RichUtils} from 'draft-js';
import draftToHtml from 'draftjs-to-html';
import 'draft-js/dist/Draft.css'
import createStyles from 'draft-js-custom-styles'
export class RichTextEditorControl extends Component {
constructor(props) {
super(props);
this.state = {
editorState: EditorState.createEmpty(),
isShowingFontSizeMenu: false,
};
// this.onChange = editorState => this.setState({editorState});
this.handleKeyCommand = this.handleKeyCommand.bind(this);
}
onEditorStateChange = (editorState) => {
this.setState({editorState});
this.props.onChange(editorState)
};
// allows user to ctrl+b, ctrl+i, etc...
handleKeyCommand(command, editorState) {
const newState = RichUtils.handleKeyCommand(editorState, command);
if (newState) {
this.onEditorStateChange(newState);
return 'handled';
}
return 'not-handled';
}
_onBoldClick (e) {
e.preventDefault()
this.onEditorStateChange(RichUtils.toggleInlineStyle(
this.state.editorState, 'BOLD'))
}
_onItalicClick (e) {
e.preventDefault()
this.onEditorStateChange(RichUtils.toggleInlineStyle(
this.state.editorState, 'ITALIC'))
}
_onFontDropDownClick (e) {
e.preventDefault();
this.state.isShowingFontSizeMenu = !this.state.isShowingFontSizeMenu
this.onEditorStateChange(this.state.editorState) //force re render to display drop down
}
_setFontSize(e, value, styles) {
e.preventDefault()
//remove current font size at selection
const newEditorState = styles.fontSize.remove(this.state.editorState)
//toggle dropdown
this.state.isShowingFontSizeMenu = !this.state.isShowingFontSizeMenu
//set editorState to display new font size
this.onEditorStateChange(styles.fontSize.add(newEditorState, value))
}
render() {
const {styles, customStyleFn} = createStyles(['font-size'])
//map array of integers to display options for dropdown
const fontSizes = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 38, 46, 54, 62, 72]
const fontSizeOptions = fontSizes.map(fontSize => (
<div
key={`font-size-${fontSize}`}
onMouseDown={e => this._setFontSize(e, `${fontSize}px`, styles)}
>{fontSize}</div>
))
return (
<div style={{marginTop:"20px"}}>
{/* toolbar */}
<div>
<button onMouseDown={this._onBoldClick.bind(this)}>B</button>
<button onMouseDown={this._onItalicClick.bind(this)}>I</button>
<button
onMouseDown={this._onFontDropDownClick.bind(this)}
>
Font Size
</button>
{/* open or close menu if the button is pressed. */}
{this.state.isShowingFontSizeMenu ?
<div>
{fontSizeOptions}
</div> : null
}
</div>
<div style={{border:"1px solid black", borderRadius:"2px", padding:"5px", marginTop:"20px"}}>
<Editor
editorState={this.state.editorState}
handleKeyCommand={this.handleKeyCommand}
onChange={this.onEditorStateChange}
customStyleFn={customStyleFn}
/>
</div>
</div>
);
}
}
export const RichTextEditorPreview = ({ value }) => {
console.log(draftToHtml(convertToRaw(value.getCurrentContent())))
return <MarkdownContent content={draftToHtml(convertToRaw(value.getCurrentContent()))} />
}