├── .cursorrules ├── .gitignore ├── .npmignore ├── .npmrc ├── .prettierrc ├── .stylelintrc.json ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── TODO ├── biome.json ├── eslint.config.ts ├── index.html ├── jsconfig.json ├── package.json ├── public └── favicon.png ├── src ├── app.vue ├── assets │ ├── icons │ │ ├── align-center.svg │ │ ├── align-distributed.svg │ │ ├── align-justify.svg │ │ ├── align-left.svg │ │ ├── align-right.svg │ │ ├── arrow-down.svg │ │ ├── assistant.svg │ │ ├── audio.svg │ │ ├── auto-width.svg │ │ ├── background-color.svg │ │ ├── barcode.svg │ │ ├── block-add.svg │ │ ├── block-menu.svg │ │ ├── bold.svg │ │ ├── bookmark.svg │ │ ├── border-none.svg │ │ ├── border.svg │ │ ├── break-marks.svg │ │ ├── bullet-list-2.svg │ │ ├── bullet-list-circle.svg │ │ ├── bullet-list-disc.svg │ │ ├── bullet-list-square.svg │ │ ├── bullet-list.svg │ │ ├── callout.svg │ │ ├── check.svg │ │ ├── chinese-case.svg │ │ ├── clear-cache.svg │ │ ├── clear-format.svg │ │ ├── clickable.svg │ │ ├── close.svg │ │ ├── code-block.svg │ │ ├── code-line-number.svg │ │ ├── code-word-wrap.svg │ │ ├── code.svg │ │ ├── color.svg │ │ ├── columns.svg │ │ ├── copy.svg │ │ ├── date.svg │ │ ├── diagrams.svg │ │ ├── download.svg │ │ ├── echarts.svg │ │ ├── edit.svg │ │ ├── embed.svg │ │ ├── emoji.svg │ │ ├── equal-proportion.svg │ │ ├── exit.svg │ │ ├── expand-down.svg │ │ ├── file-view.svg │ │ ├── file.svg │ │ ├── font-size-decrease.svg │ │ ├── font-size-increase.svg │ │ ├── format-painter.svg │ │ ├── format.svg │ │ ├── full-screen-exit.svg │ │ ├── full-screen.svg │ │ ├── hard-break.svg │ │ ├── heading.svg │ │ ├── help.svg │ │ ├── hide-toolbar.svg │ │ ├── highlight.svg │ │ ├── home-page.svg │ │ ├── hr.svg │ │ ├── html5.svg │ │ ├── image-draggable.svg │ │ ├── image-failed.svg │ │ ├── image-flip.svg │ │ ├── image-preview.svg │ │ ├── image-remove-background.svg │ │ ├── image-reset.svg │ │ ├── image-rotate.svg │ │ ├── image.svg │ │ ├── indent.svg │ │ ├── italic.svg │ │ ├── laser-pointer.svg │ │ ├── line-height.svg │ │ ├── line-number.svg │ │ ├── link.svg │ │ ├── loading.svg │ │ ├── margin.svg │ │ ├── markdown.svg │ │ ├── math.svg │ │ ├── mention.svg │ │ ├── menu.svg │ │ ├── mermaid.svg │ │ ├── message.svg │ │ ├── mind-map.svg │ │ ├── minus.svg │ │ ├── new-window.svg │ │ ├── node-add.svg │ │ ├── node-clear-format.svg │ │ ├── node-copy.svg │ │ ├── node-cut.svg │ │ ├── node-delete-2.svg │ │ ├── node-delete.svg │ │ ├── node-duplicate.svg │ │ ├── node-switch.svg │ │ ├── ordered-list-2.svg │ │ ├── ordered-list-decimal-leading-zero.svg │ │ ├── ordered-list-decimal.svg │ │ ├── ordered-list-lower-latin.svg │ │ ├── ordered-list-lower-roman.svg │ │ ├── ordered-list-simp-chinese-formal.svg │ │ ├── ordered-list-trad-chinese-informal.svg │ │ ├── ordered-list-upper-latin.svg │ │ ├── ordered-list-upper-roman.svg │ │ ├── ordered-list.svg │ │ ├── outdent.svg │ │ ├── page-background.svg │ │ ├── page-break.svg │ │ ├── page-footer.svg │ │ ├── page-header.svg │ │ ├── page-margin.svg │ │ ├── page-orientation.svg │ │ ├── page-size.svg │ │ ├── page.svg │ │ ├── palette-color.svg │ │ ├── paragraph.svg │ │ ├── pdf.svg │ │ ├── plus.svg │ │ ├── preview.svg │ │ ├── print.svg │ │ ├── qrcode.svg │ │ ├── quote.svg │ │ ├── redo.svg │ │ ├── reload.svg │ │ ├── remove.svg │ │ ├── reply.svg │ │ ├── seal.svg │ │ ├── search-replace.svg │ │ ├── select-all.svg │ │ ├── selected.svg │ │ ├── setting.svg │ │ ├── share.svg │ │ ├── shortcut.svg │ │ ├── signature.svg │ │ ├── spellcheck.svg │ │ ├── strike.svg │ │ ├── subscript.svg │ │ ├── superscript.svg │ │ ├── symbol.svg │ │ ├── table-add-column-after.svg │ │ ├── table-add-column-before.svg │ │ ├── table-add-row-after.svg │ │ ├── table-add-row-before.svg │ │ ├── table-cells-align.svg │ │ ├── table-cells-background.svg │ │ ├── table-delete-column.svg │ │ ├── table-delete-row.svg │ │ ├── table-delete.svg │ │ ├── table-fix.svg │ │ ├── table-header-cell.svg │ │ ├── table-header-column.svg │ │ ├── table-header-row.svg │ │ ├── table-merge-cell.svg │ │ ├── table-next-cell.svg │ │ ├── table-previous-cell.svg │ │ ├── table-split-cell.svg │ │ ├── table.svg │ │ ├── tag.svg │ │ ├── task-list-2.svg │ │ ├── task-list.svg │ │ ├── template.svg │ │ ├── text-box.svg │ │ ├── text.svg │ │ ├── time.svg │ │ ├── toc.svg │ │ ├── toolbar-classic.svg │ │ ├── toolbar-ribbon.svg │ │ ├── toolbar-source.svg │ │ ├── underline.svg │ │ ├── undo.svg │ │ ├── video.svg │ │ ├── view.svg │ │ ├── watermark.svg │ │ ├── web-page.svg │ │ └── word.svg │ ├── images │ │ ├── avatar.svg │ │ ├── format-painter.svg │ │ ├── laser-pointer.svg │ │ ├── watermark-compact.png │ │ └── watermark-spacious.png │ └── styles │ │ ├── _mixins.less │ │ ├── _variables.less │ │ ├── drager.less │ │ ├── editor.less │ │ ├── index.less │ │ ├── plyr.less │ │ └── tdesign.less ├── components │ ├── ai │ │ └── assistant │ │ │ └── input.vue │ ├── color-picker.vue │ ├── container │ │ ├── page.vue │ │ ├── print.vue │ │ ├── search-replace.vue │ │ └── toc.vue │ ├── editor │ │ └── index.vue │ ├── icon.vue │ ├── index.ts │ ├── index.vue │ ├── menus │ │ ├── bubble │ │ │ ├── assistant.vue │ │ │ ├── callout │ │ │ │ ├── background.vue │ │ │ │ ├── builtin.vue │ │ │ │ └── emoji-remove.vue │ │ │ ├── file │ │ │ │ └── download.vue │ │ │ ├── image │ │ │ │ ├── draggable.vue │ │ │ │ ├── edit.vue │ │ │ │ ├── flip.vue │ │ │ │ ├── open.vue │ │ │ │ ├── preview.vue │ │ │ │ ├── proportion.vue │ │ │ │ ├── remove-background.vue │ │ │ │ ├── reset.vue │ │ │ │ └── rotate.vue │ │ │ ├── index.vue │ │ │ ├── link │ │ │ │ ├── copy.vue │ │ │ │ ├── edit.vue │ │ │ │ ├── index.vue │ │ │ │ ├── open.vue │ │ │ │ └── unlink.vue │ │ │ ├── menus.vue │ │ │ ├── node │ │ │ │ ├── delete.vue │ │ │ │ ├── duplicate.vue │ │ │ │ └── tofile.vue │ │ │ ├── tag │ │ │ │ ├── background.vue │ │ │ │ ├── builtin.vue │ │ │ │ ├── color.vue │ │ │ │ ├── delete.vue │ │ │ │ └── input.vue │ │ │ ├── text-box │ │ │ │ ├── background.vue │ │ │ │ └── border.vue │ │ │ └── webpage │ │ │ │ ├── clickable.vue │ │ │ │ └── open.vue │ │ ├── button.vue │ │ ├── context │ │ │ └── block │ │ │ │ ├── common.vue │ │ │ │ ├── index.vue │ │ │ │ └── node.vue │ │ └── toolbar │ │ │ ├── base │ │ │ ├── align-center.vue │ │ │ ├── align-distributed.vue │ │ │ ├── align-dropdown.vue │ │ │ ├── align-justify.vue │ │ │ ├── align-left.vue │ │ │ ├── align-right.vue │ │ │ ├── background-color.vue │ │ │ ├── bold.vue │ │ │ ├── bullet-list.vue │ │ │ ├── clear-format.vue │ │ │ ├── code.vue │ │ │ ├── color.vue │ │ │ ├── font-family.vue │ │ │ ├── font-size.vue │ │ │ ├── format-painter.vue │ │ │ ├── heading.vue │ │ │ ├── highlight.vue │ │ │ ├── import-word.vue │ │ │ ├── indent.vue │ │ │ ├── italic.vue │ │ │ ├── line-height.vue │ │ │ ├── margin.vue │ │ │ ├── markdown.vue │ │ │ ├── ordered-list.vue │ │ │ ├── outdent.vue │ │ │ ├── print.vue │ │ │ ├── quote.vue │ │ │ ├── redo.vue │ │ │ ├── search-replace.vue │ │ │ ├── select-all.vue │ │ │ ├── strike.vue │ │ │ ├── subscript.vue │ │ │ ├── superscript.vue │ │ │ ├── task-list.vue │ │ │ ├── underline.vue │ │ │ └── undo.vue │ │ │ ├── export │ │ │ ├── embed.vue │ │ │ ├── html.vue │ │ │ ├── image.vue │ │ │ ├── pdf.vue │ │ │ ├── share.vue │ │ │ ├── text.vue │ │ │ └── word.vue │ │ │ ├── insert │ │ │ ├── audio.vue │ │ │ ├── bookmark.vue │ │ │ ├── callout.vue │ │ │ ├── chinese-date.vue │ │ │ ├── code-block.vue │ │ │ ├── columns.vue │ │ │ ├── emoji.vue │ │ │ ├── file.vue │ │ │ ├── hard-break.vue │ │ │ ├── hr.vue │ │ │ ├── image.vue │ │ │ ├── link.vue │ │ │ ├── math.vue │ │ │ ├── mention.vue │ │ │ ├── symbol.vue │ │ │ ├── tag.vue │ │ │ ├── template.vue │ │ │ ├── text-box.vue │ │ │ ├── toc.vue │ │ │ ├── video.vue │ │ │ └── web-page.vue │ │ │ ├── page │ │ │ ├── background.vue │ │ │ ├── break-marks.vue │ │ │ ├── break.vue │ │ │ ├── footer.vue │ │ │ ├── header.vue │ │ │ ├── line-number.vue │ │ │ ├── margin.vue │ │ │ ├── orientation.vue │ │ │ ├── preview.vue │ │ │ ├── size.vue │ │ │ ├── toggle-toc.vue │ │ │ └── watermark.vue │ │ │ ├── table │ │ │ ├── add-column-after.vue │ │ │ ├── add-column-before.vue │ │ │ ├── add-row-after.vue │ │ │ ├── add-row-before.vue │ │ │ ├── border-color.vue │ │ │ ├── cells-align.vue │ │ │ ├── cells-background.vue │ │ │ ├── delete-column.vue │ │ │ ├── delete-row.vue │ │ │ ├── delete.vue │ │ │ ├── fix.vue │ │ │ ├── insert.vue │ │ │ ├── merge-cells.vue │ │ │ ├── next-cell.vue │ │ │ ├── previous-cell.vue │ │ │ ├── split-cell.vue │ │ │ ├── toggle-header-cell.vue │ │ │ ├── toggle-header-column.vue │ │ │ └── toggle-header-row.vue │ │ │ └── tools │ │ │ ├── barcode.vue │ │ │ ├── chinese-case.vue │ │ │ ├── diagrams.vue │ │ │ ├── echarts.vue │ │ │ ├── mermaid.vue │ │ │ ├── mind-map.vue │ │ │ ├── qrcode.vue │ │ │ ├── seal.vue │ │ │ └── signature.vue │ ├── modal.vue │ ├── page-options.vue │ ├── statusbar │ │ ├── countdown.vue │ │ ├── index.vue │ │ └── shortcuts.vue │ ├── toolbar │ │ ├── classic.vue │ │ ├── index.vue │ │ ├── ribbon.vue │ │ └── scrollable.vue │ └── tooltip.vue ├── composables │ ├── dialog.ts │ ├── hotkeys.ts │ ├── i18n.ts │ ├── popup.ts │ ├── select.ts │ └── state.ts ├── extensions │ ├── audio │ │ ├── index.ts │ │ └── node-view.vue │ ├── bookmark.ts │ ├── break-marks.ts │ ├── bullet-list.ts │ ├── callout │ │ ├── index.ts │ │ └── node-view.vue │ ├── code-block │ │ ├── index.ts │ │ └── node-view.vue │ ├── color-highlighter │ │ ├── find-colors.ts │ │ └── index.ts │ ├── datetime │ │ ├── index.ts │ │ └── node-view.vue │ ├── echarts │ │ ├── cal-service.ts │ │ ├── index.ts │ │ ├── init-service.ts │ │ └── node-view.vue │ ├── file-handler.ts │ ├── file │ │ ├── index.ts │ │ └── node-view.vue │ ├── font-size.ts │ ├── format-painter.ts │ ├── hr.ts │ ├── iframe │ │ ├── index.ts │ │ └── node-view.vue │ ├── image │ │ ├── index.ts │ │ └── node-view.vue │ ├── indent.ts │ ├── index.ts │ ├── line-height.ts │ ├── link.ts │ ├── margin.ts │ ├── mention │ │ ├── index.ts │ │ ├── mentions.vue │ │ └── suggestion.ts │ ├── node-align.ts │ ├── ordered-list.ts │ ├── page-break.ts │ ├── selection.ts │ ├── table │ │ ├── cell.ts │ │ ├── header.ts │ │ └── index.ts │ ├── tag │ │ ├── index.ts │ │ └── node-view.vue │ ├── text-align.ts │ ├── text-box │ │ ├── index.ts │ │ └── node-view.vue │ ├── toc │ │ ├── index.ts │ │ └── node-view.vue │ ├── type-writer.ts │ └── video │ │ ├── index.ts │ │ └── node-view.vue ├── i18n.ts ├── locales │ ├── bo.json │ ├── en-US.json │ ├── ru-RU.json │ ├── tdesign │ │ └── ru-RU.ts │ └── zh-CN.json ├── main.ts ├── options │ ├── ai.ts │ ├── dicts.ts │ ├── index.ts │ └── web-pages.ts └── utils │ ├── browser.ts │ ├── content-transform.ts │ ├── copyright.ts │ ├── diagram-editor.ts │ ├── file.ts │ ├── functional.spec.ts │ ├── functional.ts │ ├── options.ts │ ├── player.ts │ ├── short-id.ts │ ├── shortcut.ts │ └── time-ago.ts ├── tsconfig.json ├── types ├── index.d.ts └── shims.d.ts ├── vite.config.ts └── vitest.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | node_modules/ 3 | 4 | # Build output 5 | dist/ 6 | package/ 7 | 8 | # Editor directories and files 9 | .idea/ 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | *.sln 14 | *.sw? 15 | 16 | # Logs 17 | logs 18 | *.log 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # Cache 24 | *.tsbuildinfo 25 | .npm 26 | .eslintcache 27 | .stylelintcache 28 | .prettiercache 29 | .biomecache 30 | vite.config.ts.timestamp* 31 | vitest.config.ts.timestamp* 32 | 33 | # Husky 34 | .husky/_ 35 | 36 | # Auto Imports 37 | types/imports.d.ts 38 | types/components.d.ts 39 | 40 | # Lock files 41 | package-lock.json 42 | yarn.lock 43 | pnpm-lock.yaml 44 | 45 | # Other 46 | .DS_Store 47 | Thumbs.db 48 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | // Ignore all files and folders starting with a dot 2 | .* 3 | 4 | // Ignore logs 5 | *.log* 6 | 7 | // Ignore timestamp files 8 | *.timestamp* 9 | 10 | // Ignore development files 11 | node_modules 12 | src/ 13 | public/ 14 | biome.json 15 | eslint.config.mjs 16 | index.html 17 | jsconfig.json 18 | package.json 19 | TODO 20 | tsconfig.json 21 | vite.config.ts 22 | vitest.config.ts 23 | yarn.lock -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | @tiptap-pro:registry=https://registry.tiptap.dev/ 2 | //registry.tiptap.dev/:_authToken=9fsQEgp8C8pbxpk8PFAjYr2oqCJzh96jh9UkQZtq4SCi1XDwBeVw2Kcs/YD1oVje -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/prettierrc", 3 | "semi": false, 4 | "tabWidth": 2, 5 | "singleQuote": true 6 | } 7 | -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["stylelint-less"], 3 | "rules": { 4 | "color-no-invalid-hex": true, 5 | "less/color-no-invalid-hex": true, 6 | "no-descending-specificity": null, 7 | "selector-pseudo-class-no-unknown": [ 8 | true, 9 | { "ignorePseudoClasses": ["deep"] } 10 | ] 11 | }, 12 | "extends": [ 13 | "stylelint-config-recommended-vue", 14 | "stylelint-config-recommended-less" 15 | ], 16 | "customSyntax": "postcss-html" 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Vue.volar", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode", 6 | "i18n-ally.vscode-i18n-ally" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": "always", 4 | "quickfix.biome": "always" 5 | }, 6 | "editor.formatOnSave": true, 7 | "eslint.validate": [ 8 | "javascript", 9 | "javascriptreact", 10 | "typescript", 11 | "typescriptreact" 12 | ], 13 | "[javascript]": { 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | }, 16 | "[javascriptreact]": { 17 | "editor.defaultFormatter": "esbenp.prettier-vscode" 18 | }, 19 | "[typescript]": { 20 | "editor.defaultFormatter": "esbenp.prettier-vscode" 21 | }, 22 | "[typescriptreact]": { 23 | "editor.defaultFormatter": "esbenp.prettier-vscode" 24 | }, 25 | "i18n-ally.localesPaths": ["src/locales"], 26 | "i18n-ally.keystyle": "nested" 27 | } 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | [English Changelog](https://editor.umodoc.com/en/docs/changelog) | [中文更新日志](https://editor.umodoc.com/cn/docs/changelog) 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2024 umo-team 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | [ ] 页面设置等可撤销和重做 -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", 3 | "formatter": { 4 | "enabled": false 5 | }, 6 | "linter": { 7 | "enabled": true, 8 | "ignore": ["node_modules", "dist"], 9 | "rules": { 10 | "recommended": true, 11 | "suspicious": { 12 | "noExplicitAny": "off" 13 | }, 14 | "performance": { 15 | "noDelete": "off", 16 | "noAccumulatingSpread": "off" 17 | }, 18 | "style": { 19 | "noNonNullAssertion": "off", 20 | "noParameterAssign": "off" 21 | } 22 | } 23 | }, 24 | "json": { 25 | "formatter": { 26 | "enabled": true 27 | } 28 | }, 29 | "css": { 30 | "linter": { 31 | "enabled": true 32 | } 33 | }, 34 | "organizeImports": { 35 | "enabled": false 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Umo Editor 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | }, 7 | "include": ["./types/**/*.d.ts"], 8 | "exclude": ["node_modules", "dist"], 9 | "types": ["vue/ref-macros"] 10 | } 11 | -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umodoc/editor/50f1247102b2e297bad4cae963ffed66b32a597a/public/favicon.png -------------------------------------------------------------------------------- /src/assets/icons/align-center.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/align-distributed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/align-justify.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/align-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/align-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/assistant.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/audio.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/auto-width.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/background-color.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/barcode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/block-add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/block-menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bold.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bookmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/border-none.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/border.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/break-marks.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bullet-list-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bullet-list-circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bullet-list-disc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bullet-list-square.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/bullet-list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/callout.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/chinese-case.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/clear-cache.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/clear-format.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/clickable.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/code-block.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/code-line-number.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/code-word-wrap.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/code.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/color.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/columns.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/date.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/diagrams.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/echarts.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/embed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/emoji.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/equal-proportion.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/exit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/expand-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/file-view.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/file.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/font-size-decrease.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/font-size-increase.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/format-painter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/format.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/full-screen-exit.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/full-screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/hard-break.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/heading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/hide-toolbar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/highlight.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/home-page.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/hr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/html5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-draggable.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-failed.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-flip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-preview.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-remove-background.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-reset.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image-rotate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/image.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/indent.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/italic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/laser-pointer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/line-height.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/line-number.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/link.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/margin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/markdown.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/math.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/mention.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/menu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/mermaid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/message.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/mind-map.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/new-window.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-add.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-clear-format.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-cut.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/icons/node-delete-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-duplicate.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/node-switch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list-lower-roman.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list-trad-chinese-informal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list-upper-latin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list-upper-roman.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/ordered-list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/outdent.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-background.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-break.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-footer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-header.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-margin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-orientation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page-size.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/page.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/palette-color.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/paragraph.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/pdf.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/preview.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/print.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/qrcode.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/quote.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/redo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/reload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/remove.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/reply.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/seal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/search-replace.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/select-all.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/selected.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/setting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/shortcut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/signature.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/spellcheck.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/strike.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/subscript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/superscript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/symbol.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-add-column-after.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-add-column-before.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-add-row-after.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-add-row-before.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-cells-align.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-cells-background.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-delete-column.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-delete-row.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-delete.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-fix.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-header-cell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-header-column.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-header-row.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-merge-cell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-next-cell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-previous-cell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table-split-cell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/table.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/tag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/task-list-2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/task-list.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/template.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/text-box.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/text.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/time.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/toc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/toolbar-classic.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/toolbar-ribbon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/toolbar-source.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/underline.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/undo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/video.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/view.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/watermark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/web-page.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/icons/word.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/format-painter.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/laser-pointer.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/watermark-compact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umodoc/editor/50f1247102b2e297bad4cae963ffed66b32a597a/src/assets/images/watermark-compact.png -------------------------------------------------------------------------------- /src/assets/images/watermark-spacious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/umodoc/editor/50f1247102b2e297bad4cae963ffed66b32a597a/src/assets/images/watermark-spacious.png -------------------------------------------------------------------------------- /src/assets/styles/index.less: -------------------------------------------------------------------------------- 1 | @import './_variables.less'; 2 | @import './_mixins.less'; 3 | @import './tdesign.less'; 4 | 5 | .umo-editor-container { 6 | p, 7 | ul, 8 | ol { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | } 13 | 14 | .umo-scrollbar { 15 | .umo-scrollbar(); 16 | } 17 | -------------------------------------------------------------------------------- /src/assets/styles/plyr.less: -------------------------------------------------------------------------------- 1 | .plyr { 2 | --plyr-color-main: var(--umo-primary-color); 3 | --plyr-badge-border-radius: var(--umo-radius); 4 | --plyr-menu-arrow-size: 0; 5 | --plyr-menu-item-arrow-size: 0; 6 | --plyr-tooltip-color: var(--umo-text-color); 7 | --plyr-tooltip-arrow-size: 0; 8 | --plyr-tooltip-radius: 2px; 9 | --plyr-tooltip-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); 10 | border-radius: var(--umo-radius); 11 | @media print { 12 | .plyr__controls { 13 | display: none; 14 | } 15 | .plyr__control { 16 | background-color: transparent; 17 | svg { 18 | width: 24px; 19 | height: 24px; 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/components/icon.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | 24 | 29 | -------------------------------------------------------------------------------- /src/components/index.ts: -------------------------------------------------------------------------------- 1 | import 'virtual:svg-icons-register' 2 | 3 | import UmoEditor from './index.vue' 4 | import UmoMenuButton from './menus/button.vue' 5 | import UmoDialog from './modal.vue' 6 | import UmoTooltip from './tooltip.vue' 7 | 8 | const useUmoEditor = { 9 | install: (app: any, options: any) => { 10 | app.provide('defaultOptions', options) 11 | app.component(UmoEditor.name ?? 'UmoEditor', UmoEditor) 12 | }, 13 | } 14 | 15 | export { 16 | UmoEditor as default, 17 | UmoDialog, 18 | UmoEditor, 19 | UmoMenuButton, 20 | UmoTooltip, 21 | useUmoEditor, 22 | } 23 | -------------------------------------------------------------------------------- /src/components/menus/bubble/assistant.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/menus/bubble/callout/background.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 36 | -------------------------------------------------------------------------------- /src/components/menus/bubble/callout/emoji-remove.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 25 | -------------------------------------------------------------------------------- /src/components/menus/bubble/file/download.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 27 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/draggable.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 24 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/edit.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 17 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/flip.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 37 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/open.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/preview.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/proportion.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 24 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/reset.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 28 | -------------------------------------------------------------------------------- /src/components/menus/bubble/image/rotate.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /src/components/menus/bubble/link/copy.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /src/components/menus/bubble/link/open.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 19 | 20 | 28 | -------------------------------------------------------------------------------- /src/components/menus/bubble/link/unlink.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | -------------------------------------------------------------------------------- /src/components/menus/bubble/node/delete.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/bubble/node/duplicate.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 39 | -------------------------------------------------------------------------------- /src/components/menus/bubble/node/tofile.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | -------------------------------------------------------------------------------- /src/components/menus/bubble/tag/background.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 34 | -------------------------------------------------------------------------------- /src/components/menus/bubble/tag/color.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 34 | -------------------------------------------------------------------------------- /src/components/menus/bubble/tag/delete.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /src/components/menus/bubble/tag/input.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 48 | 49 | 59 | -------------------------------------------------------------------------------- /src/components/menus/bubble/text-box/background.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 34 | -------------------------------------------------------------------------------- /src/components/menus/bubble/webpage/clickable.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 24 | -------------------------------------------------------------------------------- /src/components/menus/bubble/webpage/open.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-center.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 31 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-distributed.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-dropdown.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 47 | 48 | 54 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-justify.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-left.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 30 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/align-right.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 31 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/bold.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/clear-format.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/code.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/format-painter.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 25 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/indent.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/italic.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/line-height.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 41 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/markdown.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 46 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/outdent.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/print.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/quote.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/redo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/search-replace.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/select-all.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/strike.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/subscript.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/superscript.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/task-list.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/underline.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/base/undo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/export/html.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 24 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/export/pdf.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/export/share.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 44 | 45 | 62 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/export/text.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/export/word.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/audio.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/callout.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/code-block.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/file.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/hard-break.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/image.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/math.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/mention.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/tag.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/text-box.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/toc.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/insert/video.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 21 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/break-marks.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 24 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/break.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/footer.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/header.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 13 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/line-number.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/margin.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/preview.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/page/toggle-toc.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/add-column-after.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/add-column-before.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/add-row-after.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/add-row-before.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/border-color.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 33 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/cells-align.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 39 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/cells-background.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 30 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/delete-column.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/delete-row.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/delete.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 36 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/fix.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/merge-cells.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/next-cell.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/previous-cell.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/split-cell.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/toggle-header-cell.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/toggle-header-column.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/table/toggle-header-row.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/components/menus/toolbar/tools/mind-map.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/components/modal.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 28 | -------------------------------------------------------------------------------- /src/components/tooltip.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /src/composables/dialog.ts: -------------------------------------------------------------------------------- 1 | import type { DialogOptions, MessageOptions } from 'tdesign-vue-next' 2 | import { DialogPlugin, MessagePlugin } from 'tdesign-vue-next' 3 | 4 | export const useAlert = ( 5 | parmas: Omit, 6 | ) => { 7 | return DialogPlugin.alert({ 8 | placement: 'center', 9 | ...parmas, 10 | }) 11 | } 12 | export const useConfirm = (parmas: DialogOptions) => { 13 | return DialogPlugin.confirm({ 14 | placement: 'center', 15 | preventScrollThrough: false, 16 | cancelBtn: t('dialog.cancel'), 17 | ...parmas, 18 | }) 19 | } 20 | export const useMessage = (type: string, parmas: string | MessageOptions) => { 21 | const options = typeof parmas === 'string' ? { content: parmas } : parmas 22 | return ( 23 | MessagePlugin[type as keyof typeof MessagePlugin] as 24 | | CallableFunction 25 | | undefined 26 | )?.(options) 27 | } 28 | 29 | export { DialogPlugin, MessagePlugin } 30 | -------------------------------------------------------------------------------- /src/composables/hotkeys.ts: -------------------------------------------------------------------------------- 1 | import hotkeys from 'hotkeys-js' 2 | 3 | export const useHotkeys = (keys: string, callback: CallableFunction) => { 4 | hotkeys.filter = () => true 5 | hotkeys(keys, (e: Event) => { 6 | e.preventDefault() 7 | callback() 8 | return false 9 | }) 10 | } 11 | 12 | export const removeAllHotkeys = () => { 13 | hotkeys.unbind() 14 | } 15 | -------------------------------------------------------------------------------- /src/composables/i18n.ts: -------------------------------------------------------------------------------- 1 | import { isRecord } from '@tool-belt/type-predicates' 2 | 3 | import { i18n } from '../i18n' 4 | 5 | const { global } = i18n 6 | 7 | // @ts-ignore 8 | export const { t } = global 9 | 10 | export const l = (data: string | Record) => { 11 | if (typeof data === 'string') { 12 | return data 13 | } 14 | 15 | if (isRecord(data)) { 16 | return data[global.locale.value.replace('-', '_')] 17 | } 18 | } 19 | 20 | export const useI18n = () => global 21 | -------------------------------------------------------------------------------- /src/composables/popup.ts: -------------------------------------------------------------------------------- 1 | export function usePopup() { 2 | const popupVisible = ref(false) 3 | 4 | const togglePopup = (visible?: boolean) => { 5 | popupVisible.value = visible ?? !popupVisible.value 6 | } 7 | 8 | return { popupVisible, togglePopup } 9 | } 10 | -------------------------------------------------------------------------------- /src/composables/select.ts: -------------------------------------------------------------------------------- 1 | // 为解决 tdesign-vue-next select 组件的自身 Bug,采用延时渲染来避免 2 | 3 | export function useSelect() { 4 | const selectVisible = ref(false) 5 | 6 | onMounted(() => { 7 | selectVisible.value = true 8 | }) 9 | 10 | return { selectVisible } 11 | } 12 | -------------------------------------------------------------------------------- /src/extensions/audio/index.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | 4 | import NodeView from './node-view.vue' 5 | 6 | declare module '@tiptap/core' { 7 | interface Commands { 8 | setAudio: { 9 | setAudio: (options: any) => ReturnType 10 | } 11 | } 12 | } 13 | export default Node.create({ 14 | name: 'audio', 15 | group: 'block', 16 | atom: true, 17 | addAttributes() { 18 | return { 19 | vnode: { 20 | default: true, 21 | }, 22 | file: { 23 | default: null, 24 | }, 25 | id: { 26 | default: null, 27 | }, 28 | name: { 29 | default: null, 30 | }, 31 | size: { 32 | default: null, 33 | }, 34 | src: { 35 | default: null, 36 | }, 37 | uploaded: { 38 | default: false, 39 | }, 40 | previewType: { 41 | default: 'audio', 42 | }, 43 | } 44 | }, 45 | parseHTML() { 46 | return [{ tag: 'audio' }] 47 | }, 48 | renderHTML({ HTMLAttributes }) { 49 | return ['audio', mergeAttributes(HTMLAttributes)] 50 | }, 51 | addNodeView() { 52 | return VueNodeViewRenderer(NodeView) 53 | }, 54 | addCommands() { 55 | return { 56 | setAudio: 57 | (options) => 58 | ({ commands, editor }) => { 59 | return commands.insertContentAt(editor.state.selection.anchor, { 60 | type: this.name, 61 | attrs: options, 62 | }) 63 | }, 64 | } 65 | }, 66 | }) 67 | -------------------------------------------------------------------------------- /src/extensions/break-marks.ts: -------------------------------------------------------------------------------- 1 | import type { Node } from '@tiptap/pm/model' 2 | import { InvisibleNode } from '@tiptap-pro/extension-invisible-characters' 3 | import InvisibleCharacters, { 4 | HardBreakNode, 5 | ParagraphNode, 6 | } from '@tiptap-pro/extension-invisible-characters' 7 | 8 | class HeadingNode extends InvisibleNode { 9 | constructor() { 10 | super({ 11 | type: 'paragraph', 12 | predicate: (node: Node) => ['heading'].includes(node.type.name), 13 | }) 14 | } 15 | } 16 | 17 | const breakMarks = InvisibleCharacters.configure({ 18 | injectCSS: false, 19 | builders: [new HardBreakNode(), new ParagraphNode(), new HeadingNode()], 20 | }) 21 | 22 | export default breakMarks 23 | -------------------------------------------------------------------------------- /src/extensions/bullet-list.ts: -------------------------------------------------------------------------------- 1 | import BulletList from '@tiptap/extension-bullet-list' 2 | 3 | // https://www.npmjs.com/package/tiptap-extension-bullet-list 4 | export default BulletList.extend({ 5 | content: 'listItem*', 6 | addAttributes() { 7 | return { 8 | ...this.parent?.(), 9 | listType: { 10 | default: 'disc', 11 | parseHTML: (element) => 12 | element.style.getPropertyValue('list-style-type') || 'disc', 13 | renderHTML: ({ listType }) => { 14 | return { 15 | style: `list-style-type: ${listType}`, 16 | type: listType, 17 | } 18 | }, 19 | }, 20 | } 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/extensions/code-block/index.ts: -------------------------------------------------------------------------------- 1 | import CodeBlock from '@tiptap/extension-code-block-lowlight' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | import { common, createLowlight } from 'lowlight' 4 | 5 | import NodeView from './node-view.vue' 6 | 7 | const lowlight = createLowlight(common) 8 | 9 | const customCodeBlock = CodeBlock.extend({ 10 | addAttributes() { 11 | return { 12 | ...this.parent?.(), 13 | language: { 14 | default: 'plaintext', 15 | }, 16 | theme: { 17 | default: 'light', 18 | }, 19 | wordWrap: { 20 | default: true, 21 | }, 22 | } 23 | }, 24 | addNodeView() { 25 | return VueNodeViewRenderer(NodeView) 26 | }, 27 | }) 28 | 29 | export default customCodeBlock.configure({ 30 | lowlight, 31 | }) 32 | -------------------------------------------------------------------------------- /src/extensions/color-highlighter/find-colors.ts: -------------------------------------------------------------------------------- 1 | import { Node } from '@tiptap/pm/model' 2 | import { Decoration, DecorationSet } from '@tiptap/pm/view' 3 | 4 | export default function (doc: Node): DecorationSet { 5 | const hexColor = /(#[0-9a-f]{3,6})\b/gi 6 | const decorations: Decoration[] = [] 7 | 8 | doc.descendants((node, position) => { 9 | if (!node.text) { 10 | return 11 | } 12 | 13 | Array.from(node.text.matchAll(hexColor)).forEach((match) => { 14 | // eslint-disable-next-line prefer-destructuring 15 | const color = match[0] 16 | const index = match.index || 0 17 | const from = position + index 18 | const to = from + color.length 19 | const decoration = Decoration.inline(from, to, { 20 | class: 'umo-color-highlighter', 21 | style: `--color: ${color}`, 22 | }) 23 | 24 | decorations.push(decoration) 25 | }) 26 | }) 27 | 28 | return DecorationSet.create(doc, decorations) 29 | } 30 | -------------------------------------------------------------------------------- /src/extensions/color-highlighter/index.ts: -------------------------------------------------------------------------------- 1 | import { Extension } from '@tiptap/core' 2 | import { Plugin } from '@tiptap/pm/state' 3 | 4 | import findColors from './find-colors' 5 | 6 | export const ColorHighlighter = Extension.create({ 7 | name: 'colorHighlighter', 8 | addProseMirrorPlugins() { 9 | return [ 10 | new Plugin({ 11 | state: { 12 | init(_, { doc }) { 13 | return findColors(doc) 14 | }, 15 | apply(transaction, oldState) { 16 | return transaction.docChanged 17 | ? findColors(transaction.doc) 18 | : oldState 19 | }, 20 | }, 21 | props: { 22 | decorations(state) { 23 | return this.getState(state) 24 | }, 25 | }, 26 | }), 27 | ] 28 | }, 29 | }) 30 | -------------------------------------------------------------------------------- /src/extensions/datetime/index.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | 4 | import NodeView from './node-view.vue' 5 | 6 | declare module '@tiptap/core' { 7 | interface Commands { 8 | insertDatetime: { 9 | insertDatetime: (options: any) => ReturnType 10 | } 11 | } 12 | } 13 | 14 | export default Node.create({ 15 | name: 'datetime', 16 | group: 'inline', 17 | inline: true, 18 | atom: true, 19 | selectable: false, 20 | 21 | addAttributes() { 22 | return { 23 | type: { default: 'datetime' }, 24 | date: { default: null }, 25 | text: { default: '[日期]' }, 26 | format: { default: null }, 27 | withTime: { default: false }, 28 | capitalize: { default: false }, 29 | } 30 | }, 31 | 32 | parseHTML() { 33 | return [{ tag: 'span[data-type="datetime"]' }] 34 | }, 35 | 36 | renderHTML({ HTMLAttributes }) { 37 | return [ 38 | 'span', 39 | mergeAttributes(HTMLAttributes, { 'data-type': 'datetime' }), 40 | HTMLAttributes.text, 41 | ] 42 | }, 43 | 44 | addNodeView() { 45 | return VueNodeViewRenderer(NodeView) 46 | }, 47 | 48 | addCommands() { 49 | return { 50 | insertDatetime: 51 | (options) => 52 | ({ chain }) => { 53 | return chain() 54 | .insertContent({ 55 | type: this.name, 56 | attrs: options, 57 | }) 58 | .run() 59 | }, 60 | } 61 | }, 62 | }) 63 | -------------------------------------------------------------------------------- /src/extensions/echarts/init-service.ts: -------------------------------------------------------------------------------- 1 | /* 2 | //**此服务主要作用** 3 | onMounted 钩子在初次加载时容易出现 echarts-script 已经存在,但 onload 未完成的情况, 4 | 导致第二次进入时判断已存在但实际 echart 还未加载完成,导致只加载出了第一个图表,后续图表都没加载上 5 | loadEchartScript :解决同时加载多个图表时只有第一个图表展示问题。 6 | */ 7 | 8 | const echartsLoadPromise = ref | null>(null) 9 | 10 | // npm 包引入 echarts 会导致整个打包的包变大,为了解决这个问题,现使用 cdn 方式引入 11 | export function useEchartsLoader(options: any) { 12 | return { 13 | // 调用此方法,实现初始化加载 js 脚本 14 | loadEchartScript: () => { 15 | if (!options.toolbar?.disableMenuItems.includes('echarts')) { 16 | if (!echartsLoadPromise.value) { 17 | echartsLoadPromise.value = new Promise((resolve, reject) => { 18 | const existingScript = document.querySelector('#echarts-script') 19 | if (!existingScript) { 20 | const script = document.createElement('script') 21 | script.src = `${options.cdnUrl}/libs/echarts/echarts.min.js` 22 | script.id = 'echarts-script' 23 | script.type = 'text/javascript' 24 | script.onload = () => resolve() 25 | script.onerror = (error) => 26 | reject(new Error(`load Echarts ERROR`)) 27 | document.querySelector('head')!.append(script) 28 | } else { 29 | // 如果脚本已存在,则立即解析 Promise 30 | resolve() 31 | } 32 | }) 33 | } 34 | return echartsLoadPromise.value 35 | } else { 36 | return null 37 | } 38 | }, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/extensions/iframe/index.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | 4 | import NodeView from './node-view.vue' 5 | declare module '@tiptap/core' { 6 | interface Commands { 7 | setIframe: { 8 | setIframe: (options: any) => ReturnType 9 | } 10 | } 11 | } 12 | export default Node.create({ 13 | name: 'iframe', 14 | inline: false, 15 | group: 'block', 16 | atom: true, 17 | addAttributes() { 18 | return { 19 | vnode: { 20 | default: true, 21 | }, 22 | type: { 23 | default: 0, 24 | }, 25 | src: { 26 | default: null, 27 | }, 28 | width: { 29 | default: null, 30 | }, 31 | height: { 32 | default: 200, 33 | }, 34 | clickable: { 35 | default: false, 36 | }, 37 | } 38 | }, 39 | parseHTML() { 40 | return [{ tag: 'iframe' }] 41 | }, 42 | renderHTML({ HTMLAttributes }) { 43 | return [ 44 | 'iframe', 45 | mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 46 | ] 47 | }, 48 | addNodeView() { 49 | return VueNodeViewRenderer(NodeView) 50 | }, 51 | addCommands() { 52 | return { 53 | setIframe: 54 | (options) => 55 | ({ commands }) => { 56 | return commands.insertContent({ 57 | type: this.name, 58 | attrs: options, 59 | }) 60 | }, 61 | } 62 | }, 63 | }) 64 | -------------------------------------------------------------------------------- /src/extensions/link.ts: -------------------------------------------------------------------------------- 1 | import Link from '@tiptap/extension-link' 2 | import { Plugin } from '@tiptap/pm/state' 3 | 4 | const CustomLink = Link.extend({ 5 | addStorage() { 6 | return { 7 | edit: false, 8 | meta: {}, 9 | } 10 | }, 11 | addProseMirrorPlugins() { 12 | return [ 13 | new Plugin({ 14 | props: { 15 | handleClick(view, pos, event) { 16 | const target = event.target as HTMLElement 17 | if (target.tagName === 'A') { 18 | const href = target.getAttribute('href') 19 | view.dispatch( 20 | view.state.tr.setMeta('link-click', { 21 | target, 22 | href, 23 | pos, 24 | }), 25 | ) 26 | return true 27 | } 28 | return false 29 | }, 30 | }, 31 | }), 32 | ] 33 | }, 34 | onTransaction({ transaction }) { 35 | const meta = transaction.getMeta('link-click') 36 | if (meta) { 37 | this.storage.edit = true 38 | this.storage.meta = meta 39 | } 40 | }, 41 | }) 42 | 43 | CustomLink.configure({ 44 | // @ts-ignore 45 | openOnClick: (props) => !props.editor.isEditable, 46 | }) 47 | 48 | export default CustomLink 49 | -------------------------------------------------------------------------------- /src/extensions/mention/index.ts: -------------------------------------------------------------------------------- 1 | import Mention from '@tiptap/extension-mention' 2 | 3 | declare module '@tiptap/core' { 4 | interface Commands { 5 | insertMention: { 6 | insertMention: (options: any) => ReturnType 7 | } 8 | } 9 | } 10 | 11 | const CustomMention = Mention.extend({ 12 | addAttributes() { 13 | return { 14 | id: { 15 | default: null, 16 | }, 17 | label: { 18 | default: null, 19 | }, 20 | } 21 | }, 22 | addCommands() { 23 | return { 24 | insertMention: 25 | () => 26 | ({ commands }) => { 27 | return commands.insertContent( 28 | ` ${this.options?.suggestion?.char ?? '@'}`, 29 | ) 30 | }, 31 | } 32 | }, 33 | }) 34 | 35 | // 配置并导出扩展 36 | export default CustomMention.configure({ 37 | HTMLAttributes: { 38 | class: 'umo-node-mention', 39 | }, 40 | }) 41 | -------------------------------------------------------------------------------- /src/extensions/ordered-list.ts: -------------------------------------------------------------------------------- 1 | import OrderedList from '@tiptap/extension-ordered-list' 2 | 3 | // https://www.npmjs.com/package/tiptap-extension-ordered-list 4 | export default OrderedList.extend({ 5 | content: 'listItem*', 6 | addAttributes() { 7 | return { 8 | ...this.parent?.(), 9 | listType: { 10 | default: 'decimal', 11 | parseHTML: (element) => 12 | element.style.getPropertyValue('list-style-type') || 'decimal', 13 | renderHTML: ({ listType }) => { 14 | return { 15 | style: `list-style-type: ${listType}`, 16 | type: listType, 17 | } 18 | }, 19 | }, 20 | } 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /src/extensions/page-break.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | 3 | declare module '@tiptap/core' { 4 | interface Commands { 5 | setPageBreak: { 6 | setPageBreak: () => ReturnType 7 | } 8 | } 9 | } 10 | 11 | export default Node.create({ 12 | name: 'pageBreak', 13 | group: 'block', 14 | addOptions() { 15 | return { 16 | HTMLAttributes: { 17 | class: 'umo-page-break', 18 | 'data-line-number': false, 19 | 'data-content': t('page.break'), 20 | }, 21 | } 22 | }, 23 | parseHTML() { 24 | return [{ tag: 'div[class*="umo-page-break"]' }] 25 | }, 26 | renderHTML({ HTMLAttributes }) { 27 | return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)] 28 | }, 29 | addCommands() { 30 | return { 31 | setPageBreak: 32 | () => 33 | ({ commands }) => 34 | commands.insertContent({ 35 | type: this.name, 36 | }), 37 | } 38 | }, 39 | addKeyboardShortcuts() { 40 | return { 41 | 'Mod-Enter': () => this.editor.commands.setPageBreak(), 42 | } 43 | }, 44 | }) 45 | -------------------------------------------------------------------------------- /src/extensions/table/cell.ts: -------------------------------------------------------------------------------- 1 | import TableCell from '@tiptap/extension-table-cell' 2 | 3 | const TableCellOptions = { 4 | addAttributes(): any { 5 | return { 6 | // @ts-ignore 7 | ...this.parent?.(), 8 | align: { 9 | default: null, 10 | parseHTML: (element: any) => element.getAttribute('align') ?? null, 11 | renderHTML: ({ align }: any) => ({ align }), 12 | }, 13 | background: { 14 | default: null, 15 | parseHTML: (element: any) => { 16 | const style = element.getAttribute('style') ?? '' 17 | const match = style.match(/background(?:-color)?:\s*([^;]+)/i) 18 | return match ? match[1].trim() : null 19 | }, 20 | renderHTML: ({ background }: any) => { 21 | return background ? { style: `background-color: ${background}` } : {} 22 | }, 23 | }, 24 | color: { 25 | default: null, 26 | parseHTML: (element: any) => { 27 | const style = element.getAttribute('style') ?? '' 28 | const match = style.match(/(? { 33 | return color ? { style: `color: ${color}` } : {} 34 | }, 35 | }, 36 | } 37 | }, 38 | } 39 | 40 | export default TableCell.extend(TableCellOptions) 41 | export { TableCellOptions } 42 | -------------------------------------------------------------------------------- /src/extensions/table/header.ts: -------------------------------------------------------------------------------- 1 | import TableHeader from '@tiptap/extension-table-header' 2 | 3 | import { TableCellOptions } from './cell' 4 | 5 | export default TableHeader.extend(TableCellOptions) 6 | -------------------------------------------------------------------------------- /src/extensions/tag/index.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | 4 | import NodeView from './node-view.vue' 5 | 6 | declare module '@tiptap/core' { 7 | interface Commands { 8 | insertTag: { 9 | insertTag: (options: any) => ReturnType 10 | } 11 | } 12 | } 13 | 14 | export default Node.create({ 15 | name: 'tag', 16 | group: 'inline', 17 | inline: true, 18 | atom: true, 19 | 20 | addAttributes() { 21 | return { 22 | type: { default: 'default' }, 23 | text: { default: '标签内容' }, 24 | color: { default: '#999' }, 25 | backgroundColor: { default: 'rgba(0, 0, 0, 0.05)' }, 26 | } 27 | }, 28 | 29 | parseHTML() { 30 | return [{ tag: 'span[data-type="tag"]' }] 31 | }, 32 | 33 | renderHTML({ HTMLAttributes }) { 34 | return [ 35 | 'span', 36 | mergeAttributes(HTMLAttributes, { 'data-type': 'tag' }), 37 | HTMLAttributes.text, 38 | ] 39 | }, 40 | 41 | addNodeView() { 42 | return VueNodeViewRenderer(NodeView) 43 | }, 44 | 45 | addCommands() { 46 | return { 47 | insertTag: 48 | (options) => 49 | ({ chain }) => { 50 | return chain() 51 | .insertContent({ 52 | type: this.name, 53 | attrs: options, 54 | }) 55 | .run() 56 | }, 57 | } 58 | }, 59 | }) 60 | -------------------------------------------------------------------------------- /src/extensions/tag/node-view.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 19 | 20 | 39 | -------------------------------------------------------------------------------- /src/extensions/text-align.ts: -------------------------------------------------------------------------------- 1 | import TextAlign from '@tiptap/extension-text-align' 2 | 3 | export default TextAlign.extend({ 4 | addOptions() { 5 | return { 6 | ...this.parent?.(), 7 | types: ['heading', 'paragraph'], 8 | alignments: ['left', 'center', 'right', 'justify', 'distributed'], 9 | } 10 | }, 11 | addGlobalAttributes() { 12 | return [ 13 | { 14 | types: this.options.types, 15 | attributes: { 16 | textAlign: { 17 | default: this.options.defaultAlignment, 18 | parseHTML: (element) => { 19 | if (element.style.textAlignLast) { 20 | return 'distributed' 21 | } 22 | return element.style.textAlign || this.options.defaultAlignment 23 | }, 24 | renderHTML: (attributes) => { 25 | if (attributes.textAlign === this.options.defaultAlignment) { 26 | return {} 27 | } 28 | if (attributes.textAlign === 'distributed') { 29 | return { style: 'text-align-last: justify' } 30 | } 31 | return { style: `text-align: ${attributes.textAlign}` } 32 | }, 33 | }, 34 | }, 35 | }, 36 | ] 37 | }, 38 | addKeyboardShortcuts() { 39 | return { 40 | ...this.parent?.(), 41 | 'Mod-Shift-d': () => this.editor.commands.setTextAlign('distributed'), 42 | } 43 | }, 44 | }) 45 | -------------------------------------------------------------------------------- /src/extensions/toc/index.ts: -------------------------------------------------------------------------------- 1 | import { mergeAttributes, Node } from '@tiptap/core' 2 | import { VueNodeViewRenderer } from '@tiptap/vue-3' 3 | 4 | import NodeView from './node-view.vue' 5 | declare module '@tiptap/core' { 6 | interface Commands { 7 | addTableOfContents: { 8 | addTableOfContents: (option: any) => ReturnType 9 | } 10 | } 11 | } 12 | export default Node.create({ 13 | name: 'toc', 14 | group: 'block', 15 | atom: true, 16 | addAttributes() { 17 | return { 18 | vnode: { 19 | default: true, 20 | }, 21 | } 22 | }, 23 | parseHTML() { 24 | return [{ tag: 'toc' }] 25 | }, 26 | renderHTML({ HTMLAttributes }) { 27 | return ['toc', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)] 28 | }, 29 | addNodeView() { 30 | return VueNodeViewRenderer(NodeView) 31 | }, 32 | addGlobalAttributes() { 33 | return [ 34 | { 35 | types: ['heading'], 36 | attributes: {}, 37 | }, 38 | ] 39 | }, 40 | addCommands() { 41 | return { 42 | addTableOfContents: 43 | (options) => 44 | ({ chain }) => { 45 | return chain() 46 | .insertContent({ 47 | type: this.name, 48 | attrs: options, 49 | }) 50 | .run() 51 | }, 52 | } 53 | }, 54 | }) 55 | -------------------------------------------------------------------------------- /src/i18n.ts: -------------------------------------------------------------------------------- 1 | import { createI18n } from 'vue-i18n' 2 | 3 | import en_US from './locales/en-US.json' 4 | import ru_RU from './locales/ru-RU.json' 5 | import zh_CN from './locales/zh-CN.json' 6 | 7 | export const i18n = createI18n({ 8 | legacy: false, 9 | locale: 'zh-CN', 10 | defaultLocale: 'zh-CN', 11 | messages: { 12 | 'en-US': en_US, 13 | 'zh-CN': zh_CN, 14 | 'ru-RU': ru_RU, 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import type { UmoEditorOptions } from '@/types' 2 | 3 | import App from './app.vue' 4 | import { useUmoEditor } from './components' 5 | const app = createApp(App) 6 | 7 | const options = {} 8 | 9 | app.use(useUmoEditor, options as unknown as UmoEditorOptions) 10 | 11 | app.mount('#app') 12 | -------------------------------------------------------------------------------- /src/utils/browser.ts: -------------------------------------------------------------------------------- 1 | const nav = typeof navigator !== 'undefined' ? navigator : null 2 | const doc = typeof document !== 'undefined' ? document : null 3 | export const agent = nav?.userAgent ?? '' 4 | 5 | export const ie_edge = /Edg\/(\d+)/.exec(agent) 6 | export const ie_upto10 = /MSIE \d/.exec(agent) 7 | export const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(agent) 8 | 9 | export const ie = !!(ie_upto10 ?? ie_11up ?? ie_edge) 10 | export const ie_version = ie_upto10 11 | ? Reflect.get(document, 'documentMode') 12 | : ie_11up 13 | ? +ie_11up[1] 14 | : ie_edge 15 | ? +ie_edge[1] 16 | : 0 17 | export const gecko = !ie && /gecko\/(\d+)/i.test(agent) 18 | export const gecko_version = 19 | gecko && +(/Firefox\/(\d+)/.exec(agent) ?? [0, 0])[1] 20 | 21 | export const chrome = Boolean(!ie && /Chrome\/(\d+)/.test(agent)) 22 | export const chrome_version: number = chrome 23 | ? Number.parseInt(/Chrome\/(\d+)/.exec(agent)?.[1] ?? '0', 10) 24 | : 0 25 | export const safari = !ie && !!nav && nav.vendor.includes('Apple Computer') 26 | // Is true for both iOS and iPadOS for convenience 27 | export const ios = 28 | safari && (/Mobile\/\w+/.test(agent) || (!!nav && nav.maxTouchPoints > 2)) 29 | export const mac = ios || (nav ? nav.platform.includes('Mac') : false) 30 | export const windows = nav ? nav.platform.includes('Win') : false 31 | export const android = /Android \d/.test(agent) 32 | export const webkit = 33 | !!doc && 'webkitFontSmoothing' in doc.documentElement.style 34 | export const webkit_version = webkit 35 | ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) ?? [0, 0])[1] 36 | : 0 37 | -------------------------------------------------------------------------------- /src/utils/content-transform.ts: -------------------------------------------------------------------------------- 1 | export const contentTransform = (content: string) => { 2 | // 处理空内容或非字符串内容 3 | if (content && typeof content === 'string' && !content.startsWith('<')) { 4 | // 处理纯文本中的换行符 5 | console.log(content.split('\n')) 6 | return content 7 | .split('\n') 8 | .map((line) => `

