Skip to content

Instantly share code, notes, and snippets.

@markspolakovs
Created March 20, 2018 13:31
Show Gist options
  • Save markspolakovs/08b522e186905c270b9d9cfdf9020775 to your computer and use it in GitHub Desktop.
Save markspolakovs/08b522e186905c270b9d9cfdf9020775 to your computer and use it in GitHub Desktop.
side-by-side editor
.editor-split {
flex: 1;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
}
@media all and (max-width: 1356px) {
.editor-split {
flex-wrap: wrap;
}
}
.mde-header .fa {
color: #fafafa;
}
.mde-text {
min-width: 600px;
color: #212121;
flex-grow: 1;
flex-shrink: 0;
font-size: 18px;
line-height: 24px;
textarea {
resize: none;
}
}
.mde-preview {
min-width: 600px;
max-width: 50%;
flex-grow: 1;
flex-shrink: 0;
font-size: 18px;
line-height: 24px;
}
.mde-preview img {
max-width: 100%;
}
.textarea--ghost {
opacity: 0.3;
display: block;
white-space: pre-wrap;
word-wrap: break-word;
visibility: hidden;
position: absolute;
top: 0;
pointer-events: none;
font-size: 18px;
line-height: 24px;
}
import * as React from "react";
import 'react-mde/lib/styles/css/react-mde-all.css';
import showdown from "showdown";
const showdownOptions = require("../lib/showdown/showdown.config");
const { imageExtension } = require("../lib/showdown/extensions")(showdown);
showdown.extension('imageExtension', imageExtension);
const mde = require("react-mde");
const makeImageCommand = (uploadImageRef) => ({
// snip
});
export default class MarkdownEditor extends React.Component {
constructor(props) {
super(props);
this.state = {height: 0};
this.textArea = null;
this.ghost = null;
this.mounted = false;
this.commands = [
[mde.ReactMdeCommands.makeHeaderCommand, mde.ReactMdeCommands.makeBoldCommand, mde.ReactMdeCommands.makeItalicCommand],
[mde.ReactMdeCommands.makeLinkCommand, mde.ReactMdeCommands.makeQuoteCommand, mde.ReactMdeCommands.makeCodeCommand, makeImageCommand(props.uploadImage)],
[mde.ReactMdeCommands.makeUnorderedListCommand, mde.ReactMdeCommands.makeOrderedListCommand],
];
}
componentDidMount() {
this.mounted = true;
this.setFilledTextareaHeight();
}
setFilledTextareaHeight = () => {
if (this.mounted) {
const element = this.ghost;
this.setState({
height: element.clientHeight + 100,
});
}
};
handleCommand = async command => {
const {value: {text}, onChange} = this.props;
let result = command.execute(text, mde.ReactMdeSelectionHelper.getSelection(this.textArea));
if (result instanceof Promise) {
result = await result;
}
// result.scrollTop = this.textArea.scrollTop;
onChange(result);
};
getGhostField() {
return (
<div
className="textarea textarea--ghost"
ref={(c) => this.ghost = c}
aria-hidden="true"
>
{this.props.value.text}
</div>
);
}
render() {
const {value, onChange, uploadImage} = this.props;
return (
<div>
{this.getGhostField()}
<mde.ReactMdeToolbar commands={this.commands} onCommand={this.handleCommand}/>
<div className="editor-split">
<mde.ReactMdeTextArea
value={value}
onChange={onChange}
textAreaRef={(c) => this.textArea = c}
textAreaProps={{
style: {
height: this.state.height,
resize: null
},
onKeyUp: this.setFilledTextareaHeight
}}
/>
<mde.ReactMdePreview markdown={value ? value.text : ""} showdownOptions={showdownOptions}/>
</div>
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment