Reactでマークダウンエディタの作成と、マークダウン表記をHTMLに変換(ハイライト付き)してみました。
ライブラリを組み合わせることで、楽に実装することができます。
環境
- OS : macOS Catalina 10.15.3
- node.js : 12.13.1
- React : 16.12.0
Reactのライブラリは以下を使用します。
- react-simplemde-editor(EasyMDE) : 4.1.0
- marked : 0.8.0
- highitjs : 9.16.2
参考までに、紹介するコードはGitHubにあります。
https://github.com/txkxyx/react-mde
マークダウンエディタを作成する
Webの画面にマークダウンエディタを埋め込む場合、元々SimpleMDE
というライブラリが使用されていましたが、今はEasyMDE
というSimpleMDE
をフォークして作られたライブラリが使用されています。
↓EasyMDE
https://github.com/Ionaru/easy-markdown-editor
今回はEasyMDE
のReactラッパーコンポーネントであるreact-simplemde-editor
を使用してマークダウンエディタを作成します。
↓react-simplemde-editor
https://www.npmjs.com/package/react-simplemde-editor
まずは使用するパッケージをインストールします。
$ npm install react-simplemde-editor
コンポーネントを作成します。
実装はとてもシンプルです。SimpleMDE
のコンポーネントとEasyMDE
のcssファイルをインポートします。
SimpleMDE
コンポーネントにはonChange
イベントで起動する関数を渡す必要があります。この関数は合成イベントを受け取り、その値がエディターで入力したマークダウンになります。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
return(
<SimpleMDE onChange={(e) => setMarkdown(e)}/>
)
}
export default MarkDownEditor;
ツールバーにメニューが表示されています。デフォルトでは以下のメニューが表示されます。
メニュー | 説明 | 表記 |
---|---|---|
bold | 強調 | **** |
italic | 強勢 | ** |
heading | 見出し | # |
quote | 引用 | > |
unordered-list | 箇条書き | * |
ordered-list | 番号付きリスト | 1. |
link | リンク挿入 | [](https://) |
image | 画像挿入 | ![](https://) |
preview | プレビューモード | なし |
side-by-side | 入力とプレビューで画面分割 | なし |
fullscreen | 全画面でプレビューモード | なし |
guide | マークダウン記法ガイド | なし |
メニューの一覧は以下を確認してください。
https://github.com/Ionaru/easy-markdown-editor#toolbar-icons
メニューを追加する場合は以下のように実装します。
メニューを追加するとデフォルトのメニューが消えてしまうので、デフォルトのメニューを追加したい場合は別途追加します。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
const toolbar = [
{
name: "save",
action: function customFunction(editor) {
alert(editor.value())
// save action
},
className: "fa fa-save",
title: "Save"
},
'|',
'bold',
'italic',
'heading',
'|',
'quote',
'unordered-list',
'ordered-list',
'|',
'link',
'image',
'|',
'preview',
'side-by-side',
'fullscreen',
'|',
'guide',
]
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
return(
<SimpleMDE onChange={(e) => setMarkdown(e)} options={{toolbar:toolbar}}/>
)
}
export default MarkDownEditor;
マークダウンエディタを拡張する
EasyMDE
は機能を拡張することができます。その一つのCodeMirror
のイベント処理を利用して、JavaScriptのイベントをハンドリングしてみます。
CodeMirror
のイベントは以下から確認してください。
https://codemirror.net/doc/manual.html#events
画像などのファイルをマークダウンエディタにドロップして、そのデータを取得してみます。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
function handleDrop(data, e){
let files = e.dataTransfer.files;
if(files.length > 0){
let file = files[0];
alert('FileName : ' + file.name );
// any action
}
}
return(
<SimpleMDE onChange={(e) => setMarkdown(e)} events={{'drop':handleDrop}}/>
)
}
export default MarkDownEditor;
SimpleMDE
のコンポーネントのevents
のpropsにドロップ時に起動する関数を指定します。
この関数内でファイルオブジェクトを取得することができます。この関数内で画像アップロードをすると、画像アップロード込みのマークダウンエディタを実装することができます。
マークダウン表記をHTMLに変換する
マークダウン形式の文字列をHTMLに変換するために、marked
ライブラリを使用します。
$ npm install marked
先ほど作成したエディタで入力されたマークダウンをmarked
でHTMLに変換し画面に表示します。
インポートしたmarked
の引数に、マークダウン形式の文字列を渡すだけです。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
return(
<div>
<SimpleMDE onChange={(e) => setMarkdown(e)}/>
<div id="body" >
<span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
</div>
</div>
)
}
export default MarkDownEditor;
これで、エディタで入力したマークダウンをHTMLに変換して表示することができます。
ではコードを挿入している部分にハイライトを追加していきます。
ハイライトをつける
コードを挿入している部分にハイライトを付けるために、highlightjs
を導入します。
JavaScriptのハイライトのライブラリの中でも対応言語が多く、パレットの種類も豊富です。(185言語、91スタイル)
https://highlightjs.org/static/demo/
ライブラリをインストールします。
$ npm install highlightjs
実装は以下のようになります。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";
import highlight from 'highlightjs';
import 'highlightjs/styles/docco.css';
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
return(
<div>
<SimpleMDE onChange={(e) => setMarkdown(e)}/>
<div id="body" >
<span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
</div>
</div>
)
}
export default MarkDownEditor;
highlightjs
と適用したいスタイルのCSSファイルをインポートします。今回はdocco
というスタイルを使用したので、docco.css
をインポートしています。
CSSファイルはhighlightjs/styles/スタイル名.css
で指定できます。たまに違う場合もありますので、その時はハイフンを付けたりしてみてください。
highlightjs
は表示する<code>
タグのclass
属性に指定されている言語名に応じてスタイルを適用します。
例えば、マークダウンで記載したPythonのコードは以下のような流れで表示されます。
- マークダウン形式
```python
コード
```
- markedでHTMLに変換
<span><code class="language-python">コード</code></span>
マークダウンで言語をPython
に指定しているので、marked
でHTMLに変換したい際にcodeタグのclass属性にlanguage-python
が指定され、highlightjs
のスタイルが適用されます。
```python:test.pyのように言語名の後にファイル名を記載している場合、class属性にファイル名まで適用されてしまうため、marked
のオプションを使用しレンダリング前にファイル名を除去することもできます。
実装は以下のようになります。
import React, { useState } from "react";
import SimpleMDE from 'react-simplemde-editor';
import 'easymde/dist/easymde.min.css';
import marked from "marked";
import highlight from 'highlightjs';
import 'highlightjs/styles/docco.css';
// delete file name
marked.setOptions({
highlight: function (code, lang) {
return highlight.highlightAuto(code, [lang.split(':')[0]]).value;
}
});
const MarkDownEditor = () => {
const [markdown, setMarkdown] = useState('');
return(
<div>
<SimpleMDE onChange={(e) => setMarkdown(e)}/>
<div id="body" >
<span dangerouslySetInnerHTML={{ __html: marked(markdown)}}/>
</div>
</div>
)
}
export default MarkDownEditor;
スタイルは豊富に用意されているので、サイトに合わせたハイライトを選択してみてください。
まとめ
Reactでライブラリを使用して、マークダウンエディタとマークダウンをHTMLに変換してみました。
コンポーネント一つ追加するだけで、簡単にマークダウンエディタを導入できます。拡張もできるので自由度はかなり高いかなと思っています。
他にもreact-mde
などのエディタがありますが、デザインなどの面からreact-simplemde-editor
の方が個人的には好みです。
もし使用する機会があれば検討してみてください。