A simple yet powerful and extensible Markdown Editor editor for React, inspired by GitHub. This is the editor used by http://aboutdevs.com.
Warning: React-mde is not yet stable and ready for production use even though we’re working very hard towards it. Its main current problem now is that Ctrl + Z doesn’t work 100% (after executing a command, history gets messy). I, @andrerpena, am curretly working to replace the textarea with Facebook’s Draft.js, this will solve the history problem and will make it easy to implement mentions and copying files. I’m also working on making the command infrastructure more rebust. Expect a major breaking change (5.*) coming on the 18th of March. After this, my goal will be to provide a GitHub like layout. React-mde currently supports multiple layouts already, but just a simple vertical one is provided out of the box. I want provide 2 refined layouts: Stackoverflow and GitHub. I’m really sorry for the constant breaking change releases. It was my fault. I should have used minor versions (0.*) until a final version was reached, but I can’t fix that now. I will make sure that 5.* will be a pretty stable version. Thanks for your comprehension and support.
Demos are provided through https://codesandbox.io. Feel free to fork and play with different options :smile:.
React-mde 4.* - JavaScript - Basic Demo
React-mde 4.* - TypeScript - Basic Demo
React-mde 3.* - JavaScript - Basic Demo
React-mde 3.* - TypeScript - Basic Demo
npm install --save react-mde
React-mde
currently depends on:
React-mde
used Font Awesome 4.7.* as an NPM dependency before 3.*. Now Font Awesome needs
to be installed separately using your preferred method. The easiest is just add this to <head/>
:
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>
You also need NPM packages.
For React-mde
3.*+:
npm install --save showdown
For React-mde
2.: (this will install Font Awesome 4.7.)
npm install --save showdown font-awesome
React-mde is a completely controlled component. You can experiment with the props below forking the Codesandbox demos
Props:
{text: "", selection?: {start:0, end:2}, scrollTop?: number }
where text
is the text and selection
is an object containing start
and end
representing what should be selected.
Passing null to selection
is perfectly fine.value
passed as a parameter to the onChange
function is of the same type as the value
prop above.[[cmd1, cmd2],[cmd3, cmd4]]
). The first array represents groups,
the second represents commands inside that group. For an example, refer to how the getDefaultCommands()
is implemented. How to create custom commands is explained below.textarea
component.original
, the original specs by John Gruber. Please refer to the Showdown documentation for the complete list of supported flavors.showdownOptions={{tables: true}}
to ReactMde
.visibility
is an object optionally containing these booleans:
toolbar
, textarea
, preview
and previewHelp
. For example, in order to hide the preview, you can pass visibility:{{preview:false}}
.The following styles from React-mde should be added: (Both .scss and .css files are available. No need to use sass-loader if you don’t want)
Easiest way: import react-mde-all.css
:
import 'react-mde/lib/styles/css/react-mde-all.css';
If you want to have a more granular control over the styles, you can import each individual file:
import 'react-mde/lib/styles/css/react-mde.css';
import 'react-mde/lib/styles/css/react-mde-toolbar.css';
import 'react-mde/lib/styles/css/react-mde-textarea.css';
import 'react-mde/lib/styles/css/react-mde-preview.css';
If you’re using SASS, you can override these variables: https://github.com/andrerpena/react-mde/blob/master/src/styles/variables.scss
You also need Font Awesome for the toolbar icons. React-mde
3.*+ uses Font Awesome 5.*. React-mde
2.* uses Font Awesome 4.*.
Font Awesome 5 can be installed in different ways, but the easiest is just adding this to the <head/>
:
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>
If you’re using React-mde
2.*, Font Awesome 4.* is required. After installing the NPM,
import it in your JavaScript or TypeScript like this:
import '../node_modules/font-awesome/css/font-awesome.css';
Normalize is optional but it’s used in the Demo.
import '../node_modules/normalize.css/normalize.css';
Taken from the Markdown repository documentation):
Cross-side scripting is a well known technique to gain access to private information of the users of a website. The attacker injects spurious HTML content (a script) on the web page which will read the user’s cookies and do something bad with it (like steal credentials). As a countermeasure, you should filter any suspicious content coming from user input. Showdown doesn’t include an XSS filter, so you must provide your own. But be careful in how you do it…
React-mde
does not automatically sanitize the Showdown generated HTML for you. However,
you can use your preferred anti-XSS library and use the processHtml
prop to sanitize
the HTML before it is presented in the preview.
React-mde allows you to use the build-in commands, implement your own commands, or both.
There are two types of commands, the button
commands (default if you don’t say anything), and the dropdown
commands.
button
commands appear as button and execute a single action when clicked. dropdown
commands have subCommands
and
will display a dropdown when you click them.
You don’t have to create your own commands at all, but if you want, this is how a command looks like:
const makeLinkCommand = {
icon: 'link',
tooltip:
'Insert a link',
execute:
(text: string, selection: TextSelection) => {
const {newText, insertionLength} = insertText(text, '[', selection.start);
const finalText = insertText(newText, '](url)', selection.end + insertionLength).newText;
return {
text: finalText,
selection: {
start: selection.start + insertionLength,
end: selection.end + insertionLength,
},
};
},
};
props:
font-awesome
<i/>
element with the classes fa fa-${icon}
. Passing bold
will print <i className="fa fa-bold"></i>
.
If the passing value is a React element, it will print the react element.text
,
which is the textarea text before the command, and selection
, an object containing start
and end
.
Your function should return the new text
and the new selection
(after your command).{
type: 'dropdown',
icon: 'header',
subCommands: [
{
content: <p className="header-1">Header</p>,
execute: function (text, selection) {
return makeHeader(text, selection, '# ');
}
},
{
content: <p className="header-2">Header</p>,
execute: function (text, selection) {
return makeHeader(text, selection, '## ');
}
},
{
content: <p className="header-3">Header</p>,
execute: function (text, selection) {
return makeHeader(text, selection, '### ');
}
}
]
}
props:
font-awesome
<i/>
element with the classes fa fa-${icon}
. Passing bold
will print <i className="fa fa-bold"></i>
.
If the passing value is a React element, it will print the react element.subCommands is an array of objects with the following props:
li
.text
, which is the whole textarea text before your command, and selection
, a 2 items array containing the beggining and end of the current selection.
Your function should return the current text
(after your command) and the current selection
(after your command).ReactMde
is designed to make it easy for users to customize the layout, or to make any of it sub-components invisible,
like the Preview, for instance. The ReactMde
component, itself, just a thin layout wrapper for its 3 internal components
with visibility options.
If you want to create your own layout, please take a look at the source code of the ReactMde
component:
https://github.com/andrerpena/react-mde/blob/master/src/ReactMde.tsx. It’s easy to simply create your own, only
leveraging the internal components you’d like and laying them out in the way you prefer
import * as ReactMde from 'react-mde';
// Now you have (among other utility modules):
// The ReactMde.ReactMdeToolbar component
// The ReactMde.ReactMdeTextArea component
// The ReactMde.ReactMdePreview component
Major differences:
commands
to React-Mde
is now optional. If none is passed, it will automatically
use the default ones.Now the React-mde
sub-components cannot be imported directly from the main package.
This change will not affect you if you don’t using sub-components. This will not affect the majority
of the users.
// 3.* and below: import { ReactMarkdownTextArea } from “react-mde” // 4.* and after: import { ReactMdeComponents } from “react-mde” const { ReactMarkdownTextArea } = ReactMdeComponents
Architectural differences:
React-Mde
in such a way that now, introducing new layouts, like
horizontal and tabs, will not require breaking changes. The only layout available now is Vertical
.Font Awesome 5 is now used, and it’s not a NPM peer dependency anymore.
It’s up to you how to install it, it can be installed in different ways, but the easiest is just adding this to the <head/>
:
<script defer src="https://use.fontawesome.com/releases/v5.0.6/js/all.js"></script>
2.* is a major refactoring of the code to improve composability
Major differences:
react-mde
component is composed of 3 sub-components, the ReactMdeToolbar
, the ReactMdeTextArea
and the ReactMdePreview
.
You can import react-mde
directly or import each of the sub-components and have more flexibility building your own layout.react-mde-all.css
, or the SCSS alternative, for simplicity.We realized that on version 1.*, it was difficult to select which components you wanted to use. So now…
import * as ReactMde from ‘react-mde’; ReactMde.ReactMdeComponents // contains all components and you can select your own components ReactMde.getDefaultComponents() // will return an array with all components
How to upgrade an existing 1.* JavaScript project: e62af170fa
How to upgrade an existing 1.* TypeScript project: d6718305c0
Major differences:
getDefaultCommands
function, now the default commands are exported directly.textAreaId
and textareaName
props were replaced by textAreaProps
that allows you to pass whatever you want to the textarea
component.Check the project here: https://github.com/andrerpena/react-mde/projects/1
React-mde is MIT licensed
Made with :heart: by André Pena. Check out my website: https://aboutdevs.com/andrerpena