React component wrapper forEasyMDE (the most fresh SimpleMDE fork).
Only two dependencies, React (peer) and EasyMDE (peer).
Built by @RIP21
Table of contents generated with markdown-toc
>=16.8.2
easymde
now a peer dependency, please install it manuallylabel
prop has been removedoptions
shall be memoized to prevent new instances from being created on each render and other related to that bugs (more on that below)ref
, so you can easily get access to div
wrapper by using ref
prop.@babel/runtime
helpers are no longer inlined but imported.npm install --save react-simplemde-editor easymde
Note: Possibly you may need to install @babel/runtime
, try without it, but if you don't have any issues, then you shouldn't.
or to see it locally:
git clone https://github.com/RIP21/react-simplemde-editor.git
cd react-simplemde-editor
yarn install
yarn demo
open browser at localhost:3000
View the demo code for more examples.
All examples below are in TypeScript
Uncontrolled usage
import React from "react";
import SimpleMDE from "react-simplemde-editor";
import "easymde/dist/easymde.min.css";
<SimpleMDE />;
export const ControlledUsage = () => {
const [value, setValue] = useState("Initial value");
const onChange = useCallback((value: string) => {
setValue(value);
}, []);
return <SimpleMdeReact value={value} onChange={onChange} />;
};
You can set API of SimpleMDE options which you pass down as a options
prop.If you're using TypeScript it will be inferred by compiler.
Note: if you don't specify a custom id it will automatically generate an id for you.
Note that you need to useMemo
to memoize options
so they do not change on each rerender! It will affect behavior and performancebecause then on each render of the parent that renders SimpleMdeReact
you'll get a new instance of the editor, which you definitely want to avoid!Also, if you change options
on each value
change you will lose focus.So, put options
as a const
outside of the component, or if options
shall be partially or fully set by props
make sure to useMemo
incase of functional/hooks components, or class field for class
based components.Slightly more on that here: #164
export const UsingOptions = () => {
const [value, setValue] = useState("Initial");
const onChange = useCallback((value: string) => {
setValue(value);
}, []);
const autofocusNoSpellcheckerOptions = useMemo(() => {
return {
autofocus: true,
spellChecker: false,
} as SimpleMDE.Options;
}, []);
return (
<SimpleMdeReact
options={autofocusNoSpellcheckerOptions}
value={value}
onChange={onChange}
/>
);
};
You can include key maps using the extraKeys
prop.Read more at CodeMirror extra keys
export const UpdateableByHotKeys = () => {
const extraKeys = useMemo<KeyMap>(() => {
return {
Up: function (cm) {
cm.replaceSelection(" surprise. ");
},
Down: function (cm) {
cm.replaceSelection(" surprise again! ");
},
};
}, []);
const [value, setValue] = useState("initial");
const onChange = (value: string) => setValue(value);
return (
<SimpleMdeReact value={value} onChange={onChange} extraKeys={extraKeys} />
);
};
import ReactDOMServer from "react-dom/server";
export const CustomPreview = () => {
const customRendererOptions = useMemo(() => {
return {
previewRender() {
return ReactDOMServer.renderToString(
<ReactMarkdown
source={text}
renderers={{
CodeBlock: CodeRenderer,
Code: CodeRenderer,
}}
/>
);
},
} as SimpleMDE.Options;
}, []);
return (
<div>
<h4>Custom preview</h4>
<SimpleMdeReact options={customRendererOptions} />
</div>
);
};
See full list of events here
import { SimpleMdeReact } from "react-simplemde-editor";
import type { SimpleMdeToCodemirrorEvents } from "react-simplemde-editor";
export const CustomEventListeners = () => {
const [value, setValue] = useState("Initial value");
const onChange = useCallback((value: string) => {
setValue(value);
}, []);
// Make sure to always `useMemo` all the `options` and `events` props to ensure best performance!
const events = useMemo(() => {
return {
focus: () => console.log(value),
} as SimpleMdeToCodemirrorEvents;
}, []);
return <SimpleMdeReact events={events} value={value} onChange={onChange} />;
};
export const Autosaving = () => {
const delay = 1000;
const autosavedValue = localStorage.getItem(`smde_demo`) || "Initial value";
const anOptions = useMemo(() => {
return {
autosave: {
enabled: true,
uniqueId: "demo",
delay,
},
};
}, [delay]);
return (
<SimpleMdeReact id="demo" value={autosavedValue} options={anOptions} />
);
};
easymde
, codemirror
or cursor
info to be able to manipulate it.export const GetDifferentInstances = () => {
// simple mde
const [simpleMdeInstance, setMdeInstance] = useState<SimpleMDE | null>(null);
const getMdeInstanceCallback = useCallback((simpleMde: SimpleMDE) => {
setMdeInstance(simpleMde);
}, []);
useEffect(() => {
simpleMdeInstance &&
console.info("Hey I'm editor instance!", simpleMdeInstance);
}, [simpleMdeInstance]);
// codemirror
const [codemirrorInstance, setCodemirrorInstance] = useState<Editor | null>(
null
);
const getCmInstanceCallback = useCallback((editor: Editor) => {
setCodemirrorInstance(editor);
}, []);
useEffect(() => {
codemirrorInstance &&
console.info("Hey I'm codemirror instance!", codemirrorInstance);
}, [codemirrorInstance]);
// line and cursor
const [lineAndCursor, setLineAndCursor] = useState<Position | null>(null);
const getLineAndCursorCallback = useCallback((position: Position) => {
setLineAndCursor(position);
}, []);
useEffect(() => {
lineAndCursor &&
console.info("Hey I'm line and cursor info!", lineAndCursor);
}, [lineAndCursor]);
return (
<div>
<h4>Getting instance of Mde and codemirror and line and cursor info</h4>
<SimpleMdeReact
value="Go to console to see stuff logged"
getMdeInstance={getMdeInstanceCallback}
getCodemirrorInstance={getCmInstanceCallback}
getLineAndCursor={getLineAndCursorCallback}
/>
</div>
);
};
Here is how you do it. It requires mock of certain browser pieces to work, but this is whole example.
import { act, render, screen } from "@testing-library/react";
import { useState } from "react";
import { SimpleMdeReact } from "SimpleMdeReact";
import userEvent from "@testing-library/user-event";
// @ts-ignore
Document.prototype.createRange = function () {
return {
setEnd: function () {},
setStart: function () {},
getBoundingClientRect: function () {
return { right: 0 };
},
getClientRects: function () {
return {
length: 0,
left: 0,
right: 0,
};
},
};
};
const Editor = () => {
const [value, setValue] = useState("");
return <SimpleMdeReact value={value} onChange={setValue} />;
};
describe("Renders", () => {
it("succesfully", async () => {
act(() => {
render(<Editor />);
});
const editor = await screen.findByRole("textbox");
userEvent.type(editor, "hello");
expect(screen.getByText("hello")).toBeDefined();
});
});
export interface SimpleMdeReactProps
extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
id?: string;
onChange?: (value: string) => void;
value?: string;
extraKeys?: KeyMap;
options?: SimpleMDE.Options;
events?: SimpleMdeToCodemirrorEvents;
getMdeInstance?: (instance: SimpleMDE) => void;
getCodemirrorInstance?: (codemirror: Editor) => void;
getLineAndCursor?: (position: Position) => void;
}
default
- SimpleMdeReact SimpleMdeReact
- same as default
but named
Types: SimpleMdeReactProps
- props of the component DOMEvent
- certain events that are used to get events exported below CopyEvents
- only copy codemirror events GlobalEvents
- some other global codemirror events DefaultEvent
- default codemirror event handler function IndexEventsSignature
- index signature that expects string as key and returns DefaultEvent
SimpleMdeToCodemirrorEvents
- manually crafted events (based off @types/codemirror@0.0.109
that easymde
uses internally) +all the above merged together into whole mapping between Codemirror event names and actual handlers forevents
prop GetMdeInstance
- signature of the callback function that retrieves mde instance GetCodemirrorInstance
- signature of the callback function that retrieves codemirror instance GetLineAndCursor
- signature of the callback function that retrieves line and cursor info
simplemde
itself. Possible breaking changes, so I bumped version to v4.simplemde/dist/simplemde.min.css
now it will be easymde/dist/easymde.min.css
initialValue
prop has been removed and replaced with a value
prop, allowing direct changes to the value to be made after the component mounts.Version 1.0 did not have SimpleMDE options configured well, this readme reflects the changes made to better include options.This is still a very new project. Testing, feedback and PRs are welcome and appreciated.
前言 有时,当我们使用react-router模块在路由切换时会出现页面空白的情况,这次就将该情况讲解清楚并解决。 出现的问题 下面,我们直接上有问题的代码: <Switch> <Route path={"/"} component={loadable(() => import("./App.jsx"))} /> <Route path={"/home"} component={l
一、在 npm run build 的时候关闭 SourceMap 的方法 最不具破坏性且没有副作用的方案: 在根目录下新建 .env.production 文件; 然后在这个文件中只需写上一行代码: GENERATE_SOURCEMAP=false 如果因为 React 脚手架版本不支持,则可以使用以下方案,但是需要注意该方案根据不同版本会有所差异,且不会消除 CSS和 JS 文件中的 maps
CKEditor 4 页面多次调用 ,出现多个editor(编辑器),很无语 网上面有好多方法是用remove,其实是没有用的,比如: if (CKEDITOR.instances[id]){ CKEDITOR.remove(CKEDITOR.instances[id]); CKEDITOR.replace(id); } 解决办法: function Loa
如果没有看前两篇的童鞋,可以看看前两篇文章的内容,虽然写的一般,但是起码也是一个重无到有的过程。 直接进主题 到这里,其实我们的前端页面布局,后台nodejs服务程序已经有了,现在就是写页面和调用后台服务程序去处理数据了。 现在可以看看练习项目的功能点了,其实很简单啦: 1、显示文章列表 2、添加文章,当然就包括:格式、图片、链接啦 3、简单的登录控制(这个超级简单,只是做了一个管理员账号的登录)
最近在学nodejs,准备配合react+mongodb搭个博客,找了很多富文本编辑器,都不是很适合react用,后来看到一篇vue+node搭建博客的文章,里面使用的simplemde(github地址),完全就符合我的想法啊,界面简洁大方还有预览功能。 附上官方demo 用法也相当简单,官方介绍的是外链的引用方法,下面我说一下如何配合 makded 语法库和 highlight.js 代码高亮
SimpleMDE 是一个嵌入式 JavaScript 文本框,用于替代书写好看且易懂的 markdown。WYSIWYG-esque 编辑器可以让用户修改 markdown 的工具条按钮和快捷键。WYSIWYG 编辑器产生的 HTML 复杂且多 Bug。Markdown 有很多办法可以解决这个问题,但是在编辑的时候不是很清晰。SimpleMDE 可以为那些不太熟悉或者正在学习 markdown
Vue-SimpleMDE Markdown Editor component for Vue.js. Support only vue2.x. Use Setup No longer support Vue1.x, you can modify to use Install npm install vue-simplemde --save Use Internal reference in a
问题内容: 我注意到可以这样导入: …或像这样: 第一个导入模块中的所有内容(请参阅:导入整个模块的内容) 第二个仅导入模块导出(请参阅:导入默认值) 似乎这两种方法是不同的,并且根本上是不兼容的。 为什么它们都起作用? 请参考源代码并解释该机制…我有兴趣了解其工作原理。 ES6常规模块信息回答了该问题。 我在问使模块像这样工作的机制。在这里,它似乎与源代码中的 “ hacky”导出机制有关,但尚
A simple markdown editor with preview, implemented with React.js and TypeScript. This React Component aims to provide a simple Markdown editor with syntax highlighting support. This is based on textar
react-markdown-editor 是 React.js 和 TypeScript 实现的 Markdown 编辑器。 Markdown 编辑器带预览功能 安装 npm i @uiw/react-markdown-editor 文档 文档实例预览:demo preview (����中国镜像网站) 使用 import MarkdownEditor from '@uiw/react-mark
这篇快速上手指南会教你如何将TypeScript与React结合起来使用。 在最后,你将学到: 使用TypeScript和React创建工程 使用TSLint进行代码检查 使用Jest和Enzyme进行测试,以及 使用Redux管理状态 我们会使用create-react-app工具快速搭建工程环境。 这里假设你已经在使用Node.js和npm。 并且已经了解了React的基础知识。 我们之所以使