${line}

`) 9 | .join('') 10 | } 11 | 12 | return content 13 | } 14 | -------------------------------------------------------------------------------- /src/utils/copyright.ts: -------------------------------------------------------------------------------- 1 | import pkg from '../../package.json' 2 | 3 | export default `/** 4 | * ${pkg.name} ${pkg.version} 5 | * @license ${pkg.license} 6 | * @author ${pkg.author.name} ${pkg.author.url} 7 | * @see ${pkg.homepage} 8 | **/ 9 | ` 10 | 11 | export const consoleCopyright = () => { 12 | console.info( 13 | t('welcome', { version: pkg.version, homepage: pkg.homepage }), 14 | 'background:#3480f9;color:#fff;border-top-left-radius:3px;border-bottom-left-radius:3px;padding:4px 8px 3px;', 15 | 'background:#fff;color:#3480f9;border-top-right-radius:3px;border-bottom-right-radius:3px;border:solid 1px #3480f9;padding:3px 8px 2px;', 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/functional.ts: -------------------------------------------------------------------------------- 1 | import { isPromise } from '@tool-belt/type-predicates' 2 | 3 | /** 4 | * Wraps a function with error suppression and optional logging. 5 | * 6 | * @param fn - The function to execute. 7 | * @param errorMessage - The error message to log if an exception is thrown. 8 | * @returns The wrapped function with error suppression. 9 | */ 10 | export function withSuppress any>( 11 | fn: T, 12 | errorMessage?: string, 13 | ): ( 14 | ...args: Parameters 15 | ) => ReturnType extends Promise 16 | ? Promise 17 | : ReturnType | undefined { 18 | const log = errorMessage ? (msg: string) => console.error(msg) : null 19 | 20 | return (...args: Parameters) => { 21 | try { 22 | const result = fn(...args) 23 | 24 | if (isPromise(result)) { 25 | return result.catch((error) => { 26 | log?.(`${errorMessage}\n${error?.stack ?? error}`) 27 | return undefined 28 | }) 29 | } 30 | 31 | return result 32 | } catch (error) { 33 | log?.( 34 | `${errorMessage}\n${Reflect.get(error as Record, 'stack') ?? error}`, 35 | ) 36 | return undefined 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/utils/options.ts: -------------------------------------------------------------------------------- 1 | import { isRecord } from '@tool-belt/type-predicates' 2 | 3 | import { defaultOptions, ojbectSchema } from '@/options' 4 | 5 | export const getOpitons = (propsOptions: unknown, globalOptions?: unknown) => { 6 | const propsOptionsValue = 7 | isRecord(propsOptions) && Object.keys(propsOptions).includes('value') 8 | ? propsOptions.value 9 | : propsOptions 10 | 11 | const componentOptions = Object.keys(propsOptionsValue).reduce< 12 | Record 13 | >((acc: Record, key: string) => { 14 | if (propsOptionsValue[key] !== undefined) { 15 | acc[key] = propsOptionsValue[key] 16 | } 17 | return acc 18 | }, {}) 19 | 20 | const options = ojbectSchema.merge( 21 | defaultOptions, 22 | globalOptions || {}, 23 | componentOptions, 24 | ) 25 | 26 | return options 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/short-id.ts: -------------------------------------------------------------------------------- 1 | export const shortId = (length = 8) => 2 | Math.random() 3 | .toString(36) 4 | .substring(2, length + 2) 5 | -------------------------------------------------------------------------------- /src/utils/shortcut.ts: -------------------------------------------------------------------------------- 1 | export const getShortcut = (shortcut: string) => { 2 | if (!shortcut) { 3 | return '' 4 | } 5 | // 判断是 Mac OS 6 | const isMacOS = /macintosh|mac os x/gi.test(navigator.userAgent) 7 | let keys = shortcut 8 | if (isMacOS) { 9 | keys = keys 10 | .replace(/ctrl/gi, '⌘') 11 | .replace(/shift/gi, '⇧') 12 | .replace(/alt/gi, '⌥') 13 | .replace(/Enter/gi, 'Return') 14 | .replace(/Backspace/gi, 'Delete') 15 | } 16 | return keys 17 | } 18 | -------------------------------------------------------------------------------- /src/utils/time-ago.ts: -------------------------------------------------------------------------------- 1 | export const timeAgo = (timestamp: string | number | Date) => { 2 | const messages = { 3 | justNow: t('time.justNow'), 4 | past: (n: string | number | Date) => 5 | n.toString().match(/\d/) ? t('time.past', { n }) : n, 6 | day: (n: Date | number | string) => 7 | n === 1 ? t('time.yesterday') : t('time.day', { n }), 8 | hour: (n: string | number | Date) => t('time.hour', { n }), 9 | minute: (n: string | number | Date) => t('time.minute', { n }), 10 | second: (n: string | number | Date) => t('time.second', { n }), 11 | } as const 12 | const time = useTimeAgo(new Date(timestamp), { 13 | messages: messages as any, 14 | }) 15 | return time.value.replace(/"/gi, '') 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noImplicitAny": false, 4 | "removeComments": true, 5 | "disableSizeLimit": true, 6 | "target": "ESNext", 7 | "module": "ESNext", 8 | "strict": true, 9 | "allowJs": true, 10 | "noEmit": true, 11 | "jsx": "preserve", 12 | "moduleResolution": "bundler", 13 | "experimentalDecorators": true, 14 | "resolveJsonModule": true, 15 | "skipLibCheck": true, 16 | "esModuleInterop": true, 17 | "allowSyntheticDefaultImports": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "useDefineForClassFields": true, 20 | "verbatimModuleSyntax": true, 21 | "sourceMap": true, 22 | "baseUrl": ".", 23 | "types": [ 24 | "vue", 25 | "unplugin-vue-macros/macros-global", 26 | "@vue-macros/reactivity-transform/macros-global", 27 | "vite/client", 28 | "vitest/globals", 29 | "vitest", 30 | "./types/imports.d.ts", 31 | "./types/components.d.ts" 32 | ], 33 | "paths": { 34 | "@/*": ["./src/*"], 35 | "@/types": ["./types"] 36 | }, 37 | "lib": ["ESNext", "DOM", "DOM.Iterable", "ScriptHost"] 38 | }, 39 | "vueCompilerOptions": { 40 | "plugins": ["unplugin-vue-macros/volar"] 41 | }, 42 | "include": [ 43 | "*.mjs", 44 | "*.ts", 45 | "*.d.ts", 46 | "types/**/*.d.ts", 47 | "src/**/*.ts", 48 | "src/**/*.vue", 49 | "src/**/*.spec.ts", 50 | "src/**/*.spec.tsx", 51 | "src/**/*.d.ts" 52 | ], 53 | "exclude": ["node_modules", "dist"] 54 | } 55 | -------------------------------------------------------------------------------- /types/shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { DefineComponent } from 'vue' 3 | const component: DefineComponent< 4 | Record, 5 | Record, 6 | any 7 | > 8 | export default component 9 | } 10 | 11 | declare module '@vue/runtime-core' { 12 | interface ComponentCustomProperties { 13 | t: (key: string, ...args: any[]) => any 14 | } 15 | } 16 | 17 | declare function t(key: string, ...args: any[]): any 18 | 19 | declare module 'dom-to-image-more' { 20 | export function toBlob(node: HTMLElement, options?: any): Promise 21 | export function toJpeg(node: HTMLElement, options?: any): Promise 22 | export function toPng(node: HTMLElement, options?: any): Promise 23 | } 24 | declare const echarts: any 25 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, mergeConfig } from 'vitest/config' 2 | 3 | import viteConfig from './vite.config' 4 | 5 | const testConfig = defineConfig({ 6 | test: { 7 | environment: 'jsdom', 8 | globals: true, 9 | setupFiles: [], 10 | coverage: { 11 | include: ['src'], 12 | exclude: ['**/*.spec.*', '**/*.d.ts', 'src/types.ts', 'testing/*'], 13 | }, 14 | onConsoleLog(log: string) { 15 | if ( 16 | log.includes( 17 | 'Error: Not implemented: HTMLFormElement.prototype.requestSubmit', 18 | ) || 19 | log.includes('(node:25503) [DEP0040]') 20 | ) { 21 | return false 22 | } 23 | }, 24 | }, 25 | }) 26 | 27 | export default mergeConfig(viteConfig, testConfig) 28 | --------------------------------------------------------------------------------