UNPKG

@mdxeditor/editor

Version:

React component for rich text markdown editing

131 lines (130 loc) 4.98 kB
import { useCellValues } from "@mdxeditor/gurx"; import React__default from "react"; import styles from "../../styles/ui.module.css.js"; import { useCodeBlockEditorContext } from "../codeblock/CodeBlockNode.js"; import { useTranslation, readOnly$, iconComponentFor$ } from "../core/index.js"; import { languages } from "@codemirror/language-data"; import { EditorState } from "@codemirror/state"; import { lineNumbers, keymap, EditorView } from "@codemirror/view"; import { indentWithTab } from "@codemirror/commands"; import { basicLight } from "cm6-theme-basic-light"; import { basicSetup } from "codemirror"; import { $setSelection } from "lexical"; import { codeMirrorExtensions$, codeMirrorAutoLoadLanguageSupport$, codeBlockLanguages$ } from "./index.js"; import { useCodeMirrorRef } from "../sandpack/useCodeMirrorRef.js"; import { Select } from "../toolbar/primitives/select.js"; const COMMON_STATE_CONFIG_EXTENSIONS = []; const EMPTY_VALUE = "__EMPTY_VALUE__"; const CodeMirrorEditor = ({ language, nodeKey, code, focusEmitter }) => { const t = useTranslation(); const { parentEditor, lexicalNode } = useCodeBlockEditorContext(); const [readOnly, codeMirrorExtensions, autoLoadLanguageSupport, iconComponentFor, codeBlockLanguages] = useCellValues( readOnly$, codeMirrorExtensions$, codeMirrorAutoLoadLanguageSupport$, iconComponentFor$, codeBlockLanguages$ ); const codeMirrorRef = useCodeMirrorRef(nodeKey, "codeblock", language, focusEmitter); const { setCode } = useCodeBlockEditorContext(); const editorViewRef = React__default.useRef(null); const elRef = React__default.useRef(null); const setCodeRef = React__default.useRef(setCode); setCodeRef.current = setCode; codeMirrorRef.current = { getCodemirror: () => editorViewRef.current }; React__default.useEffect(() => { const el = elRef.current; void (async () => { const extensions = [ ...codeMirrorExtensions, basicSetup, basicLight, lineNumbers(), keymap.of([indentWithTab]), EditorView.lineWrapping, EditorView.updateListener.of(({ state }) => { setCodeRef.current(state.doc.toString()); }), EditorView.domEventHandlers({ focus: () => { parentEditor.update(() => { $setSelection(null); }); } }) ]; if (readOnly) { extensions.push(EditorState.readOnly.of(true)); } if (language !== "" && autoLoadLanguageSupport) { const languageData = languages.find((l) => { return l.name === language || l.alias.includes(language) || l.extensions.includes(language); }); if (languageData) { try { const languageSupport = await languageData.load(); extensions.push(languageSupport.extension); } catch (e) { console.warn("failed to load language support for", language); } } } el.innerHTML = ""; editorViewRef.current = new EditorView({ parent: el, state: EditorState.create({ doc: code, extensions }) }); el.addEventListener("keydown", stopPropagationHandler); })(); return () => { var _a; (_a = editorViewRef.current) == null ? void 0 : _a.destroy(); editorViewRef.current = null; el.removeEventListener("keydown", stopPropagationHandler); }; }, [readOnly, language, ...codeMirrorExtensions]); return /* @__PURE__ */ React__default.createElement("div", { className: styles.codeMirrorWrapper }, /* @__PURE__ */ React__default.createElement("div", { className: styles.codeMirrorToolbar }, /* @__PURE__ */ React__default.createElement( Select, { disabled: readOnly, value: language, onChange: (language2) => { parentEditor.update(() => { lexicalNode.setLanguage(language2 === EMPTY_VALUE ? "" : language2); setTimeout(() => { parentEditor.update(() => { lexicalNode.getLatest().select(); }); }); }); }, triggerTitle: t("codeBlock.selectLanguage", "Select code block language"), placeholder: t("codeBlock.inlineLanguage", "Language"), items: Object.entries(codeBlockLanguages).map(([value, label]) => ({ value: value ? value : EMPTY_VALUE, label })) } ), /* @__PURE__ */ React__default.createElement( "button", { className: styles.iconButton, type: "button", disabled: readOnly, title: t("codeblock.delete", "Delete code block"), onClick: (e) => { e.preventDefault(); parentEditor.update(() => { lexicalNode.remove(); }); } }, iconComponentFor("delete_small") )), /* @__PURE__ */ React__default.createElement("div", { ref: elRef })); }; function stopPropagationHandler(ev) { ev.stopPropagation(); } export { COMMON_STATE_CONFIG_EXTENSIONS, CodeMirrorEditor };