最近、個人的にQuill.jsを使用したアプリを開発しています。
ヘッダーにアイコンを追加する処理で少し詰まったのでその備忘録です。
全体像
今回は react
を用いて開発しました。
全体像はこんな感じです。
import { useEffect, useRef, useState } from "react";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import { MemoContent } from "@/app/constants/interfaces";
// ツールバーに表示するアイコンのオプション
const toolbarOptions = [
["bold", "italic", "underline", "strike"],
["blockquote", "code-block"],
["link", "image"],
[{ list: "ordered" }, { list: "bullet" }],
[{ indent: "-1" }, { indent: "+1" }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ align: [] }],
["clean"],
["markdown"], // 追加
];
export default function Editor({ onValueChange, content }: MemoContent) {
const editorRef = useRef<HTMLDivElement>(null);
const [quill, setQuill] = useState<Quill | null>(null);
const isMounted = useRef(false);
const icons = Quill.import("ui/icons") as Record<string, string>;
// 追加するアイコンのSVG
icons["markdown"] = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 20" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" />
<path d="M7 15v-6l2 2l2 -2v6" />
<path d="M14 13l2 2l2 -2m-2 2v-6" />
</svg>
`;
useEffect(() => {
if (!editorRef.current || quill) return;
if (!isMounted.current) {
const quillInstance = new Quill(editorRef.current, {
theme: "snow",
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
// 追加したアイコンをクリックしたときの処理
markdown: function () {
console.log("markdown");
},
},
},
},
});
setQuill(quillInstance);
isMounted.current = true;
quillInstance.on("text-change", () => {
const editorContent = quillInstance.getContents();
if (editorContent) onValueChange(editorContent);
});
}
}, []);
useEffect(() => {
if (quill) {
if (content && content.ops.length > 0) {
const currentContent = quill.getContents();
if (JSON.stringify(currentContent) !== JSON.stringify(content)) {
quill.setContents(content);
}
} else {
quill.setText("");
}
}
}, [content, quill]);
return (
<>
<div ref={editorRef} />
</>
);
}
解説
toolbarOptions
への追加
まずはここに追加したいアイコン名を追加します。
今回はmarkdown形式に変換する機能を実装したかったので markdown
という名前で追加しました。
const toolbarOptions = [
["bold", "italic", "underline", "strike"],
["blockquote", "code-block"],
["link", "image"],
[{ list: "ordered" }, { list: "bullet" }],
[{ indent: "-1" }, { indent: "+1" }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ align: [] }],
["clean"],
["markdown"], // 追加
];
アイコンの追加
ここで追加したいアイコンのSVG要素を追加します。
今回はべた書きでSVG要素を記述していますが、
font-awesome
のアイコンとかでも問題ないみたいです。
const icons = Quill.import("ui/icons") as Record<string, string>;
// 追加するアイコンのSVG
icons["markdown"] = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 20" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" />
<path d="M7 15v-6l2 2l2 -2v6" />
<path d="M14 13l2 2l2 -2m-2 2v-6" />
</svg>
`;
handlers
にクリック時の処理を追加
ql-'クラス名'
の 'クラス名' にあたる部分と同じfunction名を追加します。
const quillInstance = new Quill(editorRef.current, {
theme: "snow",
modules: {
toolbar: {
container: toolbarOptions,
handlers: {
// 追加したアイコンをクリックしたときの処理
markdown: function () {
console.log("markdown");
},
},
},
},
});
おわりに
少し複雑ですが、任意のアイコンを追加できるのは面白いなと思いました。
既存のアイコンも変更できるようなので、
またタイミングで変更してみたいと思います。
参考文献