Skip to content

Repository files navigation

Here, we have a new rich text editor called Editable, which does not use the native editable property contenteditable, but instead uses a custom renderer. This approach allows us to better control the behavior of the editor.

am-editor

A rich text editor that supports collaborative editing, you can freely use React, Vue and other front-end common libraries to extend and define plugins.

Preview · Document · Plugins

Vue2

Vue3

React

Vue2 Demo

Vue2 Nuxt Demo

Features

  • 🎁 Out-of-the-box solution with dozens of rich plugins to meet most needs
  • 🚀 Highly extensible, in addition to basic plugins for mark, inline, and block types, we also provide card components combined with front-end libraries like React and Vue to render plugin UI
  • 🎨 Rich multimedia support, not only supports images and audio/video, but also supports embedding multimedia content
  • 📝 Supports Markdown syntax
  • 🌍 Supports internationalization
  • 💻 Engine written purely in JavaScript, without relying on any front-end libraries, plugins can be rendered using front-end libraries like React and Vue. Can easily handle complex architecture
  • 👥 Built-in collaborative editing solution, lightweight configuration to use
  • 📱 Compatible with most latest mobile browsers

Plugins

PackageVersionSizedescription
@aomao/toolbarToolbar, suitable for React
@aomao/toolbar-vueToolbar, suitable for Vue3
am-editor-toolbar-vue2Toolbar, suitable for Vue2
@aomao/plugin-alignmentAlignment
@aomao/plugin-embedEmbed URL
@aomao/plugin-backcolorBackground color
@aomao/plugin-boldBold
@aomao/plugin-codeInline code
@aomao/plugin-codeblockCodeBlock, suitable for React
@aomao/plugin-codeblock-vueCodeBlock, suitable for Vue3
am-editor-codeblock-vue2CodeBlock, suitable for Vue2
@aomao/plugin-fontcolorFont color
@aomao/plugin-fontfamilyFont Family
@aomao/plugin-fontsizeFont Size
@aomao/plugin-headingHeading
@aomao/plugin-hrHorizontal rule
@aomao/plugin-indentIndentation
@aomao/plugin-italicItalic
@aomao/plugin-linkLink, suitable for React
@aomao/plugin-link-vueLink, suitable for Vue3
am-editor-link-vue2Link, suitable for Vue2
@aomao/plugin-line-heightLine height
@aomao/plugin-markMark
@aomao/plugin-mentionMention
@aomao/plugin-orderedlistOrdered list
@aomao/plugin-paintformatFormat painter
@aomao/plugin-quoteBlockquote
@aomao/plugin-redoRedo
@aomao/plugin-removeformatRemove format
@aomao/plugin-selectallSelect all
@aomao/plugin-statusStatus
@aomao/plugin-strikethroughStrikethrough
@aomao/plugin-subSub
@aomao/plugin-supSup
@aomao/plugin-tasklistTask list
@aomao/plugin-underlineUnderline
@aomao/plugin-undoUndo
@aomao/plugin-unorderedlistUnordered list
@aomao/plugin-imageImage
@aomao/plugin-tableTable
@aomao/plugin-fileFile
@aomao/plugin-mark-rangeMark range
@aomao/plugin-mathMathematical formula
@aomao/plugin-videoVideo

Getting Started

Installation

The editor consists of the engine, toolbar, and plugins. The engine provides us with the core editing capability.

Use npm or yarn to install the engine package.

$ npm install @aomao/engine
# or
$ yarn add @aomao/engine

Usage

We'll start by outputting a "Hello world!" message as usual.

