{"id":13514761,"url":"https://github.com/red-axe/am-editor","last_synced_at":"2026-03-06T20:04:21.769Z","repository":{"id":37297491,"uuid":"336297190","full_name":"red-axe/am-editor","owner":"red-axe","description":"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.","archived":false,"fork":false,"pushed_at":"2024-02-20T01:01:55.000Z","size":8032,"stargazers_count":977,"open_issues_count":63,"forks_count":202,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-12-12T15:54:12.504Z","etag":null,"topics":["am-editor","collaborative-editor","contenteditable","editor","javascript","react","react-editor","rich-text-editor","sharedb","text-editor","typescript","vue","vue-editor","wysiwyg","wysiwyg-editor"],"latest_commit_sha":null,"homepage":"https://editor.aomao.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/red-axe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-05T14:36:59.000Z","updated_at":"2025-11-06T11:42:43.000Z","dependencies_parsed_at":"2024-02-19T14:00:14.459Z","dependency_job_id":"c019eead-8e8d-421e-8600-285afd8c1305","html_url":"https://github.com/red-axe/am-editor","commit_stats":{"total_commits":1081,"total_committers":23,"mean_commits":47.0,"dds":0.3052728954671601,"last_synced_commit":"52398fc750df1770b60e78c9ddd4472ca98dc521"},"previous_names":["yanmao-cc/am-editor","itellyou-com/am-editor"],"tags_count":8889,"template":false,"template_full_name":null,"purl":"pkg:github/red-axe/am-editor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/red-axe%2Fam-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/red-axe%2Fam-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/red-axe%2Fam-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/red-axe%2Fam-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/red-axe","download_url":"https://codeload.github.com/red-axe/am-editor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/red-axe%2Fam-editor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30195571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["am-editor","collaborative-editor","contenteditable","editor","javascript","react","react-editor","rich-text-editor","sharedb","text-editor","typescript","vue","vue-editor","wysiwyg","wysiwyg-editor"],"created_at":"2024-08-01T05:01:01.419Z","updated_at":"2026-03-06T20:04:21.675Z","avatar_url":"https://github.com/red-axe.png","language":"TypeScript","readme":"\u003e Here, we have a new rich text editor called [Editable](https://github.com/editablejs/editable), which does not use the native editable property [~~contenteditable~~](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/contenteditable), but instead uses a custom renderer. This approach allows us to better control the behavior of the editor.\n\n# am-editor\n\n\u003cp align=\"center\"\u003e\n\tA rich text editor that supports collaborative editing, you can freely use React, Vue and other front-end common libraries to extend and define plugins.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ca href=\"https://editor.aomao.com\"\u003e\u003cstrong\u003ePreview\u003c/strong\u003e\u003c/a\u003e ·\n  \t\u003ca href=\"https://editor.aomao.com/docs\"\u003e\u003cstrong\u003eDocument\u003c/strong\u003e\u003c/a\u003e ·\n \t\u003ca href=\"plugins.md\"\u003e\u003cstrong\u003ePlugins\u003c/strong\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n    \u003ca href=\"README.zh-CN.md\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/lang-%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87-red.svg?longCache=true\u0026style=flat-square\"\u003e\n    \u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"./packages/engine/package.json\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/l/@aomao/engine\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://unpkg.com/@aomao/engine/dist/index.js\"\u003e\n    \u003cimg src=\"http://img.badgesize.io/https://unpkg.com/@aomao/engine/dist/index.js?compression=gzip\u0026amp;label=size\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"./packages/engine/package.json\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/@aomao/engine.svg?maxAge=3600\u0026label=version\u0026colorB=007ec6\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/@aomao/engine\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/dw/@aomao/engine\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/umijs/dumi\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/docs%20by-dumi-blue\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n[**`Vue2`**](https://github.com/zb201307/am-editor-vue2)\n\n[**`Vue3`**](https://github.com/red-axe/am-editor-vue3-demo)\n\n[**`React`** ](https://github.com/big-camel/am-editor/tree/master/examples/react)\n\n[**`Vue2 Demo`**](https://github.com/big-camel/am-editor-demo-vue2)\n\n[**`Vue2 Nuxt Demo`**](https://github.com/big-camel/am-editor-nuxt)\n\n## Features\n\n-   🎁 Out-of-the-box solution with dozens of rich plugins to meet most needs\n-   🚀 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\n-   🎨 Rich multimedia support, not only supports images and audio/video, but also supports embedding multimedia content\n-   📝 Supports Markdown syntax\n-   🌍 Supports internationalization\n-   💻 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\n-   👥 Built-in collaborative editing solution, lightweight configuration to use\n-   📱 Compatible with most latest mobile browsers\n\n## Plugins\n\n| **Package**                                                                                           |                                                                                                                                                                             **Version** |                                                                                                                                                                           **Size** | **description**                 |\n| :---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------ |\n| [`@aomao/toolbar`](./packages/toolbar)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/toolbar.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./packages/toolbar/package.json) |                           [![](http://img.badgesize.io/https://unpkg.com/@aomao/toolbar/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/toolbar/dist/index.js) | Toolbar, suitable for `React`   |\n| [`@aomao/toolbar-vue`](./packages/toolbar-vue)                                                        |                                                        [![](https://img.shields.io/npm/v/@aomao/toolbar-vue.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./packages/toolbar-vue/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/toolbar-vue/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/toolbar-vue/dist/index.js) | Toolbar, suitable for `Vue3`    |\n| [`am-editor-toolbar-vue2`](https://github.com/zb201307/am-editor-vue2/tree/main/packages/toolbar)     |     [![](https://img.shields.io/npm/v/am-editor-toolbar-vue2.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](https://github.com/zb201307/am-editor-vue2/blob/main/packages/toolbar/package.json) |           [![](http://img.badgesize.io/https://unpkg.com/am-editor-toolbar-vue2/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/am-editor-toolbar-vue2/dist/index.js) | Toolbar, suitable for `Vue2`    |\n| [`@aomao/plugin-alignment`](./plugins/alignment)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-alignment.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/alignment/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-alignment/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-alignment/dist/index.js) | Alignment                       |\n| [`@aomao/plugin-embed`](./plugins/embed)                                                              |                                                              [![](https://img.shields.io/npm/v/@aomao/plugin-embed.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/embed/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-embed/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-embed/dist/index.js) | Embed URL                       |\n| [`@aomao/plugin-backcolor`](./plugins/backcolor)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-backcolor.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/backcolor/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-backcolor/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-backcolor/dist/index.js) | Background color                |\n| [`@aomao/plugin-bold`](./plugins/bold)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-bold.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/bold/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-bold/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-bold/dist/index.js) | Bold                            |\n| [`@aomao/plugin-code`](./plugins/code)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-code.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/code/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-code/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-code/dist/index.js) | Inline code                     |\n| [`@aomao/plugin-codeblock`](./plugins/codeblock)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-codeblock.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/codeblock/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-codeblock/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-codeblock/dist/index.js) | CodeBlock, suitable for `React` |\n| [`@aomao/plugin-codeblock-vue`](./plugins/codeblock-vue)                                              |                                              [![](https://img.shields.io/npm/v/@aomao/plugin-codeblock-vue.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/codeblock-vue/package.json) | [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-codeblock-vue/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-codeblock-vue/dist/index.js) | CodeBlock, suitable for `Vue3`  |\n| [`am-editor-codeblock-vue2`](https://github.com/zb201307/am-editor-vue2/tree/main/packages/codeblock) | [![](https://img.shields.io/npm/v/am-editor-codeblock-vue2.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](https://github.com/zb201307/am-editor-vue2/tree/main/packages/codeblock/package.json) |       [![](http://img.badgesize.io/https://unpkg.com/am-editor-codeblock-vue2/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/am-editor-codeblock-vue2/dist/index.js) | CodeBlock, suitable for `Vue2`  |\n| [`@aomao/plugin-fontcolor`](./plugins/fontcolor)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-fontcolor.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/fontcolor/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-fontcolor/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-fontcolor/dist/index.js) | Font color                      |\n| [`@aomao/plugin-fontfamily`](./plugins/fontfamily)                                                    |                                                    [![](https://img.shields.io/npm/v/@aomao/plugin-fontfamily.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/fontfamily/package.json) |       [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-fontfamily/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-fontfamily/dist/index.js) | Font Family                     |\n| [`@aomao/plugin-fontsize`](./plugins/fontsize)                                                        |                                                        [![](https://img.shields.io/npm/v/@aomao/plugin-fontsize.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/fontsize/package.json) |           [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-fontsize/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-fontsize/dist/index.js) | Font Size                       |\n| [`@aomao/plugin-heading`](./plugins/heading)                                                          |                                                          [![](https://img.shields.io/npm/v/@aomao/plugin-heading.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/heading/package.json) |             [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-heading/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-heading/dist/index.js) | Heading                         |\n| [`@aomao/plugin-hr`](./plugins/hr)                                                                    |                                                                    [![](https://img.shields.io/npm/v/@aomao/plugin-hr.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/hr/package.json) |                       [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-hr/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-hr/dist/index.js) | Horizontal rule                 |\n| [`@aomao/plugin-indent`](./plugins/indent)                                                            |                                                            [![](https://img.shields.io/npm/v/@aomao/plugin-indent.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/indent/package.json) |               [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-indent/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-indent/dist/index.js) | Indentation                     |\n| [`@aomao/plugin-italic`](./plugins/italic)                                                            |                                                            [![](https://img.shields.io/npm/v/@aomao/plugin-italic.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/italic/package.json) |               [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-italic/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-italic/dist/index.js) | Italic                          |\n| [`@aomao/plugin-link`](./plugins/link)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-link.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/link/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-link/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-link/dist/index.js) | Link, suitable for `React`      |\n| [`@aomao/plugin-link-vue`](./plugins/link-vue)                                                        |                                                        [![](https://img.shields.io/npm/v/@aomao/plugin-link-vue.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/link-vue/package.json) |           [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-link-vue/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-link-vue/dist/index.js) | Link, suitable for `Vue3`       |\n| [`am-editor-link-vue2`](https://github.com/zb201307/am-editor-vue2/tree/main/packages/link)           |           [![](https://img.shields.io/npm/v/am-editor-link-vue2.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](https://github.com/zb201307/am-editor-vue2/tree/main/packages/link/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/am-editor-link-vue2/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/am-editor-link-vue2/dist/index.js) | Link, suitable for `Vue2`       |\n| [`@aomao/plugin-line-height`](./plugins/line-height)                                                  |                                                  [![](https://img.shields.io/npm/v/@aomao/plugin-line-height.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/line-height/package.json) |     [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-line-height/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-line-height/dist/index.js) | Line height                     |\n| [`@aomao/plugin-mark`](./plugins/mark)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-mark.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/mark/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-mark/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-mark/dist/index.js) | Mark                            |\n| [`@aomao/plugin-mention`](./plugins/mention)                                                          |                                                          [![](https://img.shields.io/npm/v/@aomao/plugin-mention.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/mention/package.json) |             [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-mention/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-mention/dist/index.js) | Mention                         |\n| [`@aomao/plugin-orderedlist`](./plugins/orderedlist)                                                  |                                                  [![](https://img.shields.io/npm/v/@aomao/plugin-orderedlist.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/orderedlist/package.json) |     [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-orderedlist/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-orderedlist/dist/index.js) | Ordered list                    |\n| [`@aomao/plugin-paintformat`](./plugins/paintformat)                                                  |                                                  [![](https://img.shields.io/npm/v/@aomao/plugin-paintformat.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/paintformat/package.json) |     [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-paintformat/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-paintformat/dist/index.js) | Format painter                  |\n| [`@aomao/plugin-quote`](./plugins/quote)                                                              |                                                              [![](https://img.shields.io/npm/v/@aomao/plugin-quote.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/quote/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-quote/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-quote/dist/index.js) | Blockquote                      |\n| [`@aomao/plugin-redo`](./plugins/redo)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-redo.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/redo/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-redo/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-redo/dist/index.js) | Redo                            |\n| [`@aomao/plugin-removeformat`](./plugins/removeformat)                                                |                                                [![](https://img.shields.io/npm/v/@aomao/plugin-removeformat.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/removeformat/package.json) |   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-removeformat/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-removeformat/dist/index.js) | Remove format                   |\n| [`@aomao/plugin-selectall`](./plugins/selectall)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-selectall.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/selectall/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-selectall/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-selectall/dist/index.js) | Select all                      |\n| [`@aomao/plugin-status`](./plugins/status)                                                            |                                                            [![](https://img.shields.io/npm/v/@aomao/plugin-status.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/status/package.json) |               [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-status/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-status/dist/index.js) | Status                          |\n| [`@aomao/plugin-strikethrough`](./plugins/strikethrough)                                              |                                              [![](https://img.shields.io/npm/v/@aomao/plugin-strikethrough.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/strikethrough/package.json) | [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-strikethrough/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-strikethrough/dist/index.js) | Strikethrough                   |\n| [`@aomao/plugin-sub`](./plugins/sub)                                                                  |                                                                  [![](https://img.shields.io/npm/v/@aomao/plugin-sub.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/sub/package.json) |                     [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-sub/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-sub/dist/index.js) | Sub                             |\n| [`@aomao/plugin-sup`](./plugins/sup)                                                                  |                                                                  [![](https://img.shields.io/npm/v/@aomao/plugin-sup.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/sup/package.json) |                     [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-sup/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-sup/dist/index.js) | Sup                             |\n| [`@aomao/plugin-tasklist`](./plugins/tasklist)                                                        |                                                        [![](https://img.shields.io/npm/v/@aomao/plugin-tasklist.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/tasklist/package.json) |           [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-tasklist/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-tasklist/dist/index.js) | Task list                       |\n| [`@aomao/plugin-underline`](./plugins/underline)                                                      |                                                      [![](https://img.shields.io/npm/v/@aomao/plugin-underline.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/underline/package.json) |         [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-underline/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-underline/dist/index.js) | Underline                       |\n| [`@aomao/plugin-undo`](./plugins/undo)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-undo.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/undo/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-undo/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-undo/dist/index.js) | Undo                            |\n| [`@aomao/plugin-unorderedlist`](./plugins/unorderedlist)                                              |                                              [![](https://img.shields.io/npm/v/@aomao/plugin-unorderedlist.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/unorderedlist/package.json) | [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-unorderedlist/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-unorderedlist/dist/index.js) | Unordered list                  |\n| [`@aomao/plugin-image`](./plugins/image)                                                              |                                                              [![](https://img.shields.io/npm/v/@aomao/plugin-image.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/image/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-image/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-image/dist/index.js) | Image                           |\n| [`@aomao/plugin-table`](./plugins/table)                                                              |                                                              [![](https://img.shields.io/npm/v/@aomao/plugin-table.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/table/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-table/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-table/dist/index.js) | Table                           |\n| [`@aomao/plugin-file`](./plugins/file)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-file.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/file/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-file/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-file/dist/index.js) | File                            |\n| [`@aomao/plugin-mark-range`](./plugins/mark-range)                                                    |                                                    [![](https://img.shields.io/npm/v/@aomao/plugin-mark-range.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/mark-range/package.json) |       [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-mark-range/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-mark-range/dist/index.js) | Mark range                      |\n| [`@aomao/plugin-math`](./plugins/math)                                                                |                                                                [![](https://img.shields.io/npm/v/@aomao/plugin-math.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/math/package.json) |                   [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-math/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-math/dist/index.js) | Mathematical formula            |\n| [`@aomao/plugin-video`](./plugins/video)                                                              |                                                              [![](https://img.shields.io/npm/v/@aomao/plugin-video.svg?maxAge=3600\u0026label=\u0026colorB=007ec6)](./plugins/video/package.json) |                 [![](http://img.badgesize.io/https://unpkg.com/@aomao/plugin-video/dist/index.js?compression=gzip\u0026label=%20)](https://unpkg.com/@aomao/plugin-video/dist/index.js) | Video                           |\n\n## Getting Started\n\n### Installation\n\nThe editor consists of the `engine`, `toolbar`, and `plugins`. The `engine` provides us with the core editing capability.\n\nUse `npm` or `yarn` to install the engine package.\n\n```bash\n$ npm install @aomao/engine\n# or\n$ yarn add @aomao/engine\n```\n\n### Usage\n\nWe'll start by outputting a \"Hello world!\" message as usual.\n\n```tsx\nimport React, { useEffect, useRef, useState } from 'react';\nimport Engine, { EngineInterface } from '@aomao/engine';\n\nconst EngineDemo = () =\u003e {\n\t//Editor container\n\tconst ref = useRef\u003cHTMLDivElement | null\u003e(null);\n\t//Engine instance\n\tconst [engine, setEngine] = useState\u003cEngineInterface\u003e();\n\t//Editor content\n\tconst [content, setContent] = useState\u003cstring\u003e('\u003cp\u003eHello world!\u003c/p\u003e');\n\n\tuseEffect(() =\u003e {\n\t\tif (!ref.current) return;\n\t\t//Instantiate the engine\n\t\tconst engine = new Engine(ref.current);\n\t\t//Set the editor value\n\t\tengine.setValue(content);\n\t\t//Listen to the editor value change event\n\t\tengine.on('change', () =\u003e {\n\t\t\tconst value = engine.getValue();\n\t\t\tsetContent(value);\n\t\t\tconsole.log(`value:${value}`);\n\t\t});\n\t\t//Set the engine instance\n\t\tsetEngine(engine);\n\t}, []);\n\n\treturn \u003cdiv ref={ref} /\u003e;\n};\nexport default EngineDemo;\n```\n\n### Plugins\n\nImport the `@aomao/plugin-bold` bold plugin.\n\n```tsx\nimport Bold from '@aomao/plugin-bold';\n```\n\nAdd the `Bold` plugin to the engine.\n\n```tsx\n//Instantiate the engine\nconst engine = new Engine(ref.current, {\n\tplugins: [Bold],\n});\n```\n\n### Card\n\nA 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.\n\nIntroduce `@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`.\n\n```tsx\nimport CodeBlock, { CodeBlockComponent } from '@aomao/plugin-codeblock';\n```\n\nAdd the `CodeBlock` plugin and the `CodeBlockComponent` card component to the engine.\n\n```tsx\n//Instantiate the engine\nconst engine = new Engine(ref.current, {\n\tplugins: [CodeBlock],\n\tcards: [CodeBlockComponent],\n});\n```\n\nThe `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.\n\n## Node Constraints\n\nTo 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.\n\nA simple `schema` looks like this:\n\n```ts\n{\n  name:'p', // node name\n  type:'block' // node type\n}\n```\n\nIn addition, properties, styles, etc. can also be described, for example:\n\n```ts\n{\n  name:'span', // node name\n  type:'mark', // node type\n  attributes: {\n    // The node has a style attribute\n    style: {\n      // Must contain a color style\n      color: {\n        required: true, // must contain\n        value:'@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\n      }\n    },\n    // Optional include a test attribute, its value can be arbitrary, but it is not required\n    test:'*'\n  }\n}\n```\n\nThe following types of nodes conform to the above rules:\n\n```html\n\u003cspan style=\"color:#fff\"\u003e\u003c/span\u003e\n\u003cspan style=\"color:#fff\" test=\"test123\" test1=\"test1\"\u003e\u003c/span\u003e\n\u003cspan style=\"color:#fff;background-color:#000;\"\u003e\u003c/span\u003e\n\u003cspan style=\"color:#fff;background-color:#000;\" test=\"test123\"\u003e\u003c/span\u003e\n```\n\nBut except that color and test have been defined in `schema`, other attributes (background-color, test1) will be filtered out by the editor during processing.\n\nThe nodes in the editable area have four types of combined nodes of `mark`, `inline`, block`, and `card`through the`schema`rule. They are composed of different attributes, styles or`html` structures. Certain constraints are imposed on nesting.\n\n### Toolbar\n\nImport 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`\n\nExcept 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.\n\n```tsx\nimport Toolbar, { ToolbarPlugin, ToolbarComponent } from '@aomao/toolbar';\n```\n\nAdd 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\n\n```tsx\n//Instantiate the engine\nconst engine = new Engine(ref.current, {\n\tplugins: [ToolbarPlugin],\n\tcards: [ToolbarComponent],\n});\n```\n\nRendering toolbar, the toolbar has been configured with all plugins, here we only need to pass in the plugin name\n\n```tsx\nreturn (\n    ...\n    {\n        engine \u0026\u0026 (\n            \u003cToolbar\n                engine={engine}\n                items={[\n                    ['collapse'],\n                    [\n                        'bold',\n                    ],\n                ]}\n            /\u003e\n        )\n    }\n    ...\n)\n```\n\nFor more complex toolbar configuration, please check the document [https://editor.aomao.com/config/toolbar](https://editor.aomao.com/config/toolbar)\n\n### Collaborative Editing\n\nThis 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](https://github.com/yjs/yjs) through `WebSocket` to achieve multi-user collaborative editing.\n\n#### Interactive mode\n\nEach editor, as a [client](https://github.com/red-axe/am-editor/blob/master/examples/react/components/editor/index.tsx#L250), communicates and interacts with the [server](https://github.com/big-camel/am-editor/tree/master/yjs-server) through the `WebSocket` function in the `@aomao/plugin-yjs-websocket` plugin.\n\n-   `@aomao/yjs` implements the conversion of editor and `Yjs` data\n-   `@aomao/plugin-yjs-websocket` provides the `WebSocket` client function of the editor and `Yjs`\n-   `@aomao/plugin-yjs-websocket/server` provides the `WebSocket` server of `Yjs`, written in Node.js, and supports data storage using `MongoDB` and `LevelDB`.\n\n### Project icon\n\n[Iconfont](https://at.alicdn.com/t/project/1456030/0cbd04d3-3ca1-4898-b345-e0a9150fcc80.html?spm=a313x.7781069.1998910419.35)\n\n## Development\n\n### React\n\nBefore using this open-source library, you need to install dependencies in the project root directory.\n\n```base\nyarn install\n\nlerna bootstrap\n```\n\nAfter installing the dependencies, you only need to execute the following command in the root directory to start the project:\n\n```base\nyarn start\n```\n\nThe development directory structure of this open-source library is as follows:\n\n-   `packages` contains the engine and toolbar-related code\n-   `plugins` contains all plugins\n-   `api` provides API access required by some plugins, and uses https://editor.aomao.com as the default API service\n-   `yjs-server` contains collaborative server code, which can be started by `yarn dev`.\n\n### Vue\n\n[am-editor vue example](https://github.com/red-axe/am-editor-vue3-demo)\n\n## Contribution\n\nThanks [pleasedmi](https://github.com/pleasedmi)、[Elena211314](https://github.com/Elena211314)、[zb201307](https://github.com/zb201307)、[cheon](https://github.com/number317) for donation\n\n### Alipay\n\n![alipay](https://cdn-object.aomao.com/contribution/alipay.png?x-oss-process=image/resize,w_200)\n\n### WeChat Pay\n\n![wechat](https://cdn-object.aomao.com/contribution/weichat.png?x-oss-process=image/resize,w_200)\n\n### PayPal\n\n[https://paypal.me/aomaocom](https://paypal.me/aomaocom)\n","funding_links":["https://paypal.me/aomaocom"],"categories":["Rich text editor"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fred-axe%2Fam-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fred-axe%2Fam-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fred-axe%2Fam-editor/lists"}