TinyMCE + ReactでNotionライクなスラッシュコマンド(ショートカット)使えるようにする
category
date
Jan 27, 2023
slug
tinymce-react-slash-shortcut
status
Published
summary
TinyMCE + Reactでオートコンプリート機能を使って、Notionライクなスラッシュコマンド(ショートカット)使えるようにしてみた話
type
Post
TinyMCE + Reactでのsetup関数
setup関数は以下のように設定します。
<Editor
onInit={(evt, editor) => (editorRef.current = editor)}
initialValue=""
init={{
height: 500,
menubar: false,
plugins: [
'advlist autolink lists link image charmap print preview anchor',
'searchreplace visualblocks code fullscreen',
'insertdatetime media table paste code help wordcount'
],
toolbar:
'undo redo | formatselect | ' +
'bold italic backcolor | alignleft aligncenter ' +
'alignright alignjustify | bullist numlist outdent indent | ' +
'removeformat | help',
content_style:
'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }',
setup: (editor) => {
editor.ui.registry.addButton('myButton', {
text: 'My button',
onAction: () => {
alert('Button clicked!');
}
});
}
}}
/>
Autocompleter APIを使用する
オートコンプリートを設定するために、TyneMCEのAutocompleter API を使用します。
setup: (editor) => {
const insertActions = [
{
text: 'Heading 1',
icon: 'h1',
action: function () {
editor.execCommand(
'mceInsertContent',
false,
'<h1></h1>'
);
editor.selection.select(editor.selection.getNode());
}
},
{
type: 'separator'
},
{
text: 'Bulleted list',
icon: 'unordered-list',
action: function () {
editor.execCommand('InsertUnorderedList', false);
}
},
];
// Autocompleter API
editor.ui.registry.addAutocompleter(
'Menubar-item-variable',
{
ch: '/',
minChars: 0 /** Zero value means that the menu appears as soon as you type the "/" */,
columns: 1,
fetch: (pattern) => {
const matchedActions = insertActions.filter(
function (action) {
return (
action.type === 'separator' ||
action.text
.toLowerCase()
.indexOf(pattern.toLowerCase()) !== -1
);
}
);
return new Promise((resolve) => {
var results = matchedActions.map(function (
action
) {
return {
meta: action,
text: action.text,
icon: action.icon,
value: action.text,
type: action.type
};
});
resolve(results);
});
},
onAction: (autocompleteApi, rng, action, meta) => {
editor.selection.setRng(rng);
// Some actions don't delete the "slash", so we delete all the slash
// command content before performing the action
editor.execCommand('Delete');
meta.action();
autocompleteApi.hide();
}
}
);
}