I have this basic code that renders inputted md as html, and by default all checkboxes are disabled and even if I make them enabled with developer menu in browser they are still can`t be checked. How can I make them checkable, and how can I change the markdown according to "preview mode" where I'm changing state of these checkboxes?
I tried using the Rehype library but it didn't go well, which is why I'm asking this question.
import { createElement } from "react";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkReact from "remark-react/lib";
import { PreviewWindow } from "./style";
import RemarkCode from "./remarkCode";
import { defaultSchema } from "hast-util-sanitize";
import "github-markdown-css/github-markdown.css";
import { ViewMode } from "../types";
import remarkRehype from "remark-rehype";
import rehypeDocument from "rehype-document";
import rehypeFormat from "rehype-format";
import rehypeStringify from "rehype-stringify";
import rehypeReact from "rehype-react";
interface Props {
doc: string;
mode: ViewMode;
}
const schema = {
...defaultSchema,
attributes: {
...defaultSchema.attributes,
code: [...(defaultSchema.attributes?.code || []), "className"],
},
};
const Preview = (props: Props) => {
const { doc, mode } = props;
if (mode !== ViewMode.Edit) {
const md = unified()
.use(remarkParse)
.use(remarkGfm)
// .use(remarkRehype)
// .use(rehypeDocument)
// .use(rehypeFormat)
// .use(rehypeStringify)
.use(remarkReact, {
createElement: createElement,
sanitize: schema,
remarkReactComponents: {
code: RemarkCode,
},
} as any)
// .use(rehypeReact, {
// createElement: createElement,
// sanitize: schema,
// remarkReactComponents: {
// code: RemarkCode,
// },
// } as any)
.processSync(doc).result;
return (
<PreviewWindow $mode={mode} className="markdown-body editor">
{" "}
{md as any}
</PreviewWindow>
);
}
};
export default Preview;
import { MutableRefObject, useEffect, useRef, useState } from "react";
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
import { EditorState } from "@codemirror/state";
import { EditorView, keymap, highlightActiveLine, lineNumbers, highlightActiveLineGutter, drawSelection } from "@codemirror/view";
import { syntaxHighlighting, HighlightStyle, indentOnInput, bracketMatching } from "@codemirror/language";
import { tags } from "@lezer/highlight";
import { markdown, markdownLanguage } from "@codemirror/lang-markdown";
import { languages } from "@codemirror/language-data";
import { oneDark } from "@codemirror/theme-one-dark";
import { vim, Vim } from "@replit/codemirror-vim";
interface Props {
initialDoc: string,
onChange?: (state: EditorState) => void
}
const transparentTheme = EditorView.theme({
"&": {
backgroundColor: "transparent !important",
height: "100%"
}
});
const syntaxHighlightingCustom = HighlightStyle.define([
{
tag: tags.heading1,
fontSize: "1.6em",
fontWeight: "bold"
},
{
tag: tags.heading2,
fontSize: "1.4em",
fontWeight: "bold"
},
{
tag: tags.heading3,
fontSize: "1.2em",
fontWeight: "bold"
}
]);
const useCodeMirror = <T extends Element>(
props: Props
): [MutableRefObject<T | null>, EditorView?] => {
const refContainer = useRef<T>(null);
const [editorView, setEditorView] = useState<EditorView>();
const { onChange } = props;
useEffect(() => {
if (!refContainer.current) return;
const startState = EditorState.create({
doc: props.initialDoc,
extensions: [
vim(),
keymap.of([...defaultKeymap, ...historyKeymap]),
lineNumbers(),
highlightActiveLineGutter(),
history(),
indentOnInput(),
bracketMatching(),
highlightActiveLine(),
drawSelection(),
markdown({
base: markdownLanguage,
codeLanguages: languages,
addKeymap: true
}),
oneDark,
transparentTheme,
syntaxHighlighting(syntaxHighlightingCustom),
EditorView.lineWrapping,
EditorView.updateListener.of(update => {
if (update.changes) {
onChange && onChange(update.state);
}
})
]
});
Vim.map(":", "<Esc>");
const view = new EditorView({
state: startState,
parent: refContainer.current
});
setEditorView(view);
return () => {
view.destroy();
}
}, [refContainer]);
return [refContainer, editorView];
}
export default useCodeMirror;
import { EditorState } from "@codemirror/state";
import { useCallback } from "react";
import useCodeMirror from "./useCodeMirror";
import { EditorWindow } from "./style";
import { ViewMode } from "../types";
interface Props {
initialDoc: string,
mode: ViewMode
onChange: (doc: string) => void
}
const Editor = (props: Props) => {
const { onChange, initialDoc, mode } = props;
if (mode !== ViewMode.Preview) {
const handleChange = useCallback(
(state: EditorState) => onChange(state.doc.toString()),
[onChange]
);
const [refContainer, editorView] = useCodeMirror<HTMLDivElement>({
initialDoc,
onChange: handleChange
});
return <EditorWindow $mode={mode} ref={refContainer}></EditorWindow>
}
}
export default Editor;