├── .npmignore ├── packages ├── list-module │ ├── src │ │ ├── assets │ │ │ └── index.less │ │ ├── locale │ │ │ ├── zh-CN.ts │ │ │ ├── en.ts │ │ │ └── index.ts │ │ ├── utils │ │ │ └── maps.ts │ │ ├── index.ts │ │ ├── module │ │ │ ├── custom-types.ts │ │ │ ├── menu │ │ │ │ ├── BulletedListMenu.ts │ │ │ │ ├── NumberedListMenu.ts │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ └── constants │ │ │ └── svg.ts │ ├── README.md │ ├── tsconfig.json │ ├── rollup.config.js │ └── CHANGELOG.md ├── basic-modules │ ├── src │ │ ├── modules │ │ │ ├── divider │ │ │ │ ├── README.md │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ ├── parse-elem-html.ts │ │ │ │ └── index.ts │ │ │ ├── line-height │ │ │ │ ├── menu │ │ │ │ │ ├── config.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── custom-types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── style-to-html.ts │ │ │ │ ├── render-style.tsx │ │ │ │ └── parse-style-html.ts │ │ │ ├── color │ │ │ │ ├── custom-types.ts │ │ │ │ ├── menu │ │ │ │ │ ├── ColorMenu.ts │ │ │ │ │ ├── BgColorMenu.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── pre-parse-html.ts │ │ │ │ ├── render-style.tsx │ │ │ │ └── parse-style-html.ts │ │ │ ├── todo │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── index.ts │ │ │ │ └── plugin.ts │ │ │ ├── common │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ │ ├── full-screen │ │ │ │ ├── menu │ │ │ │ │ ├── index.ts │ │ │ │ │ └── FullScreen.ts │ │ │ │ └── index.ts │ │ │ ├── font-size-family │ │ │ │ ├── custom-types.ts │ │ │ │ ├── index.ts │ │ │ │ ├── render-style.tsx │ │ │ │ └── menu │ │ │ │ │ └── index.ts │ │ │ ├── paragraph │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── render-elem.tsx │ │ │ │ └── parse-elem-html.ts │ │ │ ├── blockquote │ │ │ │ ├── custom-types.ts │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── render-elem.tsx │ │ │ │ └── parse-elem-html.ts │ │ │ ├── code-block │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── pre-parse-html.ts │ │ │ │ ├── render-elem.tsx │ │ │ │ └── index.ts │ │ │ ├── indent │ │ │ │ ├── custom-types.ts │ │ │ │ ├── menu │ │ │ │ │ └── index.ts │ │ │ │ ├── style-to-html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── render-style.tsx │ │ │ │ ├── parse-style-html.ts │ │ │ │ └── pre-parse-html.ts │ │ │ ├── justify │ │ │ │ ├── custom-types.ts │ │ │ │ ├── style-to-html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── parse-style-html.ts │ │ │ │ ├── menu │ │ │ │ │ ├── JustifyLeftMenu.ts │ │ │ │ │ ├── JustifyJustifyMenu.ts │ │ │ │ │ ├── JustifyRightMenu.ts │ │ │ │ │ ├── JustifyCenterMenu.ts │ │ │ │ │ └── index.ts │ │ │ │ └── render-style.tsx │ │ │ ├── emotion │ │ │ │ ├── index.ts │ │ │ │ └── menu │ │ │ │ │ ├── config.ts │ │ │ │ │ └── index.ts │ │ │ ├── link │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── menu │ │ │ │ │ └── config.ts │ │ │ │ ├── index.ts │ │ │ │ ├── render-elem.tsx │ │ │ │ └── parse-elem-html.ts │ │ │ ├── header │ │ │ │ ├── menu │ │ │ │ │ ├── Header1ButtonMenu.ts │ │ │ │ │ ├── Header2ButtonMenu.ts │ │ │ │ │ ├── Header3ButtonMenu.ts │ │ │ │ │ ├── Header4ButtonMenu.ts │ │ │ │ │ └── Header5ButtonMenu.ts │ │ │ │ ├── custom-types.ts │ │ │ │ └── elem-to-html.ts │ │ │ ├── image │ │ │ │ ├── menu │ │ │ │ │ ├── Width30.ts │ │ │ │ │ ├── Width50.ts │ │ │ │ │ └── Width100.ts │ │ │ │ ├── custom-types.ts │ │ │ │ ├── elem-to-html.ts │ │ │ │ ├── plugin.ts │ │ │ │ ├── parse-elem-html.ts │ │ │ │ └── index.ts │ │ │ ├── undo-redo │ │ │ │ ├── index.ts │ │ │ │ └── menu │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── RedoMenu.ts │ │ │ │ │ └── UndoMenu.ts │ │ │ └── text-style │ │ │ │ ├── custom-types.ts │ │ │ │ ├── menu │ │ │ │ ├── BoldMenu.ts │ │ │ │ ├── CodeMenu.ts │ │ │ │ ├── ItalicMenu.ts │ │ │ │ ├── ThroughMenu.ts │ │ │ │ ├── UnderlineMenu.ts │ │ │ │ ├── SubMenu.ts │ │ │ │ └── SupMenu.ts │ │ │ │ ├── index.ts │ │ │ │ └── helper.ts │ │ ├── assets │ │ │ ├── index.less │ │ │ ├── simple-style.less │ │ │ ├── code-block.less │ │ │ ├── blockquote.less │ │ │ ├── divider.less │ │ │ ├── emotion.less │ │ │ └── color.less │ │ ├── locale │ │ │ └── index.ts │ │ └── utils │ │ │ ├── util.ts │ │ │ └── vdom.ts │ ├── README.md │ ├── tsconfig.json │ ├── __tests__ │ │ ├── divider │ │ │ ├── elem-to-html.test.ts │ │ │ └── parse-html.test.ts │ │ ├── justify │ │ │ ├── text-style-to-html.test.ts │ │ │ ├── render-text-style.test.tsx │ │ │ └── parse-html.test.ts │ │ ├── indent │ │ │ ├── text-style-to-html.test.ts │ │ │ └── render-text-style.test.tsx │ │ ├── line-height │ │ │ ├── text-style-to-html.test.ts │ │ │ ├── render-text-style.test.tsx │ │ │ └── parse-html.test.ts │ │ ├── blockquote │ │ │ ├── elem-to-html.test.ts │ │ │ └── render-elem.test.ts │ │ ├── image │ │ │ ├── plugin.test.ts │ │ │ ├── elem-to-html.test.ts │ │ │ └── parse-html.test.ts │ │ ├── color │ │ │ ├── text-style-to-html.test.ts │ │ │ └── render-text-style.test.tsx │ │ ├── link │ │ │ ├── elem-to-html.test.ts │ │ │ └── render-elem.test.ts │ │ ├── paragraph │ │ │ ├── render-elem.test.ts │ │ │ └── elem-to-html.test.ts │ │ ├── font-size-family │ │ │ ├── text-style-to-html.test.ts │ │ │ └── render-text-style.test.tsx │ │ ├── full-screen │ │ │ └── full-screen-menu.test.ts │ │ ├── header │ │ │ └── plugin.test.ts │ │ ├── code-block │ │ │ ├── elem-to-html.test.ts │ │ │ └── render-elem.test.ts │ │ ├── todo │ │ │ ├── plugin.test.ts │ │ │ ├── pre-parse-html.test.ts │ │ │ ├── elem-to-html.test.ts │ │ │ └── render-elem.test.ts │ │ └── text-style │ │ │ ├── parse-html.test.ts │ │ │ ├── text-to-html.test.ts │ │ │ └── menu │ │ │ └── clear-style-menu.test.ts │ └── rollup.config.js ├── upload-image-module │ ├── src │ │ ├── assets │ │ │ └── index.less │ │ ├── locale │ │ │ ├── zh-CN.ts │ │ │ ├── en.ts │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── utils │ │ │ └── dom.ts │ │ └── module │ │ │ ├── index.ts │ │ │ └── menu │ │ │ └── index.ts │ ├── README.md │ ├── tsconfig.json │ └── rollup.config.js ├── core │ ├── src │ │ ├── to-html │ │ │ ├── README.md │ │ │ └── node2html.ts │ │ ├── render │ │ │ ├── README.md │ │ │ ├── helper.ts │ │ │ ├── element │ │ │ │ ├── renderStyle.ts │ │ │ │ └── getRenderElem.tsx │ │ │ ├── text │ │ │ │ └── renderStyle.ts │ │ │ └── node2Vnode.ts │ │ ├── parse-html │ │ │ ├── README.md │ │ │ └── helper.ts │ │ ├── menus │ │ │ ├── README.md │ │ │ ├── bar-item │ │ │ │ ├── SimpleButton.ts │ │ │ │ └── tooltip.ts │ │ │ ├── index.ts │ │ │ ├── panel-and-modal │ │ │ │ └── DropPanel.ts │ │ │ ├── helpers │ │ │ │ └── helpers.ts │ │ │ └── register.ts │ │ ├── assets │ │ │ ├── progress.less │ │ │ ├── index.less │ │ │ ├── common.less │ │ │ ├── drop-panel.less │ │ │ ├── full-screen.less │ │ │ └── bar.less │ │ ├── constants │ │ │ └── index.ts │ │ ├── create │ │ │ └── index.ts │ │ ├── upload │ │ │ ├── index.ts │ │ │ └── interface.ts │ │ ├── utils │ │ │ └── key.ts │ │ ├── config │ │ │ └── register.ts │ │ ├── text-area │ │ │ └── event-handlers │ │ │ │ ├── copy.ts │ │ │ │ ├── focus.ts │ │ │ │ └── keypress.ts │ │ └── i18n │ │ │ └── index.ts │ ├── __tests__ │ │ ├── menus │ │ │ ├── README.md │ │ │ └── register-menus │ │ │ │ ├── index.ts │ │ │ │ ├── register-button-menu.ts │ │ │ │ ├── register-select-menu.ts │ │ │ │ └── register-modal-menu.ts │ │ ├── render │ │ │ └── README.md │ │ ├── parse-html │ │ │ └── README.md │ │ ├── to-html │ │ │ └── README.md │ │ ├── create-core-editor.ts │ │ ├── i18n │ │ │ └── index.test.ts │ │ └── config │ │ │ └── menu-config.test.ts │ ├── tsconfig.json │ ├── README.md │ └── rollup.config.js ├── editor │ ├── examples │ │ ├── README.md │ │ └── css │ │ │ ├── editor.css │ │ │ └── view.css │ ├── favicon.ico │ ├── demo │ │ ├── README.md │ │ └── css │ │ │ └── layout.css │ ├── tsconfig.json │ ├── src │ │ ├── utils │ │ │ └── dom.ts │ │ ├── locale │ │ │ ├── zh-CN.ts │ │ │ ├── en.ts │ │ │ └── index.ts │ │ ├── init-default-config │ │ │ ├── config │ │ │ │ └── index.ts │ │ │ └── index.ts │ │ └── assets │ │ │ └── index.less │ ├── README.md │ ├── README-en.md │ └── rollup.config.js ├── table-module │ ├── README.md │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ ├── locale │ │ │ ├── index.ts │ │ │ ├── zh-CN.ts │ │ │ └── en.ts │ │ ├── utils │ │ │ └── util.ts │ │ └── module │ │ │ ├── render-elem │ │ │ ├── render-row.tsx │ │ │ └── index.ts │ │ │ ├── custom-types.ts │ │ │ └── pre-parse-html.ts │ └── rollup.config.js ├── video-module │ ├── README.md │ ├── tsconfig.json │ ├── src │ │ ├── index.ts │ │ ├── locale │ │ │ ├── index.ts │ │ │ ├── zh-CN.ts │ │ │ └── en.ts │ │ ├── module │ │ │ ├── custom-types.ts │ │ │ ├── index.ts │ │ │ └── elem-to-html.ts │ │ ├── utils │ │ │ └── util.ts │ │ └── assets │ │ │ └── index.less │ ├── rollup.config.js │ └── __tests__ │ │ ├── util.test.ts │ │ └── render-elem.test.ts └── code-highlight │ ├── README.md │ ├── tsconfig.json │ ├── src │ ├── locale │ │ ├── en.ts │ │ ├── zh-CN.ts │ │ └── index.ts │ ├── index.ts │ ├── module │ │ ├── menu │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── elem-to-html.ts │ │ ├── render-style.tsx │ │ └── parse-style-html.ts │ ├── custom-types.ts │ ├── utils │ │ ├── dom.ts │ │ └── vdom.ts │ └── constants │ │ └── svg.ts │ ├── rollup.config.js │ └── __tests__ │ ├── render-text-style.test.tsx │ ├── decorate.test.ts │ ├── content.ts │ └── elem-to-html.test.ts ├── cypress ├── support │ ├── index.ts │ └── commands.ts ├── fixtures │ └── example.json ├── integration │ └── editor.spec.ts ├── cypress.d.ts ├── tsconfig.json └── plugins │ └── index.ts ├── .yarnrc ├── tests ├── utils │ ├── stylesMock.js │ ├── create-toolbar.ts │ └── create-editor.ts └── setup │ └── index.ts ├── .eslintignore ├── .browserslistrc ├── docs ├── README.md ├── images │ ├── cypress.jpg │ ├── editor.png │ ├── editor-en.png │ └── cypress-run.jpg ├── join.md └── dev.md ├── cypress.json ├── commitlint.config.js ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── feature.md │ ├── question.md │ └── bug.md ├── README.md ├── CHANGELOG.md ├── babel.config.json ├── README-en.md ├── .prettierrc.js ├── scripts └── release-tag.js ├── tsconfig.json ├── jest.config.js ├── .eslintrc.js └── lerna.json /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | .vscode 3 | -------------------------------------------------------------------------------- /packages/list-module/src/assets/index.less: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cypress/support/index.ts: -------------------------------------------------------------------------------- 1 | import './commands' 2 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npm.taobao.org" -------------------------------------------------------------------------------- /tests/utils/stylesMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | dist/ 3 | lib/ 4 | *.html -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/divider/README.md: -------------------------------------------------------------------------------- 1 | # 分割线 -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | not IE 11 3 | maintained node versions -------------------------------------------------------------------------------- /packages/upload-image-module/src/assets/index.less: -------------------------------------------------------------------------------- 1 | // styles 2 | -------------------------------------------------------------------------------- /packages/core/src/to-html/README.md: -------------------------------------------------------------------------------- 1 | # to html 2 | 3 | 把 content 为 html 4 | -------------------------------------------------------------------------------- /packages/core/src/render/README.md: -------------------------------------------------------------------------------- 1 | # render 2 | 3 | 把 JSON content 转换为 vdom 4 | -------------------------------------------------------------------------------- /packages/core/src/parse-html/README.md: -------------------------------------------------------------------------------- 1 | # parse html 2 | 3 | 把 html 转换为 JSON content 4 | -------------------------------------------------------------------------------- /packages/editor/examples/README.md: -------------------------------------------------------------------------------- 1 | # examples 2 | 3 | - 本地测试 4 | - 提交 `master` 会发布到测试机 5 | -------------------------------------------------------------------------------- /packages/core/__tests__/menus/README.md: -------------------------------------------------------------------------------- 1 | # menus test 2 | 3 | TODO 各个 modules 中没有这块代码的测试,待编写... 4 | -------------------------------------------------------------------------------- /packages/core/__tests__/render/README.md: -------------------------------------------------------------------------------- 1 | # render test 2 | 3 | 各个 module `renderElem` 已经测试了该模块的代码。 4 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 文档 2 | 3 | - [开发文档](./dev.md) 4 | - [发布到 npm](./publish.md) 5 | - [加入研发团队](./join.md) 6 | -------------------------------------------------------------------------------- /docs/images/cypress.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowerskitchen/wangEditor/HEAD/docs/images/cypress.jpg -------------------------------------------------------------------------------- /docs/images/editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowerskitchen/wangEditor/HEAD/docs/images/editor.png -------------------------------------------------------------------------------- /docs/images/editor-en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowerskitchen/wangEditor/HEAD/docs/images/editor-en.png -------------------------------------------------------------------------------- /packages/core/__tests__/parse-html/README.md: -------------------------------------------------------------------------------- 1 | # parse-html test 2 | 3 | 各个 module `parseHtml` 已经测试了该模块的代码。 4 | -------------------------------------------------------------------------------- /docs/images/cypress-run.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowerskitchen/wangEditor/HEAD/docs/images/cypress-run.jpg -------------------------------------------------------------------------------- /packages/core/__tests__/to-html/README.md: -------------------------------------------------------------------------------- 1 | # to-html test 2 | 3 | 各个 module 中的 `editor.getHtml()` API 会测试到这部分代码。 4 | -------------------------------------------------------------------------------- /packages/editor/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flowerskitchen/wangEditor/HEAD/packages/editor/favicon.ico -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8881", 3 | "defaultCommandTimeout": 8000, 4 | "video": false 5 | } -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['cz'], 3 | rules: { 4 | 'type-empty': [2, 'never'], 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /packages/editor/demo/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor demo 2 | 3 | 修改左侧目录,在 demo 目录搜索 `MENU_CONF` 4 | 5 | demo 部署参考 `deploy-demos.yml` 配置 6 | -------------------------------------------------------------------------------- /packages/list-module/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor list-module 2 | 3 | List module built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | Cypress.Commands.add('getByClass', (selector, ...args) => { 2 | return cy.get(`.w-e-${selector}`, ...args) 3 | }) 4 | -------------------------------------------------------------------------------- /packages/table-module/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor table-module 2 | 3 | Table module built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /packages/video-module/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor video-module 2 | 3 | Video module built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /packages/basic-modules/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor basic-modules 2 | 3 | Basic modules built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /packages/core/src/menus/README.md: -------------------------------------------------------------------------------- 1 | # menus 2 | 3 | 统一注册 menu ,menu 支持 4 | - classic toolbar 5 | - hovering toolbar 6 | - tooltip 7 | - contextMenu 8 | -------------------------------------------------------------------------------- /packages/editor/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": [ 4 | "./src/**/*", 5 | "../custom-types.d.ts" 6 | ] 7 | } -------------------------------------------------------------------------------- /packages/code-highlight/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor code highlight 2 | 3 | Code highlight module built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /packages/upload-image-module/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor upload-image-module 2 | 3 | Upload image module built in [wangEditor](https://www.wangeditor.com/) by default. 4 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/editor/src/utils/dom.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description dom utils 3 | * @author wangfupeng 4 | */ 5 | 6 | import DOMElement = globalThis.Element 7 | 8 | export { DOMElement } 9 | -------------------------------------------------------------------------------- /packages/basic-modules/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/code-highlight/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/list-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": {}, 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/table-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /packages/video-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | open_collective: wangeditor 5 | -------------------------------------------------------------------------------- /packages/upload-image-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": {}, 3 | "extends": "../../tsconfig.json", 4 | "include": [ 5 | "./src/**/*", 6 | "../custom-types.d.ts" 7 | ] 8 | } -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /packages/code-highlight/src/locale/en.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n en 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | highLightModule: { 8 | selectLang: 'Language', 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /packages/code-highlight/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | highLightModule: { 8 | selectLang: '选择语言', 9 | }, 10 | } 11 | -------------------------------------------------------------------------------- /packages/core/__tests__/menus/register-menus/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 注册菜单,入口 3 | * @author wangfupeng 4 | */ 5 | 6 | import './register-button-menu' 7 | import './register-select-menu' 8 | import './register-modal-menu' 9 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/line-height/menu/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description line-height config 3 | * @author wangfupeng 4 | */ 5 | 6 | export function genLineHeightConfig() { 7 | return ['1', '1.15', '1.5', '2', '2.5', '3'] 8 | } 9 | -------------------------------------------------------------------------------- /packages/list-module/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | listModule: { 8 | unOrderedList: '无序列表', 9 | orderedList: '有序列表', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/editor/examples/css/editor.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0 10px; 3 | } 4 | 5 | .editor-toolbar { 6 | border: 1px solid #ccc; 7 | } 8 | 9 | .editor-text-area { 10 | border: 1px solid #ccc; 11 | border-top: 0; 12 | height: 400px; 13 | } -------------------------------------------------------------------------------- /packages/list-module/src/locale/en.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n en 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | listModule: { 8 | unOrderedList: 'Unordered list', 9 | orderedList: 'Ordered list', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/assets/progress.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-progress-bar { 4 | position: absolute; 5 | width: 0; 6 | height: 1px; 7 | background-color: @textarea-handler-bg-color; 8 | transition: width 0.3s; 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export const IGNORE_TAGS = new Set([ 2 | 'doctype', 3 | '!doctype', 4 | 'meta', 5 | 'script', 6 | 'style', 7 | 'link', 8 | 'frame', 9 | 'iframe', 10 | 'title', 11 | 'svg', // TODO 暂时忽略 12 | ]) 13 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | uploadImgModule: { 8 | uploadImage: '上传图片', 9 | uploadError: '{{fileName}} 上传出错', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/index.less: -------------------------------------------------------------------------------- 1 | @import "simple-style.less"; 2 | @import "color.less"; 3 | @import "blockquote.less"; 4 | @import "emotion.less"; 5 | @import "divider.less"; 6 | @import "blockquote.less"; 7 | @import "code-block.less"; 8 | @import "image.less"; 9 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/simple-style.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-text-container [data-slate-editor] code { 4 | font-family: monospace; 5 | background-color: @textarea-slight-bg-color; 6 | padding: 3px; 7 | border-radius: 3px; 8 | } 9 | -------------------------------------------------------------------------------- /packages/core/src/create/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description create entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import coreCreateEditor from './create-editor' 7 | import coreCreateToolbar from './create-toolbar' 8 | 9 | export { coreCreateEditor, coreCreateToolbar } 10 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/locale/en.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n en 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | uploadImgModule: { 8 | uploadImage: 'Upload Image', 9 | uploadError: '{{fileName}} upload error', 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/editor/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | editor: { 8 | more: '更多', 9 | justify: '对齐', 10 | indent: '缩进', 11 | image: '图片', 12 | video: '视频', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/render/helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description formats helper 3 | * @author wangfupeng 4 | */ 5 | 6 | export function genElemId(id: string) { 7 | return `w-e-element-${id}` 8 | } 9 | 10 | export function genTextId(id: string) { 11 | return `w-e-text-${id}` 12 | } 13 | -------------------------------------------------------------------------------- /packages/editor/src/locale/en.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n en 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | editor: { 8 | more: 'More', 9 | justify: 'Justify', 10 | indent: 'Indent', 11 | image: 'Image', 12 | video: 'Video', 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/color/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Text 引入到最外层的 custom-types.d.ts 7 | 8 | export type ColorText = { 9 | text: string 10 | color?: string 11 | bgColor?: string 12 | } 13 | -------------------------------------------------------------------------------- /packages/list-module/src/utils/maps.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description maps 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Element as SlateElement } from 'slate' 7 | import { IDomEditor } from '@wangeditor/core' 8 | 9 | export const ELEM_TO_EDITOR = new WeakMap() 10 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/todo/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description todo menu entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import TodoMenu from './Todo' 7 | 8 | export const todoMenuConf = { 9 | key: 'todo', 10 | factory() { 11 | return new TodoMenu() 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/core/src/assets/index.less: -------------------------------------------------------------------------------- 1 | @import "common.less"; 2 | @import "textarea.less"; 3 | @import "bar.less"; 4 | @import "bar-item.less"; 5 | @import "select-list.less"; 6 | @import "drop-panel.less"; 7 | @import "modal.less"; 8 | @import "progress.less"; 9 | @import "full-screen.less"; 10 | -------------------------------------------------------------------------------- /packages/table-module/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description table entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import './assets/index.less' 7 | 8 | // 配置多语言 9 | import './locale/index' 10 | 11 | import wangEditorTableModule from './module/index' 12 | export default wangEditorTableModule 13 | -------------------------------------------------------------------------------- /packages/video-module/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description video module 3 | * @author wangfupeng 4 | */ 5 | 6 | import './assets/index.less' 7 | 8 | // 配置多语言 9 | import './locale/index' 10 | 11 | import wangEditorVideoModule from './module/index' 12 | export default wangEditorVideoModule 13 | -------------------------------------------------------------------------------- /packages/core/src/upload/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description upload entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import createUploader from './createUploader' 7 | import { IUploadConfig } from './interface' 8 | 9 | export { createUploader, IUploadConfig } 10 | 11 | // TODO upload 能力,写到文档中,二次开发使用 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/common/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description common menu config 3 | * @author wangfupeng 4 | */ 5 | 6 | import EnterMenu from './EnterMenu' 7 | 8 | export const enterMenuConf = { 9 | key: 'enter', 10 | factory() { 11 | return new EnterMenu() 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/list-module/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description list module 3 | * @author wangfupeng 4 | */ 5 | 6 | import './assets/index.less' 7 | 8 | // 配置多语言 9 | import './locale/index' 10 | 11 | // 导出 module 12 | import wangEditorListModule from './module/index' 13 | export default wangEditorListModule 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/full-screen/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description menu entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import FullScreen from './FullScreen' 7 | 8 | export const fullScreenConf = { 9 | key: 'fullScreen', 10 | factory() { 11 | return new FullScreen() 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description upload image 3 | * @author wangfupeng 4 | */ 5 | 6 | import './assets/index.less' 7 | 8 | // 配置多语言 9 | import './locale/index' 10 | 11 | import wangEditorUploadImageModule from './module/index' 12 | export default wangEditorUploadImageModule 13 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/font-size-family/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Text 引入到最外层的 custom-types.d.ts 7 | 8 | export type FontSizeAndFamilyText = { 9 | text: string 10 | fontSize?: string 11 | fontFamily?: string 12 | } 13 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/paragraph/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type ParagraphElement = { 11 | type: 'paragraph' 12 | children: Text[] 13 | } 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/blockquote/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type BlockQuoteElement = { 11 | type: 'blockquote' 12 | children: Text[] 13 | } 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/code-block/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description code-block menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import CodeBlockMenu from './CodeBlockMenu' 7 | 8 | export const codeBlockMenuConf = { 9 | key: 'codeBlock', 10 | factory() { 11 | return new CodeBlockMenu() 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/editor/demo/css/layout.css: -------------------------------------------------------------------------------- 1 | /* body { 2 | margin: 20px; 3 | } */ 4 | 5 | .page-container { 6 | margin-top: 15px; 7 | display: flex; 8 | } 9 | 10 | .page-left { 11 | width: 150px; 12 | padding: 0 10px; 13 | } 14 | 15 | .page-right { 16 | padding: 0 10px; 17 | flex: 1; 18 | width: calc(100vw - 170px); 19 | } -------------------------------------------------------------------------------- /packages/editor/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/blockquote/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description block quote menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import BlockquoteMenu from './BlockquoteMenu' 7 | 8 | export const blockquoteMenuConf = { 9 | key: 'blockquote', 10 | factory() { 11 | return new BlockquoteMenu() 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/todo/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type TodoElement = { 11 | type: 'todo' 12 | checked: boolean 13 | children: Text[] 14 | } 15 | -------------------------------------------------------------------------------- /packages/list-module/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/table-module/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/video-module/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/code-highlight/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /packages/core/src/assets/common.less: -------------------------------------------------------------------------------- 1 | .w-e-text-container *, 2 | .w-e-toolbar * { 3 | padding: 0; 4 | margin: 0; 5 | box-sizing: border-box; 6 | outline: none; 7 | } 8 | 9 | .w-e-text-container { 10 | p, li, td, th, blockquote { 11 | line-height: 1.5; 12 | } 13 | } 14 | 15 | .w-e-toolbar * { 16 | line-height: 1.5; 17 | } -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/divider/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description divider element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 7 | 8 | type EmptyText = { 9 | text: '' 10 | } 11 | 12 | export type DividerElement = { 13 | type: 'divider' 14 | children: EmptyText[] 15 | } 16 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/indent/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type IndentElement = { 11 | type: string 12 | indent?: string | null 13 | children: Text[] 14 | } 15 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/justify/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type JustifyElement = { 11 | type: string 12 | textAlign?: string 13 | children: Text[] 14 | } 15 | -------------------------------------------------------------------------------- /packages/table-module/src/utils/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 工具函数 3 | * @author wangfupeng 4 | */ 5 | 6 | import { nanoid } from 'nanoid' 7 | 8 | /** 9 | * 获取随机数字符串 10 | * @param prefix 前缀 11 | * @returns 随机数字符串 12 | */ 13 | export function genRandomStr(prefix: string = 'r'): string { 14 | return `${prefix}-${nanoid()}` 15 | } 16 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/locale/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { i18nAddResources } from '@wangeditor/core' 7 | import enResources from './en' 8 | import zhResources from './zh-CN' 9 | 10 | i18nAddResources('en', enResources) 11 | i18nAddResources('zh-CN', zhResources) 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 建议增加新功能 3 | about: 请按照该模板填写,以便我们能真正了解你的需求,否则该 issue 将不予受理! 4 | --- 5 | 6 | ## 功能描述 7 | 8 | *请输入内容……* 9 | 10 | ## 提炼几个功能点 11 | 12 | - 功能1 13 | - 功能2 14 | - 功能3 15 | 16 | ## 原型图 17 | 18 | *涉及到 UI 改动的功能,请一定提供原型图。原型图能表明功能即可,不要求规范和美观* 19 | 20 | ## 可参考的案例 21 | 22 | *是否已有可参考的案例(如其他编辑器),有的话请给出链接* 23 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/line-height/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type LineHeightElement = { 11 | type: string 12 | lineHeight?: string 13 | children: Text[] 14 | } 15 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/common/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description common module 3 | * @author wangfupeng 4 | */ 5 | import { IModuleConf } from '@wangeditor/core' 6 | import { enterMenuConf } from './menu/index' 7 | 8 | const commonModule: Partial = { 9 | menus: [enterMenuConf], 10 | } 11 | 12 | export default commonModule 13 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/emotion/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description emotion entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import { IModuleConf } from '@wangeditor/core' 7 | import { emotionMenuConf } from './menu/index' 8 | 9 | const emotion: Partial = { 10 | menus: [emotionMenuConf], 11 | } 12 | 13 | export default emotion 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/full-screen/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 全屏 3 | * @author wangfupeng 4 | */ 5 | 6 | import { IModuleConf } from '@wangeditor/core' 7 | import { fullScreenConf } from './menu/index' 8 | 9 | const fullScreen: Partial = { 10 | menus: [fullScreenConf], 11 | } 12 | 13 | export default fullScreen 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/link/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type LinkElement = { 11 | type: 'link' 12 | url: string 13 | target?: string 14 | children: Text[] 15 | } 16 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/code-block.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-text-container [data-slate-editor] pre>code { 4 | display: block; 5 | border: 1px solid @textarea-slight-border-color; 6 | border-radius: 4px 4px; 7 | text-indent: 0; 8 | background-color: @textarea-slight-bg-color; 9 | padding: 10px; 10 | font-size: @size; 11 | } 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/header/menu/Header1ButtonMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description header1 button menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import HeaderButtonMenuBase from './HeaderButtonMenuBase' 7 | 8 | class Header1ButtonMenu extends HeaderButtonMenuBase { 9 | title = 'H1' 10 | type = 'header1' 11 | } 12 | 13 | export default Header1ButtonMenu 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/header/menu/Header2ButtonMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description header2 button menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import HeaderButtonMenuBase from './HeaderButtonMenuBase' 7 | 8 | class Header2ButtonMenu extends HeaderButtonMenuBase { 9 | title = 'H2' 10 | type = 'header2' 11 | } 12 | 13 | export default Header2ButtonMenu 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/header/menu/Header3ButtonMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description header3 button menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import HeaderButtonMenuBase from './HeaderButtonMenuBase' 7 | 8 | class Header3ButtonMenu extends HeaderButtonMenuBase { 9 | title = 'H3' 10 | type = 'header3' 11 | } 12 | 13 | export default Header3ButtonMenu 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/header/menu/Header4ButtonMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description header4 button menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import HeaderButtonMenuBase from './HeaderButtonMenuBase' 7 | 8 | class Header4ButtonMenu extends HeaderButtonMenuBase { 9 | title = 'H4' 10 | type = 'header4' 11 | } 12 | 13 | export default Header4ButtonMenu 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/header/menu/Header5ButtonMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description header5 button menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import HeaderButtonMenuBase from './HeaderButtonMenuBase' 7 | 8 | class Header5ButtonMenu extends HeaderButtonMenuBase { 9 | title = 'H5' 10 | type = 'header5' 11 | } 12 | 13 | export default Header5ButtonMenu 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/image/menu/Width30.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description image width 30% 3 | * @author wangfupeng 4 | */ 5 | 6 | import ImageWidthBaseClass from './WidthBase' 7 | 8 | class ImageWidth30 extends ImageWidthBaseClass { 9 | readonly title = '30%' // 菜单标题 10 | readonly value = '30%' // css width 的值 11 | } 12 | 13 | export default ImageWidth30 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/image/menu/Width50.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description image width 50% 3 | * @author wangfupeng 4 | */ 5 | 6 | import ImageWidthBaseClass from './WidthBase' 7 | 8 | class ImageWidth50 extends ImageWidthBaseClass { 9 | readonly title = '50%' // 菜单标题 10 | readonly value = '50%' // css width 的值 11 | } 12 | 13 | export default ImageWidth50 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/blockquote.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-text-container [data-slate-editor] blockquote { 4 | display: block; 5 | border-left: 8px solid @textarea-selected-border-color; 6 | padding: 10px 10px; 7 | margin: 10px 0; 8 | line-height: 1.5; 9 | font-size: 100%; 10 | background-color: @textarea-slight-bg-color; 11 | } 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/image/menu/Width100.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description image width 100% 3 | * @author wangfupeng 4 | */ 5 | 6 | import ImageWidthBaseClass from './WidthBase' 7 | 8 | class ImageWidth100 extends ImageWidthBaseClass { 9 | readonly title = '100%' // 菜单标题 10 | readonly value = '100%' // css width 的值 11 | } 12 | 13 | export default ImageWidth100 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/undo-redo/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description undo redo 3 | * @author wangfupeng 4 | */ 5 | 6 | import { IModuleConf } from '@wangeditor/core' 7 | import { redoMenuConf, undoMenuConf } from './menu/index' 8 | 9 | const undoRedo: Partial = { 10 | menus: [redoMenuConf, undoMenuConf], 11 | } 12 | 13 | export default undoRedo 14 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/divider/elem-to-html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description to html 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Element } from 'slate' 7 | 8 | function dividerToHtml(elem: Element, childrenHtml: string): string { 9 | return `
` 10 | } 11 | 12 | export const dividerToHtmlConf = { 13 | type: 'divider', 14 | elemToHtml: dividerToHtml, 15 | } 16 | -------------------------------------------------------------------------------- /packages/list-module/src/module/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description list element 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Text } from 'slate' 7 | 8 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 9 | 10 | export type ListItemElement = { 11 | type: 'list-item' 12 | ordered: boolean // 有序/无序 13 | level: number // 层级:0 1 2 ... 14 | children: Text[] 15 | } 16 | -------------------------------------------------------------------------------- /packages/table-module/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | tableModule: { 8 | deleteCol: '删除列', 9 | deleteRow: '删除行', 10 | deleteTable: '删除表格', 11 | widthAuto: '宽度自适应', 12 | insertCol: '插入列', 13 | insertRow: '插入行', 14 | insertTable: '插入表格', 15 | header: '表头', 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /packages/core/src/utils/key.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An auto-incrementing identifier for keys. 3 | */ 4 | 5 | let n = 0 6 | 7 | /** 8 | * A class that keeps track of a key string. We use a full class here because we 9 | * want to be able to use them as keys in `WeakMap` objects. 10 | */ 11 | export class Key { 12 | id: string 13 | 14 | constructor() { 15 | this.id = `${n++}` 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/text-style/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Text 引入到最外层的 custom-types.d.ts 7 | 8 | export type StyledText = { 9 | text: string 10 | bold?: boolean 11 | code?: boolean 12 | italic?: boolean 13 | through?: boolean 14 | underline?: boolean 15 | sup?: boolean 16 | sub?: boolean 17 | } 18 | -------------------------------------------------------------------------------- /packages/editor/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor editor 2 | 3 | [English](./README-en.md) 4 | 5 | 开源 Web 富文本编辑器,开箱即用,配置简单。支持 JS Vue React 。 6 | 7 | - [文档](https://www.wangeditor.com/) 8 | - [demo](https://www.wangeditor.com/demo/) 9 | 10 | ![](../../docs/images/editor.png) 11 | 12 | 交流 13 | - [提交问题和建议](https://github.com/wangeditor-team/wangEditor/issues) 14 | - 加入 QQ 群([官网](https://www.wangeditor.com/)有群号) 15 | -------------------------------------------------------------------------------- /packages/code-highlight/src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description code-highlight 3 | * @author wangfupeng 4 | */ 5 | 6 | import './assets/index.less' 7 | 8 | // 配置多语言 9 | import './locale/index' 10 | 11 | import wangEditorCodeHighlightModule from './module/index' 12 | import wangEditorCodeHighLightDecorate from './decorate' 13 | 14 | export { wangEditorCodeHighlightModule, wangEditorCodeHighLightDecorate } 15 | -------------------------------------------------------------------------------- /packages/video-module/src/module/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description video element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 7 | 8 | type EmptyText = { 9 | text: '' 10 | } 11 | 12 | export type VideoElement = { 13 | type: 'video' 14 | src: string 15 | poster?: string 16 | width?: string 17 | height?: string 18 | children: EmptyText[] 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 使用时遇到了问题(非 bug) 3 | about: 请按照该模板填写,以便我们能真正了解你的问题,否则该 issue 将不予受理! 4 | --- 5 | 6 | ## 问题描述 7 | 8 | *请输入遇到的问题...* 9 | 10 | ## wangEditor 版本 11 | 12 | *请输入内容……* 13 | 14 | ## 是否查阅了文档 ? 15 | 16 | (文档链接 [www.wangeditor.com](https://www.wangeditor.com/) ) 17 | 18 | *是/否* 19 | 20 | ## 最小成本的复现步骤 21 | 22 | (请告诉我们,如何**最快的**复现该问题?) 23 | 24 | - 步骤一 25 | - 步骤二 26 | - 步骤三 27 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/blockquote/elem-to-html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description to html 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Element } from 'slate' 7 | 8 | function quoteToHtml(elem: Element, childrenHtml: string): string { 9 | return `
${childrenHtml}
` 10 | } 11 | 12 | export const quoteToHtmlConf = { 13 | type: 'blockquote', 14 | elemToHtml: quoteToHtml, 15 | } 16 | -------------------------------------------------------------------------------- /cypress/integration/editor.spec.ts: -------------------------------------------------------------------------------- 1 | describe('Basic Editor', () => { 2 | it('create editor', () => { 3 | cy.visit('/examples/default-mode.html') 4 | 5 | cy.get('#btn-create').click() 6 | 7 | cy.get('#editor-toolbar').should('have.attr', 'data-w-e-toolbar', 'true') 8 | cy.get('#editor-text-area').should('have.attr', 'data-w-e-textarea', 'true') 9 | cy.get('#w-e-textarea-1').contains('一行标题') 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/divider.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-textarea-divider { 4 | padding: 20px 20px; 5 | margin: 20px auto; 6 | border-radius: 3px; 7 | 8 | // &:hover { 9 | // background-color: @textarea-slight-bg-color; 10 | // } 11 | 12 | hr { 13 | display: block; 14 | border: 0; 15 | height: 1px; 16 | background-color: @textarea-border-color; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wangEditor 5 2 | 3 | [English](./README-en.md) 4 | 5 | ## 介绍 6 | 7 | 开源 Web 富文本编辑器,开箱即用,配置简单。支持 JS Vue React 。 8 | 9 | - [文档](https://www.wangeditor.com/) 10 | - [demo](https://www.wangeditor.com/demo/) 11 | 12 | ![](./docs/images/editor.png) 13 | 14 | ## 交流 15 | 16 | - [讨论问题和建议](https://github.com/wangeditor-team/wangEditor/issues) 17 | 18 | ## 捐赠 19 | 20 | 支持 wangEditor 开源工作 https://opencollective.com/wangeditor 21 | -------------------------------------------------------------------------------- /packages/basic-modules/src/assets/emotion.less: -------------------------------------------------------------------------------- 1 | @import "../../../vars.less"; 2 | 3 | .w-e-panel-content-emotion { 4 | list-style: none; 5 | text-align: left; 6 | width: 300px; 7 | font-size: 20px; 8 | 9 | li { 10 | display: inline-block; 11 | padding: 0 5px; 12 | cursor: pointer; 13 | border-radius: 3px 3px; 14 | 15 | &:hover { 16 | background-color: @textarea-slight-bg-color; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /packages/code-highlight/src/module/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description code-highlight menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import SelectLangMenu from './SelectLangMenu' 7 | import { genCodeLangs } from './config' 8 | 9 | export const selectLangMenuConf = { 10 | key: 'codeSelectLang', 11 | factory() { 12 | return new SelectLangMenu() 13 | }, 14 | config: { 15 | codeLangs: genCodeLangs(), 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # wangEditor core 2 | 3 | [wangEditor](https://www.wangeditor.com/) core. 4 | 5 | ## Main Functionalities 6 | - View( model -> vdom -> DOM ) + Selection 7 | - Menus + toolbar + hoverbar 8 | - Core editor APIs and events 9 | - Register third-party modules (menus, plugins...) 10 | 11 | ## Main dependencies 12 | - [slate.js](https://docs.slatejs.org/) 13 | - [snabbdom.js](https://github.com/snabbdom/snabbdom) 14 | -------------------------------------------------------------------------------- /packages/editor/README-en.md: -------------------------------------------------------------------------------- 1 | # wangEditor editor 2 | 3 | [中文](./README.md) 4 | 5 | Open source web rich text editor, run right out of the box. Support JS Vue React. 6 | 7 | - [Document](https://www.wangeditor.com/en/) 8 | - [Demo](https://www.wangeditor.com/demo/?lang=en) 9 | 10 | ![](../../docs/images/editor-en.png) 11 | 12 | You can [commit an issue]((https://github.com/wangeditor-team/wangEditor/issues)) if you have any question. 13 | -------------------------------------------------------------------------------- /packages/code-highlight/src/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | // 拷贝自 basic-modules/src/modules/code-block/custom-types.ts 7 | 8 | type PureText = { 9 | text: string 10 | } 11 | 12 | export type PreElement = { 13 | type: 'pre' 14 | children: CodeElement[] 15 | } 16 | 17 | export type CodeElement = { 18 | type: 'code' 19 | language: string 20 | children: PureText[] 21 | } 22 | -------------------------------------------------------------------------------- /packages/table-module/src/locale/en.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n en 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | tableModule: { 8 | deleteCol: 'Delete column', 9 | deleteRow: 'Delete row', 10 | deleteTable: 'Delete table', 11 | widthAuto: 'Width auto', 12 | insertCol: 'Insert column', 13 | insertRow: 'Insert row', 14 | insertTable: 'Insert table', 15 | header: 'Header', 16 | }, 17 | } 18 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/utils/dom.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description DOM 操作 3 | * @author wangfupeng 4 | */ 5 | 6 | import $, { append, on, remove, val, click, hide } from 'dom7' 7 | export { Dom7Array } from 'dom7' 8 | 9 | if (append) $.fn.append = append 10 | if (on) $.fn.on = on 11 | if (remove) $.fn.remove = remove 12 | if (val) $.fn.val = val 13 | if (click) $.fn.click = click 14 | if (hide) $.fn.hide = hide 15 | 16 | export default $ 17 | -------------------------------------------------------------------------------- /cypress/cypress.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare namespace Cypress { 4 | interface CustomWindow extends Window {} 5 | 6 | interface Chainable { 7 | /** 8 | * Window object with additional properties used during test. 9 | */ 10 | window(options?: Partial): Chainable 11 | 12 | getByClass(dataTestAttribute: string, args?: any): Chainable 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/code-block/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 自定义 element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 7 | 8 | type PureText = { 9 | text: string 10 | } 11 | 12 | export type PreElement = { 13 | type: 'pre' 14 | children: CodeElement[] 15 | } 16 | 17 | export type CodeElement = { 18 | type: 'code' 19 | language: string 20 | children: PureText[] 21 | } 22 | -------------------------------------------------------------------------------- /packages/upload-image-module/src/module/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description uploadImage module 3 | * @author wangfupeng 4 | */ 5 | 6 | import { IModuleConf } from '@wangeditor/core' 7 | import withUploadImage from './plugin' 8 | import { uploadImageMenuConf } from './menu/index' 9 | 10 | const uploadImage: Partial = { 11 | menus: [uploadImageMenuConf], 12 | editorPlugin: withUploadImage, 13 | } 14 | 15 | export default uploadImage 16 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/paragraph/elem-to-html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description to html 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Element } from 'slate' 7 | 8 | function pToHtml(elem: Element, childrenHtml: string): string { 9 | if (childrenHtml === '') { 10 | return '


' 11 | } 12 | return `

${childrenHtml}

` 13 | } 14 | 15 | export const pToHtmlConf = { 16 | type: 'paragraph', 17 | elemToHtml: pToHtml, 18 | } 19 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/undo-redo/menu/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description menu entry 3 | * @author wangfupeng 4 | */ 5 | 6 | import RedoMenu from './RedoMenu' 7 | import UndoMenu from './UndoMenu' 8 | 9 | export const undoMenuConf = { 10 | key: 'undo', 11 | factory() { 12 | return new UndoMenu() 13 | }, 14 | } 15 | 16 | export const redoMenuConf = { 17 | key: 'redo', 18 | factory() { 19 | return new RedoMenu() 20 | }, 21 | } 22 | -------------------------------------------------------------------------------- /packages/core/__tests__/create-core-editor.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description create editor - 用于 packages/core 单元测试 3 | * @author wangfupeng 4 | */ 5 | 6 | import createEditor from '../src/create/create-editor' 7 | 8 | export default function (options: any = {}) { 9 | const container = document.createElement('div') 10 | document.body.appendChild(container) 11 | 12 | return createEditor({ 13 | selector: container, 14 | ...options, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /packages/basic-modules/src/utils/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 工具函数 3 | * @author wangfupeng 4 | */ 5 | 6 | import { nanoid } from 'nanoid' 7 | 8 | /** 9 | * 获取随机数字符串 10 | * @param prefix 前缀 11 | * @returns 随机数字符串 12 | */ 13 | export function genRandomStr(prefix: string = 'r'): string { 14 | return `${prefix}-${nanoid()}` 15 | } 16 | 17 | export function replaceSymbols(str: string) { 18 | return str.replace(//g, '>') 19 | } 20 | -------------------------------------------------------------------------------- /packages/video-module/src/utils/util.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 工具函数 3 | * @author wangfupeng 4 | */ 5 | 6 | import { nanoid } from 'nanoid' 7 | 8 | /** 9 | * 获取随机数字符串 10 | * @param prefix 前缀 11 | * @returns 随机数字符串 12 | */ 13 | export function genRandomStr(prefix: string = 'r'): string { 14 | return `${prefix}-${nanoid()}` 15 | } 16 | 17 | export function replaceSymbols(str: string) { 18 | return str.replace(//g, '>') 19 | } 20 | -------------------------------------------------------------------------------- /tests/utils/create-toolbar.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description create toolbar for test 3 | * @author wangfupeng 4 | */ 5 | import { createToolbar as create } from '../../packages/editor/src' 6 | 7 | export default function createToolbar(editor: any, config: any = {}) { 8 | const container = document.createElement('div') 9 | document.body.appendChild(container) 10 | 11 | return create({ 12 | editor, 13 | selector: container, 14 | config, 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog Link 2 | - [basic-modules](./packages/basic-modules/CHANGELOG.md) 3 | - [code-highlight](./packages/code-highlight/CHANGELOG.md) 4 | - [core](./packages/core/CHANGELOG.md) 5 | - [editor](./packages/editor/CHANGELOG.md) 6 | - [list-module](./packages/list-module/CHANGELOG.md) 7 | - [table-module](./packages/table-module/CHANGELOG.md) 8 | - [upload-image-module](./packages/upload-image-module/CHANGELOG.md) 9 | - [video-module](./packages/video-module/CHANGELOG.md) -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/color/menu/ColorMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description color menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { FONT_COLOR_SVG } from '../../../constants/icon-svg' 9 | 10 | class ColorMenu extends BaseMenu { 11 | readonly title = t('color.color') 12 | readonly iconSvg = FONT_COLOR_SVG 13 | readonly mark = 'color' 14 | } 15 | 16 | export default ColorMenu 17 | -------------------------------------------------------------------------------- /packages/core/src/parse-html/helper.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description parse-html helper fns 3 | * @author wangfupeng 4 | */ 5 | 6 | const REPLACE_SPACE_160_REG = new RegExp(String.fromCharCode(160), 'g') 7 | 8 | /** 9 | * 把 charCode 160 的空格(` ` 转换的),替换为 charCode 32 的空格(JS 默认的) 10 | * @param str str 11 | * @returns str 12 | */ 13 | export function replaceSpace160(str: string): string { 14 | const res = str.replace(REPLACE_SPACE_160_REG, ' ') 15 | return res 16 | } 17 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/color/menu/BgColorMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description bg color menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { BG_COLOR_SVG } from '../../../constants/icon-svg' 9 | 10 | class BgColorMenu extends BaseMenu { 11 | readonly title = t('color.bgColor') 12 | readonly iconSvg = BG_COLOR_SVG 13 | readonly mark = 'bgColor' 14 | } 15 | 16 | export default BgColorMenu 17 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/text-style/menu/BoldMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description bold menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { BOLD_SVG } from '../../../constants/icon-svg' 9 | 10 | class BoldMenu extends BaseMenu { 11 | readonly mark = 'bold' 12 | readonly title = t('textStyle.bold') 13 | readonly iconSvg = BOLD_SVG 14 | readonly hotkey = 'mod+b' 15 | } 16 | 17 | export default BoldMenu 18 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/text-style/menu/CodeMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description code menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { CODE_SVG } from '../../../constants/icon-svg' 9 | 10 | class CodeMenu extends BaseMenu { 11 | readonly mark = 'code' 12 | readonly title = t('textStyle.code') 13 | readonly iconSvg = CODE_SVG 14 | readonly hotkey = 'mod+e' 15 | } 16 | 17 | export default CodeMenu 18 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/emotion/menu/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description menu config 3 | * @author wangfupeng 4 | */ 5 | 6 | export function genConfig() { 7 | const emotions = 8 | '😀 😃 😄 😁 😆 😅 😂 🤣 😊 😇 🙂 🙃 😉 😌 😍 😘 😗 😙 😚 😋 😛 😝 😜 🤓 😎 😏 😒 😞 😔 😟 😕 🙁 😣 😖 😫 😩 😢 😭 😤 😠 😡 😳 😱 😨 🤗 🤔 😶 😑 😬 🙄 😯 😴 😷 🤑 😈 🤡 💩 👻 💀 👀 👣 👐 🙌 👏 🤝 👍 👎 👊 ✊ 🤛 🤜 🤞 ✌️ 🤘 👌 👈 👉 👆 👇 ☝️ ✋ 🤚 🖐 🖖 👋 🤙 💪 🖕 ✍️ 🙏' 9 | return emotions.split(' ') 10 | } 11 | -------------------------------------------------------------------------------- /packages/basic-modules/src/modules/image/custom-types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description image element 3 | * @author wangfupeng 4 | */ 5 | 6 | //【注意】需要把自定义的 Element 引入到最外层的 custom-types.d.ts 7 | 8 | type EmptyText = { 9 | text: '' 10 | } 11 | 12 | export type ImageStyle = { 13 | width?: string 14 | height?: string 15 | } 16 | 17 | export type ImageElement = { 18 | type: 'image' 19 | src: string 20 | alt?: string 21 | href?: string 22 | style?: ImageStyle 23 | children: EmptyText[] 24 | } 25 | -------------------------------------------------------------------------------- /packages/list-module/src/module/menu/BulletedListMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description bulleted list menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { BULLETED_LIST_SVG } from '../../constants/svg' 9 | 10 | class BulletedListMenu extends BaseMenu { 11 | readonly ordered = false 12 | readonly title = t('listModule.unOrderedList') 13 | readonly iconSvg = BULLETED_LIST_SVG 14 | } 15 | 16 | export default BulletedListMenu 17 | -------------------------------------------------------------------------------- /packages/list-module/src/module/menu/NumberedListMenu.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description numbered list menu 3 | * @author wangfupeng 4 | */ 5 | 6 | import { t } from '@wangeditor/core' 7 | import BaseMenu from './BaseMenu' 8 | import { NUMBERED_LIST_SVG } from '../../constants/svg' 9 | 10 | class NumberedListMenu extends BaseMenu { 11 | readonly ordered = true 12 | readonly title = t('listModule.orderedList') 13 | readonly iconSvg = NUMBERED_LIST_SVG 14 | } 15 | 16 | export default NumberedListMenu 17 | -------------------------------------------------------------------------------- /packages/video-module/src/locale/zh-CN.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description i18n zh-CN 3 | * @author wangfupeng 4 | */ 5 | 6 | export default { 7 | videoModule: { 8 | delete: '删除视频', 9 | uploadVideo: '上传视频', 10 | insertVideo: '插入视频', 11 | videoSrc: '视频地址', 12 | videoSrcPlaceHolder: '视频文件 url 或第三方 ', children: [] } 24 | const vnode = renderVideoConf.renderElem(elem, null, editor) 25 | expect(vnode.sel).toBe('div') 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /packages/basic-modules/__tests__/todo/elem-to-html.test.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description todo elem to html test 3 | * @author wangfupeng 4 | */ 5 | 6 | import { todoToHtmlConf } from '../../src/modules/todo/elem-to-html' 7 | 8 | describe('todo - elem to html', () => { 9 | it('todo elem to html', () => { 10 | expect(todoToHtmlConf.type).toBe('todo') 11 | 12 | const todoNode1 = { 13 | type: 'todo', 14 | checked: true, 15 | children: [{ text: '' }], 16 | } 17 | const html1 = todoToHtmlConf.elemToHtml(todoNode1, 'hello') 18 | expect(html1).toBe( 19 | `
hello
` 20 | ) 21 | 22 | const todoNode2 = { 23 | type: 'todo', 24 | checked: false, 25 | children: [{ text: '' }], 26 | } 27 | const html2 = todoToHtmlConf.elemToHtml(todoNode2, 'hello') 28 | expect(html2).toBe(`
hello
`) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /packages/core/src/upload/interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description upload interface 3 | * @author wangfupeng 4 | */ 5 | 6 | import { UppyFile } from '@uppy/core' 7 | 8 | type FilesType = { [key: string]: UppyFile<{}, {}> } 9 | 10 | /** 11 | * 配置参考 https://uppy.io/docs/uppy/ 12 | */ 13 | export interface IUploadConfig { 14 | server: string 15 | fieldName?: string 16 | maxFileSize?: number 17 | maxNumberOfFiles?: number 18 | meta?: Record 19 | metaWithUrl: boolean 20 | headers?: 21 | | Headers 22 | | ((file: UppyFile, Record>) => Headers) 23 | | undefined 24 | withCredentials?: boolean 25 | timeout?: number 26 | onBeforeUpload?: (files: FilesType) => boolean | FilesType 27 | onSuccess: (file: UppyFile<{}, {}>, response: any) => void 28 | onProgress?: (progress: number) => void 29 | onFailed: (file: UppyFile<{}, {}>, response: any) => void 30 | onError: (file: UppyFile<{}, {}>, error: any, res: any) => void 31 | } 32 | -------------------------------------------------------------------------------- /packages/editor/src/init-default-config/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description set default config 3 | * @author wangfupeng 4 | */ 5 | 6 | import Boot from '../Boot' 7 | import { 8 | getDefaultEditorConfig, 9 | getDefaultToolbarConfig, 10 | getSimpleEditorConfig, 11 | getSimpleToolbarConfig, 12 | } from './config' 13 | 14 | import { wangEditorCodeHighLightDecorate } from '@wangeditor/code-highlight' 15 | 16 | const defaultEditorConfig = getDefaultEditorConfig() 17 | Boot.setEditorConfig({ 18 | ...defaultEditorConfig, 19 | decorate: wangEditorCodeHighLightDecorate, // 代码高亮 20 | }) 21 | 22 | const simpleEditorConfig = getSimpleEditorConfig() 23 | Boot.setSimpleEditorConfig({ 24 | ...simpleEditorConfig, 25 | decorate: wangEditorCodeHighLightDecorate, // 代码高亮 26 | }) 27 | 28 | const defaultToolbarConfig = getDefaultToolbarConfig() 29 | Boot.setToolbarConfig(defaultToolbarConfig) 30 | 31 | const simpleToolbarConfig = getSimpleToolbarConfig() 32 | Boot.setSimpleToolbarConfig(simpleToolbarConfig) 33 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "independent", 6 | "npmClient": "yarn", 7 | "useWorkspaces": true, 8 | "command": { 9 | "publish": { 10 | "ignoreChanges": ["ignored-file", "*.md"], 11 | "message": "chore(release): publish", 12 | "conventionalCommits": true, 13 | "registry": "https://npm.pkg.github.com" 14 | }, 15 | "version": { 16 | "message": "chore(release): publish", 17 | "allowBranch": "master" 18 | } 19 | }, 20 | "changelog": { 21 | "repo": "wangeditor-team/wangEditor", 22 | "labels": { 23 | "tag: new feature": ":rocket: New Feature", 24 | "tag: breaking change": ":boom: Breaking Change", 25 | "tag: bug fix": ":bug: Bug Fix", 26 | "tag: enhancement": ":nail_care: Enhancement", 27 | "tag: documentation": ":memo: Documentation", 28 | "tag: internal": ":house: Internal" 29 | }, 30 | "cacheDir": ".changelog" 31 | }, 32 | "changelogPreset": "angular" 33 | } 34 | -------------------------------------------------------------------------------- /packages/core/src/text-area/event-handlers/focus.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description 处理 onfocus 事件 3 | * @author wangfupeng 4 | */ 5 | 6 | import { IDomEditor } from '../../editor/interface' 7 | import { DomEditor } from '../../editor/dom-editor' 8 | import TextArea from '../TextArea' 9 | import { IS_FIREFOX } from '../../utils/ua' 10 | import { IS_FOCUSED } from '../../utils/weak-maps' 11 | 12 | function handleOnFocus(event: Event, textarea: TextArea, editor: IDomEditor) { 13 | const el = DomEditor.toDOMNode(editor, editor) 14 | const root = DomEditor.findDocumentOrShadowRoot(editor) 15 | textarea.latestElement = root.activeElement 16 | 17 | // COMPAT: If the editor has nested editable elements, the focus 18 | // can go to them. In Firefox, this must be prevented because it 19 | // results in issues with keyboard navigation. (2017/03/30) 20 | if (IS_FIREFOX && event.target !== el) { 21 | el.focus() 22 | return 23 | } 24 | 25 | IS_FOCUSED.set(editor, true) 26 | } 27 | 28 | export default handleOnFocus 29 | -------------------------------------------------------------------------------- /packages/code-highlight/__tests__/content.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description code content 3 | * @author wangfupeng 4 | */ 5 | 6 | export const text = 'const a = 100;' 7 | 8 | export const textNode = { text: text } 9 | 10 | export const language = 'javascript' 11 | 12 | export const codeNode = { 13 | type: 'code', 14 | language, 15 | children: [textNode], 16 | } 17 | 18 | export const preNode = { 19 | type: 'pre', 20 | children: [codeNode], 21 | } 22 | 23 | export const content = [{ type: 'paragraph', children: [{ text: 'hello world' }] }, preNode] 24 | 25 | export const textNodePath = [1, 0, 0] 26 | 27 | export const codeLocation = { 28 | anchor: { offset: text.length, path: textNodePath }, 29 | focus: { offset: text.length, path: textNodePath }, 30 | } 31 | 32 | export const paragraphLocation = { 33 | anchor: { offset: 0, path: [0, 0] }, 34 | focus: { offset: 0, path: [0, 0] }, 35 | } 36 | 37 | describe('加一个 case 防止报错~', () => { 38 | it('1 + 1 = 2', () => { 39 | expect(1 + 1).toBe(2) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /packages/video-module/src/module/elem-to-html.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @description to html 3 | * @author wangfupeng 4 | */ 5 | 6 | import { Element } from 'slate' 7 | import { VideoElement } from './custom-types' 8 | import { genSizeStyledIframeHtml } from '../utils/dom' 9 | 10 | function videoToHtml(elemNode: Element, childrenHtml?: string): string { 11 | const { src = '', poster = '', width = 'auto', height = 'auto' } = elemNode as VideoElement 12 | let res = '
\n' 13 | 14 | if (src.trim().indexOf('