importReact,{useEffect,useRef,useState}from'react';importEngine,{EngineInterface}from'@aomao/engine';constEngineDemo=()=>{//Editor containerconstref=useRef<HTMLDivElement|null>(null);//Engine instanceconst[engine,setEngine]=useState<EngineInterface>();//Editor contentconst[content,setContent]=useState<string>('<p>Hello world!</p>');useEffect(()=>{if(!ref.current)return;//Instantiate the engineconstengine=newEngine(ref.current);//Set the editor valueengine.setValue(content);//Listen to the editor value change eventengine.on('change',()=>{constvalue=engine.getValue();setContent(value);console.log(`value:${value}`);});//Set the engine instancesetEngine(engine);},[]);return<divref={ref}/>;};exportdefaultEngineDemo;

Plugins

Import the @aomao/plugin-bold bold plugin.

importBoldfrom'@aomao/plugin-bold';

Add the Bold plugin to the engine.

//Instantiate the engineconstengine=newEngine(ref.current,{plugins: [Bold],});

Card

A card is a separately defined area in the editor, with its UI and logic for rendering custom content inside the card using React, Vue, or other front-end libraries before being mounted onto the editor.

Introduce @aomao/plugin-codeblock, a code block plugin with a language drop-down that is rendered using React, which distinguishes it from Vue3 using @aomao/plugin-codeblock-vue.

importCodeBlock,{CodeBlockComponent}from'@aomao/plugin-codeblock';

Add the CodeBlock plugin and the CodeBlockComponent card component to the engine.

//Instantiate the engineconstengine=newEngine(ref.current,{plugins: [CodeBlock],cards: [CodeBlockComponent],});

The CodeBlock plugin supports markdown by default. You can trigger it by typing the code block syntax at the beginning of a line in the editor, followed by a space and the language name, such as ```javascript.

Node Constraints

To manage nodes more conveniently and reduce complexity, the editor abstracts node properties and functionality and defines four types of nodes: mark, inline, block, and card. They are composed of different attributes, styles, or HTML structures, and are uniformly constrained using a schema.

A simple schema looks like this:

{name:'p',// node nametype:'block'// node type}

In addition, properties, styles, etc. can also be described, for example:

{name:'span',// node nametype:'mark',// node typeattributes: {// The node has a style attributestyle: {// Must contain a color stylecolor: {required: true,// must containvalue:'@color'// The value is a color value that conforms to the css specification. @color is the color validation defined in the editor. Here, methods and regular expressions can also be used to determine whether the required rules are met}},// Optional include a test attribute, its value can be arbitrary, but it is not requiredtest:'*'}}

The following types of nodes conform to the above rules:

<spanstyle="color:#fff"></span><spanstyle="color:#fff" test="test123" test1="test1"></span><spanstyle="color:#fff;background-color:#000;"></span><spanstyle="color:#fff;background-color:#000;" test="test123"></span>

But except that color and test have been defined in schema, other attributes (background-color, test1) will be filtered out by the editor during processing.

The nodes in the editable area have four types of combined nodes of mark, inline, block, and cardthrough theschemarule. They are composed of different attributes, styles orhtml` structures. Certain constraints are imposed on nesting.

Toolbar

Import the @aomao/toolbar toolbar. Due to the complex interaction, the toolbar is basically rendered using React + Antd UI components, while Vue3 uses @aomao/toolbar-vue

Except for UI interaction, most of the work of the toolbar is just to call the engine to execute the corresponding plugin commands after different button events are triggered. In the case of complicated requirements or the need to re-customize the UI, it is easier to modify after the fork.

importToolbar,{ToolbarPlugin,ToolbarComponent}from'@aomao/toolbar';

Add the ToolbarPlugin plugin and ToolbarComponent card component to the engine, which allows us to use the shortcut key / in the editor to wake up the card toolbar

//Instantiate the engineconstengine=newEngine(ref.current,{plugins: [ToolbarPlugin],cards: [ToolbarComponent],});

Rendering toolbar, the toolbar has been configured with all plugins, here we only need to pass in the plugin name

return(
...
{
engine&&(<Toolbarengine={engine}items={[['collapse'],['bold',],]}/>)}
...
)

For more complex toolbar configuration, please check the document https://editor.aomao.com/config/toolbar

Collaborative Editing

This open-source library listens to changes in the HTML structure of the editing area (contenteditable root node), uses MutationObserver to reverse-engineer the data structure, and connects and interacts with Yjs through WebSocket to achieve multi-user collaborative editing.

Interactive mode

Each editor, as a client, communicates and interacts with the server through the WebSocket function in the @aomao/plugin-yjs-websocket plugin.

  • @aomao/yjs implements the conversion of editor and Yjs data
  • @aomao/plugin-yjs-websocket provides the WebSocket client function of the editor and Yjs
  • @aomao/plugin-yjs-websocket/server provides the WebSocket server of Yjs, written in Node.js, and supports data storage using MongoDB and LevelDB.

Project icon

Iconfont

Development

React

Before using this open-source library, you need to install dependencies in the project root directory.

yarn install
lerna bootstrap

After installing the dependencies, you only need to execute the following command in the root directory to start the project:

yarn start

The development directory structure of this open-source library is as follows:

  • packages contains the engine and toolbar-related code
  • plugins contains all plugins
  • api provides API access required by some plugins, and uses https://editor.aomao.com as the default API service
  • yjs-server contains collaborative server code, which can be started by yarn dev.

Vue

am-editor vue example

Contribution

Thanks pleasedmiElena211314zb201307cheon for donation

Alipay

alipay

WeChat Pay

wechat

PayPal

https://paypal.me/aomaocom

About

A rich text editor that supports collaborative editing and allows for the free use of front-end common libraries such as React and Vue to extend and define plugins.

Topics

Resources

Code of conduct

Stars

976 stars

Watchers

15 watching

Forks

Releases

Used by

Contributors

Languages