🎉
EditorjsでDarkmodeに対応する
Next+MUIでダークモードが割といい感じにできることを知り早速実装したものの、Editorjsはダークモード的なスタイルがない。
と思っていたらリリースノートにEditorjs開発者用にダークモード実装したよ〜という記載があったのでソースコードを探しに行ったらあった。
Nextでcssmoduleを使って実装
ArticleEditor.tsx
import { useEffect, useRef } from "react";
import EditorJS, { API, EditorConfig, OutputData } from "@editorjs/editorjs";
import { useTheme } from "@mui/material/styles";
import useId from "@mui/utils/useId";
import styles from "./ArticleEditor.module.css";
import { EditorTools, i18n } from "@constants/EditorTools";
import useLocale from "@hooks/useLocale";
type ArticleEditorProps = {
defaultValue?: OutputData;
placeholder?: EditorConfig["placeholder"];
readOnly?: EditorConfig["readOnly"];
minHeight?: EditorConfig["minHeight"];
autofocus?: EditorConfig["autofocus"];
hideToolbar?: EditorConfig["hideToolbar"];
onReady?: () => void;
onSave?: (data: OutputData) => void;
onChange?: (api: API, event: CustomEvent) => void;
onInitialize?: (editor: EditorJS) => void;
};
const ArticleEditor = ({
defaultValue,
placeholder,
readOnly,
minHeight,
autofocus,
hideToolbar,
onReady,
onChange,
onSave,
onInitialize,
}: ArticleEditorProps) => {
const id = useId();
const { locale } = useLocale();
const editorJS = useRef<EditorJS | null>(null);
const theme = useTheme();
useEffect(() => {
if (editorJS.current === null) {
editorJS.current = new EditorJS({
placeholder,
readOnly,
minHeight,
autofocus,
hideToolbar,
holder: id,
data: defaultValue,
i18n: i18n(locale),
tools: EditorTools(locale),
onChange(api: API, event: CustomEvent) {
if (readOnly) return;
editorJS.current?.save().then((res) => {
if (onSave) {
onSave(res);
}
});
if (onChange) {
onChange(api, event);
}
},
onReady() {
if (onReady) {
onReady();
}
},
});
if (onInitialize) {
onInitialize(editorJS.current);
}
}
}, []);
return (
<div
id={id}
className={
theme.palette.mode === "dark"
? `${styles.wrapper} ${styles["dark-mode"]}`
: ""
}
/>
);
};
ArticleEditor.defaultProps = {
defaultValue: { blocks: [] },
placeholder: "",
readOnly: false,
minHeight: 0,
autofocus: false,
hideToolbar: false,
onReady: () => {},
onChange: () => {},
onSave: () => {},
onInitialize: () => {},
};
export default ArticleEditor;
ArticleEditor.module.css
.wrapper {
background: var(--color-bg-main);
color: var(--color-text-main);
}
.dark-mode {
--color-border-light: rgba(255, 255, 255, .08);
--color-bg-main: #1c1e24;
--color-text-main: #737886;
}
/**
* Dark theme overrides
*/
.dark-mode img {
opacity: 0.5;
}
.dark-mode .cdx-simple-image__picture--with-border,
.dark-mode .cdx-input {
border-color: var(--color-border-light);
}
.dark-mode .ce-example__button {
box-shadow: 0 24px 18px -14px rgba(4, 154, 255, 0.24);
}
.dark-mode .ce-example__output {
background-color: #17191f;
}
.dark-mode .inline-code {
background-color: rgba(53, 56, 68, 0.62);
color: #727683;
}
.dark-mode a {
color: #959ba8;
}
.dark-mode .ce-example__statusbar-toggler,
.dark-mode .ce-example__statusbar-button {
background-color: #343842;
}
.dark-mode .ce-example__statusbar-toggler::before {
transform: translateX(calc(var(--toggler-size) * 2.2 - var(--toggler-size)));
}
.dark-mode .ce-example__statusbar-toggler::after {
content: '*';
right: auto;
left: 6px;
top: 7px;
color: #fff;
box-shadow: none;
font-size: 32px;
}
.dark-mode.show-block-boundaries .ce-block,
.dark-mode.show-block-boundaries .ce-block__content {
box-shadow: 0 0 0 1px rgba(128, 144, 159, 0.09) inset;
}
.dark-mode.thin-mode .ce-example__content {
border-color: var(--color-border-light);
}
.dark-mode .ce-example__statusbar-item:not(:last-of-type)::after {
color: var(--color-border-light);
}
.dark-mode .ce-block--selected .ce-block__content,
.dark-mode ::selection {
background-color: rgba(57, 68, 84, 0.57);
}
.dark-mode .ce-toolbox__button,
.dark-mode .ce-toolbar__settings-btn,
.dark-mode .ce-toolbar__plus {
color: inherit;
}
.dark-mode .ce-stub {
opacity: 0.3;
}
ce-toolbar__plusとかのCSSが一部当たらなくて若干困っているものの、ダークモードで完全に使えない状態から、キーボードであれば普通に使える状態にまではいけることがわかったのでOK。
Discussion