├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── .vitepress │ ├── config.ts │ └── theme │ │ ├── Layout.vue │ │ ├── components │ │ └── NodeEditor.vue │ │ └── index.ts ├── changelog.md ├── extensions │ ├── block-container.md │ ├── code-block-shiki.md │ ├── details.md │ ├── emoji.md │ └── unique-id.md ├── guide │ └── vue.md ├── index.md ├── playground.md └── zh-CN │ ├── changelog.md │ ├── extensions │ ├── block-container.md │ ├── code-block-shiki.md │ ├── details.md │ ├── emoji.md │ └── unique-id.md │ ├── guide │ └── vue.md │ ├── index.md │ └── playground.md ├── eslint.config.js ├── migrations.json ├── nx.json ├── package.json ├── packages ├── tiptap-extension-block-container │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── blockContainer.css │ │ ├── blockContainer.ts │ │ ├── extentDocument.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts ├── tiptap-extension-code-block-shiki │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── codeBlockShiki.css │ │ ├── codeBlockShiki.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts ├── tiptap-extension-details │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── project.json │ ├── src │ │ ├── details.ts │ │ ├── detailsContent.ts │ │ ├── detailsSummary.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts ├── tiptap-extension-emoji │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── emoji.ts │ │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts ├── tiptap-extension-unique-id │ ├── README.md │ ├── eslint.config.js │ ├── package.json │ ├── project.json │ ├── src │ │ ├── index.ts │ │ └── uniqueId.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts ├── vue-kit │ ├── README.md │ ├── package.json │ ├── project.json │ ├── src │ │ ├── components │ │ │ └── NoteEditor.vue │ │ ├── composables │ │ │ └── useNoteEditor.ts │ │ ├── index.ts │ │ ├── setupKit.ts │ │ └── vue-shims.d.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── vite.config.ts └── vue-play │ ├── index.html │ ├── package.json │ ├── project.json │ ├── src │ ├── App.vue │ └── main.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── vite.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── tsconfig.base.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | 41 | .nx/cache 42 | .nx/workspace-data 43 | 44 | # vitepress docs 45 | docs/.vitepress/cache -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no -- commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.experimental.useFlatConfig": true, 3 | "prettier.enable": false, 4 | "editor.formatOnSave": true, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll.eslint": "explicit", 7 | "source.organizeImports": "never" 8 | }, 9 | "eslint.rules.customizations": [ 10 | { "rule": "style/*", "severity": "off" }, 11 | { "rule": "format/*", "severity": "off" }, 12 | { "rule": "*-indent", "severity": "off" }, 13 | { "rule": "*-spacing", "severity": "off" }, 14 | { "rule": "*-spaces", "severity": "off" }, 15 | { "rule": "*-order", "severity": "off" }, 16 | { "rule": "*-dangle", "severity": "off" }, 17 | { "rule": "*-newline", "severity": "off" }, 18 | { "rule": "*quotes", "severity": "off" }, 19 | { "rule": "*semi", "severity": "off" } 20 | ], 21 | "eslint.validate": [ 22 | "javascript", 23 | "javascriptreact", 24 | "typescript", 25 | "typescriptreact", 26 | "vue", 27 | "html", 28 | "markdown", 29 | "json", 30 | "jsonc", 31 | "yaml", 32 | "toml" 33 | ], 34 | "cSpell.words": [ 35 | "blockquote", 36 | "dropcursor", 37 | "emojilib", 38 | "Gapcursor", 39 | "Prosemirror", 40 | "shiki", 41 | "unref" 42 | ], 43 | "typescript.tsdk": "node_modules/typescript/lib" 44 | } 45 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.3.1 (2024-04-20) 2 | 3 | 4 | ### 🚀 Features 5 | 6 | - **emoji:** remove ^ for input rules ([b4d8f7c](https://github.com/litingyes/note-editor/commit/b4d8f7c)) 7 | 8 | ### 🩹 Fixes 9 | 10 | - **block-container:** split error ([d000839](https://github.com/litingyes/note-editor/commit/d000839)) 11 | 12 | ### ❤️ Thank You 13 | 14 | - liting @litingyes 15 | 16 | ## 0.3.0 (2024-03-29) 17 | 18 | 19 | ### 🚀 Features 20 | 21 | - **emoji:** init ([cb7bfa8](https://github.com/liting-yes/note-editor/commit/cb7bfa8)) 22 | 23 | ### 🩹 Fixes 24 | 25 | - **code-block-shiki:** type check error ([335afec](https://github.com/liting-yes/note-editor/commit/335afec)) 26 | - **code-block-shiki:** decorations parse error ([3d36f20](https://github.com/liting-yes/note-editor/commit/3d36f20)) 27 | 28 | ### ❤️ Thank You 29 | 30 | - liting @liting-yes 31 | 32 | ## 0.2.1 (2024-03-27) 33 | 34 | 35 | ### 🩹 Fixes 36 | 37 | - **code-block-shiki:** find code-block change and highlighter is valid ([c4ce39e](https://github.com/liting-yes/note-editor/commit/c4ce39e)) 38 | 39 | ### ❤️ Thank You 40 | 41 | - liting @liting-yes 42 | 43 | ## 0.2.0 (2024-03-27) 44 | 45 | 46 | ### 🚀 Features 47 | 48 | - **details:** done ([681d497](https://github.com/liting-yes/note-editor/commit/681d497)) 49 | - **unique id:** add types as default value ([5041e98](https://github.com/liting-yes/note-editor/commit/5041e98)) 50 | - **vue-kit:** export vue sfc instance type ([c55e238](https://github.com/liting-yes/note-editor/commit/c55e238)) 51 | 52 | ### 🩹 Fixes 53 | 54 | - **code-block-shiki:** handle highlighter is null ([2c35721](https://github.com/liting-yes/note-editor/commit/2c35721)) 55 | - **unique-id:** traversal logic in create ([f0de32b](https://github.com/liting-yes/note-editor/commit/f0de32b)) 56 | 57 | ### ❤️ Thank You 58 | 59 | - liting @liting-yes 60 | 61 | ## 0.1.0 (2024-03-24) 62 | 63 | 64 | ### 🚀 Features 65 | 66 | - **code-block-shiki:** support display and toggle lang ([9e60091](https://github.com/liting-yes/note-editor/commit/9e60091)) 67 | 68 | ### 🩹 Fixes 69 | 70 | - **code-block-shiki:** calculate the length of ([9086c2a](https://github.com/liting-yes/note-editor/commit/9086c2a)) 71 | 72 | ### ❤️ Thank You 73 | 74 | - liting @liting-yes 75 | 76 | ## 0.0.1-10 (2024-03-22) 77 | 78 | 79 | ### 🚀 Features 80 | 81 | - **block-container:** reader drag bar ([7ed9c3e](https://github.com/liting-yes/note-editor/commit/7ed9c3e)) 82 | - **code-block-shiki:** init ([ac6393f](https://github.com/liting-yes/note-editor/commit/ac6393f)) 83 | - **shiki:** support option theme ([86c7258](https://github.com/liting-yes/note-editor/commit/86c7258)) 84 | - **unique id:** add blockContainer as default type ([db331a5](https://github.com/liting-yes/note-editor/commit/db331a5)) 85 | - **unique id:** support inject node-name ([12bcd5f](https://github.com/liting-yes/note-editor/commit/12bcd5f)) 86 | - **vue:** add code block ([0a4a99a](https://github.com/liting-yes/note-editor/commit/0a4a99a)) 87 | 88 | ### 🩹 Fixes 89 | 90 | - **block container:** set attrs on dom ([9c34cc7](https://github.com/liting-yes/note-editor/commit/9c34cc7)) 91 | - **block container:** handle enter ([25cb01e](https://github.com/liting-yes/note-editor/commit/25cb01e)) 92 | - **shiki:** highlighter-generic type ([8089bac](https://github.com/liting-yes/note-editor/commit/8089bac)) 93 | 94 | ### ❤️ Thank You 95 | 96 | - liting @liting-yes 97 | 98 | ## 0.0.1-9 (2024-03-07) 99 | 100 | This was a version bump only, there were no code changes. 101 | 102 | ## 0.0.1-8 (2024-03-07) 103 | 104 | 105 | ### 🚀 Features 106 | 107 | - **dragBar:** support split by enter ([363cb91](https://github.com/liting-yes/note-editor/commit/363cb91)) 108 | 109 | ### ❤️ Thank You 110 | 111 | - liting @liting-yes 112 | 113 | ## 0.0.1-7 (2024-03-06) 114 | 115 | This was a version bump only, there were no code changes. 116 | 117 | ## 0.0.1-6 (2024-03-04) 118 | 119 | 120 | ### 🚀 Features 121 | 122 | - **vue-kit:** support pass editorOptions in useNoteEditor ([f06c5ff](https://github.com/liting-yes/note-editor/commit/f06c5ff)) 123 | 124 | ### 🩹 Fixes 125 | 126 | - **tiptap-extension-unique-id:** generate id error ([94ec0b8](https://github.com/liting-yes/note-editor/commit/94ec0b8)) 127 | 128 | ### ❤️ Thank You 129 | 130 | - liting @liting-yes 131 | 132 | ## 0.0.1-4 (2024-03-02) 133 | 134 | 135 | ### 🚀 Features 136 | 137 | - **vue-kit:** add focus and underline extensions ([a89188a](https://github.com/liting-yes/note-editor/commit/a89188a)) 138 | - **vue-kit:** add useNoteEditor ([9ba3469](https://github.com/liting-yes/note-editor/commit/9ba3469)) 139 | - **vue-kit:** add unique-id ([eb87840](https://github.com/liting-yes/note-editor/commit/eb87840)) 140 | 141 | ### ❤️ Thank You 142 | 143 | - liting @liting-yes 144 | 145 | ## 0.0.1-3 (2024-03-02) 146 | 147 | 148 | ### 🩹 Fixes 149 | 150 | - dependencies ([7e32e0a](https://github.com/liting-yes/note-editor/commit/7e32e0a)) 151 | 152 | ### ❤️ Thank You 153 | 154 | - liting @liting-yes 155 | 156 | ## 0.0.1-2 (2024-03-02) 157 | 158 | 159 | ### 🚀 Features 160 | 161 | - init @note-editor/vue-kit ([b8666fa](https://github.com/liting-yes/note-editor/commit/b8666fa)) 162 | 163 | ### ❤️ Thank You 164 | 165 | - liting @liting-yes 166 | 167 | ## 0.0.1-1 (2024-03-01) 168 | 169 | 170 | ### 🚀 Features 171 | 172 | - init tiptap-extension-unique-id ([418406d](https://github.com/liting-yes/note-editor/commit/418406d)) 173 | 174 | ### ❤️ Thank You 175 | 176 | - liting @liting-yes -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Liting 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Note Editor 2 | 3 | Tiptap-based text editor 4 | 5 | > [!IMPORTANT] 6 | > Trying out best practice: [Rich text editor with Vue.js & Tiptap](https://github.com/vueditor/rich-text-editor.git) 7 | -------------------------------------------------------------------------------- /docs/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | export default defineConfig({ 4 | title: 'Note Editor', 5 | description: 'Tiptap-based text editor', 6 | lastUpdated: true, 7 | themeConfig: { 8 | socialLinks: [ 9 | { 10 | icon: 'npm', 11 | link: 'https://www.npmjs.com/settings/note-editor/packages', 12 | }, 13 | { 14 | icon: 'github', 15 | link: 'https://github.com/liting-yes/note-editor.git', 16 | }, 17 | ], 18 | footer: { 19 | message: 'Released under the MIT License.', 20 | copyright: 'Copyright © 2024-present Liting', 21 | }, 22 | search: { 23 | provider: 'local', 24 | }, 25 | }, 26 | locales: { 27 | 'root': { 28 | label: 'English', 29 | lang: 'en-US', 30 | themeConfig: { 31 | nav: [ 32 | { text: 'Guide', link: '/guide/vue' }, 33 | { text: 'Extensions', link: '/extensions/block-container' }, 34 | { text: 'Playground', link: '/playground' }, 35 | { text: 'CHANGELOG', link: '/changelog' }, 36 | ], 37 | sidebar: [ 38 | { 39 | text: 'Guide', 40 | items: [ 41 | { text: 'Vue', link: '/guide/vue' }, 42 | ], 43 | }, 44 | { 45 | text: 'Extensions', 46 | items: [ 47 | { text: 'Block container', link: '/extensions/block-container' }, 48 | { text: 'Code block shiki', link: '/extensions/code-block-shiki' }, 49 | { text: 'Details', link: '/extensions/details' }, 50 | { text: 'Emoji', link: '/extensions/emoji' }, 51 | { text: 'Unique ID', link: '/extensions/unique-id' }, 52 | ], 53 | }, 54 | { 55 | text: 'Playground', 56 | link: '/playground', 57 | }, 58 | ], 59 | }, 60 | }, 61 | 'zh-CN': { 62 | label: '简体中文', 63 | lang: 'zh-CN', 64 | themeConfig: { 65 | nav: [ 66 | { text: '指南', link: '/zh-CN/guide/vue' }, 67 | { text: '插件', link: '/zh-CN/extensions/block-container' }, 68 | { text: '演练场', link: '/zh-CN/playground' }, 69 | { text: 'CHANGELOG', link: '/zh-CN/changelog' }, 70 | 71 | ], 72 | sidebar: [ 73 | { 74 | text: '指南', 75 | items: [ 76 | { text: 'Vue', link: '/zh-CN/guide/vue' }, 77 | ], 78 | }, 79 | { 80 | text: '插件', 81 | items: [ 82 | { text: 'Block container (块容器)', link: '/zh-CN/extensions/block-container' }, 83 | { text: 'Code block shiki (shiki代码块)', link: '/zh-CN/extensions/code-block-shiki' }, 84 | { text: 'Details (详情块)', link: '/zh-CN/extensions/details' }, 85 | { text: 'Emoji (表情)', link: '/zh-CN/extensions/emoji' }, 86 | { text: 'Unique ID (唯一ID)', link: '/zh-CN/extensions/unique-id' }, 87 | ], 88 | }, 89 | { 90 | text: 'Playground (演练场)', 91 | link: '/zh-CN/playground', 92 | }, 93 | ], 94 | }, 95 | }, 96 | }, 97 | }) 98 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/Layout.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 47 | 48 | 73 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/components/NodeEditor.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 28 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import type { Theme } from 'vitepress' 2 | import DefaultTheme from 'vitepress/theme' 3 | import Layout from './Layout.vue' 4 | import NodeEditor from './components/NodeEditor.vue' 5 | 6 | export default { 7 | extends: DefaultTheme, 8 | Layout, 9 | enhanceApp({ app }) { 10 | app.component('NoteEditor', NodeEditor) 11 | }, 12 | } satisfies Theme 13 | -------------------------------------------------------------------------------- /docs/changelog.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/extensions/block-container.md: -------------------------------------------------------------------------------- 1 | # Block Container 2 | 3 | bloc container extension for tiptap 4 | 5 | ## Installation 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-block-container 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-block-container 15 | ``` 16 | 17 | ::: 18 | 19 | ## Usage 20 | 21 | ::: tip 22 | `@note-editor/tiptap-extension-block-container` is already included by [`@note-editor/vue-kit`](/guide/vue), so usually you don’t need to repeat the installation 23 | ::: 24 | 25 | ::: danger 26 | The `@tiptap/extension-document` has been extended to implement a top-level block container, so please pay attention to the compatibility processing of old and new data structures. If you want to see more, please see the [source code](https://github.com/liting-yes/note-editor/blob/main/packages/tiptap-extension-block-container/src/extentDocument.ts). 27 | ::: 28 | 29 | ```ts 30 | import { Editor } from '@tiptap/core' 31 | import { blockContainer } from '@note-editor/tiptap-extension-block-container' 32 | 33 | const editor = new Editor({ 34 | content: '

@note-editor/tiptap-extension-unique-id

', 35 | extensions: [ 36 | blockContainer 37 | ] 38 | }) 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/extensions/code-block-shiki.md: -------------------------------------------------------------------------------- 1 | # Code Block Shiki 2 | 3 | Code block extension with shiki for tiptap 4 | 5 | ::: warning 6 | The extension will override [Code block](https://tiptap.dev/docs/editor/api/nodes/code-block). 7 | ::: 8 | 9 | ## Installation 10 | 11 | ::: code-group 12 | 13 | ```bash [npm] 14 | npm install @note-editor/tiptap-extension-code-block-shiki 15 | ``` 16 | 17 | ```bash [pnpm] 18 | pnpm add @note-editor/tiptap-extension-code-block-shiki 19 | ``` 20 | 21 | ::: 22 | 23 | ## Usage 24 | 25 | ```ts 26 | import { Editor } from '@tiptap/core' 27 | import { codeBlockShiki } from '@note-editor/tiptap-extension-code-block-shiki' 28 | 29 | const editor = new Editor({ 30 | content: '

@note-editor/tiptap-extension-code-block-shiki

', 31 | extensions: [ 32 | codeBlockShiki 33 | ] 34 | }) 35 | ``` 36 | 37 | ## Settings 38 | 39 | ### theme 40 | 41 | Theme for highlight, want to see more please check [shiki themes](https://shiki.style/themes) 42 | 43 | ```ts 44 | codeBlockShiki.configure({ 45 | theme: 'vitesse-light' // default 46 | }) 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/extensions/details.md: -------------------------------------------------------------------------------- 1 | # Details 2 | 3 | Details extension for tiptap 4 | 5 | ## Installation 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-details 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-details 15 | ``` 16 | 17 | ::: 18 | 19 | ## Usage 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { details } from '@note-editor/tiptap-extension-details' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-details

', 27 | extensions: [ 28 | details 29 | ] 30 | }) 31 | ``` 32 | 33 | ## Settings 34 | 35 | ### HTMLAttributes 36 | 37 | Custom HTML attributes that should be added to the rendered HTML tag. 38 | 39 | ### detailSummaryOptions 40 | 41 | Options for detail summary extension. 42 | 43 | ### detailContentOptions 44 | 45 | Options for detail content extension. 46 | 47 | ## Commands 48 | 49 | ### insertDetails 50 | 51 | Insert a details in current pos. 52 | -------------------------------------------------------------------------------- /docs/extensions/emoji.md: -------------------------------------------------------------------------------- 1 | # Emoji 2 | 3 | Emoji extension for tiptap 4 | 5 | ## Installation 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-emoji 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-emoji 15 | ``` 16 | 17 | ::: 18 | 19 | ## Usage 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { emoji } from '@note-editor/tiptap-extension-emoji' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-emoji

', 27 | extensions: [ 28 | emoji 29 | ] 30 | }) 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/extensions/unique-id.md: -------------------------------------------------------------------------------- 1 | # @note-editor/tiptap-extension-unique-id 2 | 3 | unique id extension for tiptap 4 | 5 | ## Installation 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-unique-id 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-unique-id 15 | ``` 16 | 17 | ::: 18 | 19 | ## Usage 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { uniqueId } from '@note-editor/tiptap-extension-unique-id' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-unique-id

', 27 | extensions: [ 28 | uniqueId 29 | ] 30 | }) 31 | ``` 32 | 33 | ## Settings 34 | 35 | ### attributeName 36 | 37 | Name of the attribute that is attached to the HTML tag (will be prefixed with **data-**). 38 | 39 | ```ts 40 | uniqueID.configure({ 41 | attributeName: 'id' // default 42 | }) 43 | ``` 44 | 45 | ### types 46 | 47 | All types that should get a unique ID, for example ['paragraph'] 48 | 49 | ```ts 50 | uniqueID.configure({ 51 | types: ['blockContainer', 'paragraph', 'details', 'detailsSummary', 'detailsContent'] // default 52 | }) 53 | ``` 54 | 55 | ### generateID 56 | 57 | A function that generates and returns a unique ID. 58 | 59 | ```ts 60 | import { nanoid } from 'nanoid' 61 | 62 | uniqueID.configure({ 63 | generateID: () => nanoid() // default 64 | }) 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/guide/vue.md: -------------------------------------------------------------------------------- 1 | # Starter for Vue 2 | 3 | The **VueKit** is a collection of [Tiptap](https://tiptap.dev/docs/editor/introduction) extensions with vue. If you’re just getting started, this extension is for you. 4 | 5 | ## Installation 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @tiptap/vue-3 @note-editor/vue-kit 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @tiptap/vue-3 @note-editor/vue-kit 15 | ``` 16 | 17 | ::: 18 | 19 | ## Export 20 | 21 | ### setupKit 22 | 23 | a collection of Tiptap extensions, similar to [StarterKit](https://tiptap.dev/docs/editor/api/extensions/starter-kit) 24 | 25 | ```ts 26 | import { Editor } from '@tiptap/core' 27 | import { setupKit } from '@note-editor/vue-kit' 28 | 29 | const editor = new Editor({ 30 | extensions: [ 31 | setupKit 32 | ] 33 | }) 34 | ``` 35 | 36 | ### useNoteEditor 37 | 38 | a vue composable for tiptap 39 | 40 | ```ts 41 | import { useNoteEditor } from '@note-editor/vue-kit' 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```vue 47 | 53 | 54 | 57 | ``` 58 | 59 | You can configure the included extensions, or even disable a few of them, like shown below. 60 | 61 | ```vue 62 | 79 | 80 | 83 | ``` 84 | 85 | ## Included extensions 86 | 87 | ### Nodes 88 | 89 | - [Blockquote](https://tiptap.dev/docs/editor/api/nodes/blockquote) 90 | - [BulletList](https://tiptap.dev/docs/editor/api/nodes/bullet-list) 91 | - [Document](https://tiptap.dev/docs/editor/api/nodes/document) 92 | - [HardBreak](https://tiptap.dev/docs/editor/api/nodes/hard-break) 93 | - [Heading](https://tiptap.dev/docs/editor/api/nodes/heading) 94 | - [HorizontalRule](https://tiptap.dev/docs/editor/api/nodes/horizontal-rule) 95 | - [ListItem](https://tiptap.dev/docs/editor/api/nodes/list-item) 96 | - [OrderedList](https://tiptap.dev/docs/editor/api/nodes/ordered-list) 97 | - [Paragraph](https://tiptap.dev/docs/editor/api/nodes/paragraph) 98 | - [Table](https://tiptap.dev/docs/editor/api/nodes/table) 99 | - [TableCell](https://tiptap.dev/docs/editor/api/nodes/table-cell) 100 | - [TableHeader](https://tiptap.dev/docs/editor/api/nodes/table-header) 101 | - [TableRow](https://tiptap.dev/docs/editor/api/nodes/table-row) 102 | - [TaskItem](https://tiptap.dev/docs/editor/api/nodes/task-item) 103 | - [TaskList](https://tiptap.dev/docs/editor/api/nodes/task-list) 104 | - [Text](https://tiptap.dev/docs/editor/api/nodes/text) 105 | - [Block Container](/extensions/block-container) 106 | - [Code Block Shiki](/extensions/code-block-shiki) 107 | - [Details](/extensions/details) 108 | 109 | ### Marks 110 | 111 | - [Bold](https://tiptap.dev/docs/editor/api/marks/bold) 112 | - [Code](https://tiptap.dev/docs/editor/api/marks/code) 113 | - [Highlight](https://tiptap.dev/docs/editor/api/marks/highlight) 114 | - [Italic](https://tiptap.dev/docs/editor/api/marks/italic) 115 | - [Strike](https://tiptap.dev/docs/editor/api/marks/strike) 116 | - [Subscript](https://tiptap.dev/docs/editor/api/marks/subscript) 117 | - [Superscript](https://tiptap.dev/docs/editor/api/marks/superscript) 118 | - [TextStyle](https://tiptap.dev/docs/editor/api/marks/text-style) 119 | - [Underline](https://tiptap.dev/docs/editor/api/marks/underline) 120 | 121 | ### Extensions 122 | 123 | - [CharacterCount](https://tiptap.dev/docs/editor/api/extensions/character-count) 124 | - [Color](https://tiptap.dev/docs/editor/api/extensions/color) 125 | - [Focus](https://tiptap.dev/docs/editor/api/extensions/focus) 126 | - [FontFamily](https://tiptap.dev/docs/editor/api/extensions/font-family) 127 | - [Gapcursor](https://tiptap.dev/docs/editor/api/extensions/dropcursor) 128 | - [History](https://tiptap.dev/docs/editor/api/extensions/history) 129 | - [Placeholder](https://tiptap.dev/docs/editor/api/extensions/placeholder) 130 | - [TextAlign](https://tiptap.dev/docs/editor/api/extensions/text-align) 131 | - [Typography](https://tiptap.dev/docs/editor/api/extensions/typography) 132 | - [Unique ID](/extensions/unique-id) 133 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: Note Editor 6 | text: Tiptap-based text editor 7 | actions: 8 | - theme: brand 9 | text: Best practice 10 | link: https://github.com/vueditor/rich-text-editor.git 11 | - theme: alt 12 | text: Guide 13 | link: /guide/vue 14 | - theme: alt 15 | text: Extensions 16 | link: /extensions/unique-id 17 | 18 | features: 19 | - title: Easy to integrate 20 | details: Nanny tutorial + Complete packaging chain 21 | - title: Easy to customize 22 | details: Based on Tiptap packaging, easy to expand 23 | --- 24 | -------------------------------------------------------------------------------- /docs/playground.md: -------------------------------------------------------------------------------- 1 | # Playground 2 | 3 | Note Editor Playground for Vue 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/zh-CN/changelog.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/zh-CN/extensions/block-container.md: -------------------------------------------------------------------------------- 1 | # Block Container(块容器) 2 | 3 | 用于 Tiptap 的块容器插件 4 | 5 | ## 安装 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-block-container 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-block-container 15 | ``` 16 | 17 | ::: 18 | 19 | ## 用法 20 | 21 | ::: tip 22 | `@note-editor/tiptap-extension-block-container` 已经被 [`@note-editor/vue-kit`](/guide/vue) 收集在内, 所以通常来说不需要单独安装 23 | ::: 24 | 25 | ::: danger 26 | `@tiptap/extension-document` 被拓展以实现顶级的块容器,所以请注意新旧数据结构的兼容处理。 如果你想了解更多, 请查看 [源码](https://github.com/liting-yes/note-editor/blob/main/packages/tiptap-extension-block-container/src/extentDocument.ts). 27 | ::: 28 | 29 | ```ts 30 | import { Editor } from '@tiptap/core' 31 | import { blockContainer } from '@note-editor/tiptap-extension-block-container' 32 | 33 | const editor = new Editor({ 34 | content: '

@note-editor/tiptap-extension-unique-id

', 35 | extensions: [ 36 | blockContainer 37 | ] 38 | }) 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/zh-CN/extensions/code-block-shiki.md: -------------------------------------------------------------------------------- 1 | # Code Block Shiki 2 | 3 | 基于 Shiki 进行代码高亮的代码块插件 4 | 5 | ::: warning 6 | 此插件会覆盖掉 [Code block](https://tiptap.dev/docs/editor/api/nodes/code-block) 7 | ::: 8 | 9 | ## 安装 10 | 11 | ::: code-group 12 | 13 | ```bash [npm] 14 | npm install @note-editor/tiptap-extension-code-block-shiki 15 | ``` 16 | 17 | ```bash [pnpm] 18 | pnpm add @note-editor/tiptap-extension-code-block-shiki 19 | ``` 20 | 21 | ::: 22 | 23 | ## 用法 24 | 25 | ```ts 26 | import { Editor } from '@tiptap/core' 27 | import { codeBlockShiki } from '@note-editor/tiptap-extension-code-block-shiki' 28 | 29 | const editor = new Editor({ 30 | content: '

@note-editor/tiptap-extension-code-block-shiki

', 31 | extensions: [ 32 | codeBlockShiki 33 | ] 34 | }) 35 | ``` 36 | 37 | ## 设置 38 | 39 | ### theme 40 | 41 | 高亮主题, 想查看更多请跳转 [shiki themes](https://shiki.style/themes) 42 | 43 | ```ts 44 | codeBlockShiki.configure({ 45 | theme: 'vitesse-light' // default 46 | }) 47 | ``` 48 | -------------------------------------------------------------------------------- /docs/zh-CN/extensions/details.md: -------------------------------------------------------------------------------- 1 | # Details 2 | 3 | 用于 Tiptap 的 details 插件 4 | 5 | ## 安装 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-details 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-details 15 | ``` 16 | 17 | ::: 18 | 19 | ## 用法 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { details } from '@note-editor/tiptap-extension-details' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-details

', 27 | extensions: [ 28 | details 29 | ] 30 | }) 31 | ``` 32 | 33 | ## 设置 34 | 35 | ### HTMLAttributes 36 | 37 | 将渲染到对应 HTMl 标签上的自定义属性 38 | 39 | ### detailSummaryOptions 40 | 41 | **detail summary extension** 的配置项 42 | 43 | ### detailContentOptions 44 | 45 | **detail content extension** 的配置项 46 | 47 | ## 命令行 48 | 49 | ### insertDetails 50 | 51 | 在当前位置插入一个 details 52 | -------------------------------------------------------------------------------- /docs/zh-CN/extensions/emoji.md: -------------------------------------------------------------------------------- 1 | # Emoji 2 | 3 | 基于 tiptap 的 emoji 插件 4 | 5 | ## 安装 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-emoji 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-emoji 15 | ``` 16 | 17 | ::: 18 | 19 | ## 用法 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { emoji } from '@note-editor/tiptap-extension-emoji' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-emoji

', 27 | extensions: [ 28 | emoji 29 | ] 30 | }) 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/zh-CN/extensions/unique-id.md: -------------------------------------------------------------------------------- 1 | # @note-editor/tiptap-extension-unique-id 2 | 3 | 用于 Tiptap 的注入唯一 ID 的插件 4 | 5 | ## 安装 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @note-editor/tiptap-extension-unique-id 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @note-editor/tiptap-extension-unique-id 15 | ``` 16 | 17 | ::: 18 | 19 | ## 用法 20 | 21 | ```ts 22 | import { Editor } from '@tiptap/core' 23 | import { uniqueId } from '@note-editor/tiptap-extension-unique-id' 24 | 25 | const editor = new Editor({ 26 | content: '

@note-editor/tiptap-extension-unique-id

', 27 | extensions: [ 28 | uniqueId 29 | ] 30 | }) 31 | ``` 32 | 33 | ## 设置 34 | 35 | ### attributeName 36 | 37 | 附加到 HTML 标签上的属性名 (自动添加 **data-** 前缀). 38 | 39 | ```ts 40 | uniqueID.configure({ 41 | attributeName: 'id' // default 42 | }) 43 | ``` 44 | 45 | ### types 46 | 47 | 穷举需要注入 Unique ID 的节点类型, 比如 ['paragraph'] 48 | 49 | ```ts 50 | uniqueID.configure({ 51 | types: ['blockContainer', 'paragraph', 'details', 'detailsSummary', 'detailsContent'] // default 52 | }) 53 | ``` 54 | 55 | ### generateID 56 | 57 | 一个生成并返回唯一 ID 的函数 58 | 59 | ```ts 60 | import { nanoid } from 'nanoid' 61 | 62 | uniqueID.configure({ 63 | generateID: () => nanoid() // default 64 | }) 65 | ``` 66 | -------------------------------------------------------------------------------- /docs/zh-CN/guide/vue.md: -------------------------------------------------------------------------------- 1 | # Vue 指南 2 | 3 | **VueKit** 是一个 [Tiptap](https://tiptap.dev/docs/editor/introduction) 插件集。如果你是刚起步,这个插件正合适 4 | 5 | ## 安装 6 | 7 | ::: code-group 8 | 9 | ```bash [npm] 10 | npm install @tiptap/vue-3 @note-editor/vue-kit 11 | ``` 12 | 13 | ```bash [pnpm] 14 | pnpm add @tiptap/vue-3 @note-editor/vue-kit 15 | ``` 16 | 17 | ::: 18 | 19 | ## 导出 20 | 21 | ### setupKit 22 | 23 | 一个 Tiptap 插件集,类似于 [StarterKit](https://tiptap.dev/docs/editor/api/extensions/starter-kit) 24 | 25 | ```ts 26 | import { Editor } from '@tiptap/core' 27 | import { setupKit } from '@note-editor/vue-kit' 28 | 29 | const editor = new Editor({ 30 | extensions: [ 31 | setupKit 32 | ] 33 | }) 34 | ``` 35 | 36 | ### useNoteEditor 37 | 38 | 一个用于 Tiptap 的 Vue 组合式函数 39 | 40 | ```ts 41 | import { useNoteEditor } from '@note-editor/vue-kit' 42 | ``` 43 | 44 | ## 用法 45 | 46 | ```vue 47 | 53 | 54 | 57 | ``` 58 | 59 | 对于涵盖的插件,你既可以设置其配置项,也可以禁用它。示例如下: 60 | 61 | ```vue 62 | 79 | 80 | 83 | ``` 84 | 85 | ## 涵盖的插件列表 86 | 87 | ### Nodes 88 | 89 | - [Blockquote](https://tiptap.dev/docs/editor/api/nodes/blockquote) 90 | - [BulletList](https://tiptap.dev/docs/editor/api/nodes/bullet-list) 91 | - [Document](https://tiptap.dev/docs/editor/api/nodes/document) 92 | - [HardBreak](https://tiptap.dev/docs/editor/api/nodes/hard-break) 93 | - [Heading](https://tiptap.dev/docs/editor/api/nodes/heading) 94 | - [HorizontalRule](https://tiptap.dev/docs/editor/api/nodes/horizontal-rule) 95 | - [ListItem](https://tiptap.dev/docs/editor/api/nodes/list-item) 96 | - [OrderedList](https://tiptap.dev/docs/editor/api/nodes/ordered-list) 97 | - [Paragraph](https://tiptap.dev/docs/editor/api/nodes/paragraph) 98 | - [Table](https://tiptap.dev/docs/editor/api/nodes/table) 99 | - [TableCell](https://tiptap.dev/docs/editor/api/nodes/table-cell) 100 | - [TableHeader](https://tiptap.dev/docs/editor/api/nodes/table-header) 101 | - [TableRow](https://tiptap.dev/docs/editor/api/nodes/table-row) 102 | - [TaskItem](https://tiptap.dev/docs/editor/api/nodes/task-item) 103 | - [TaskList](https://tiptap.dev/docs/editor/api/nodes/task-list) 104 | - [Text](https://tiptap.dev/docs/editor/api/nodes/text) 105 | - [Block Container](/zh-CN/extensions/block-container) 106 | - [Code Block Shiki](/zh-CN/extensions/code-block-shiki) 107 | - [Details](/zh-CN/extensions/details) 108 | 109 | ### Marks 110 | 111 | - [Bold](https://tiptap.dev/docs/editor/api/marks/bold) 112 | - [Code](https://tiptap.dev/docs/editor/api/marks/code) 113 | - [Highlight](https://tiptap.dev/docs/editor/api/marks/highlight) 114 | - [Italic](https://tiptap.dev/docs/editor/api/marks/italic) 115 | - [Strike](https://tiptap.dev/docs/editor/api/marks/strike) 116 | - [Subscript](https://tiptap.dev/docs/editor/api/marks/subscript) 117 | - [Superscript](https://tiptap.dev/docs/editor/api/marks/superscript) 118 | - [TextStyle](https://tiptap.dev/docs/editor/api/marks/text-style) 119 | - [Underline](https://tiptap.dev/docs/editor/api/marks/underline) 120 | 121 | ### Extensions 122 | 123 | - [CharacterCount](https://tiptap.dev/docs/editor/api/extensions/character-count) 124 | - [Color](https://tiptap.dev/docs/editor/api/extensions/color) 125 | - [Focus](https://tiptap.dev/docs/editor/api/extensions/focus) 126 | - [FontFamily](https://tiptap.dev/docs/editor/api/extensions/font-family) 127 | - [Gapcursor](https://tiptap.dev/docs/editor/api/extensions/dropcursor) 128 | - [History](https://tiptap.dev/docs/editor/api/extensions/history) 129 | - [Placeholder](https://tiptap.dev/docs/editor/api/extensions/placeholder) 130 | - [TextAlign](https://tiptap.dev/docs/editor/api/extensions/text-align) 131 | - [Typography](https://tiptap.dev/docs/editor/api/extensions/typography) 132 | - [Unique ID](/zh-CN/extensions/unique-id) 133 | -------------------------------------------------------------------------------- /docs/zh-CN/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: Note Editor 6 | text: 基于 Tiptap 的文本编辑器 7 | actions: 8 | - theme: brand 9 | text: 最佳实践 10 | link: https://github.com/vueditor/rich-text-editor.git 11 | - theme: alt 12 | text: 指南 13 | link: /zh-CN/guide/vue 14 | - theme: alt 15 | text: 插件 16 | link: /zh-CN/extensions/unique-id 17 | 18 | features: 19 | - title: 集成简单 20 | details: 保姆式教程 + 完整的封装链 21 | - title: 易于自定义 22 | details: 基于 Tiptap 封装,拓展难度低 23 | --- 24 | -------------------------------------------------------------------------------- /docs/zh-CN/playground.md: -------------------------------------------------------------------------------- 1 | # 演练场 2 | 3 | Note Editor 在 Vue 中的演练 4 | 5 | 6 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import antfu from '@antfu/eslint-config' 2 | 3 | export default antfu({ 4 | vue: true, 5 | typescript: true, 6 | react: true, 7 | formatters: { 8 | css: true, 9 | html: true, 10 | markdown: true, 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /migrations.json: -------------------------------------------------------------------------------- 1 | { 2 | "migrations": [ 3 | { 4 | "version": "18.1.0-beta.3", 5 | "description": "Moves affected.defaultBase to defaultBase in `nx.json`", 6 | "implementation": "./src/migrations/update-17-2-0/move-default-base", 7 | "package": "nx", 8 | "name": "move-default-base-to-nx-json-root" 9 | }, 10 | { 11 | "cli": "nx", 12 | "version": "19.2.0-beta.2", 13 | "description": "Updates the default workspace data directory to .nx/workspace-data", 14 | "implementation": "./src/migrations/update-19-2-0/move-workspace-data-directory", 15 | "package": "nx", 16 | "name": "19-2-0-move-graph-cache-directory" 17 | }, 18 | { 19 | "cli": "nx", 20 | "version": "19.2.2-beta.0", 21 | "description": "Updates the nx wrapper.", 22 | "implementation": "./src/migrations/update-17-3-0/update-nxw", 23 | "package": "nx", 24 | "name": "19-2-2-update-nx-wrapper" 25 | }, 26 | { 27 | "version": "19.2.4-beta.0", 28 | "description": "Set project name in nx.json explicitly", 29 | "implementation": "./src/migrations/update-19-2-4/set-project-name", 30 | "x-repair-skip": true, 31 | "package": "nx", 32 | "name": "19-2-4-set-project-name" 33 | }, 34 | { 35 | "version": "19.6.0-beta.0", 36 | "description": "Add dependsOn: [build] to preview targets using preview-server", 37 | "implementation": "./src/migrations/update-19-6-0/add-depends-on-for-preview", 38 | "package": "@nx/vite", 39 | "name": "update-19-6-0-add-depends-on-for-preview-server" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsConfig": { 3 | "@nx/js": { 4 | "analyzeSourceFiles": true 5 | } 6 | }, 7 | "extends": "nx/presets/npm.json", 8 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 9 | "plugins": [ 10 | { 11 | "plugin": "@nx/eslint/plugin", 12 | "options": { 13 | "targetName": "lint" 14 | } 15 | }, 16 | { 17 | "plugin": "@nx/vite/plugin", 18 | "options": { 19 | "buildTargetName": "build", 20 | "previewTargetName": "preview", 21 | "testTargetName": "test", 22 | "serveTargetName": "serve", 23 | "serveStaticTargetName": "serve-static" 24 | } 25 | } 26 | ], 27 | "targetDefaults": { 28 | "@nx/rollup:rollup": { 29 | "cache": true, 30 | "dependsOn": ["^build"], 31 | "inputs": ["default", "^default"] 32 | }, 33 | "@nx/vite:build": { 34 | "cache": true, 35 | "dependsOn": ["^build"], 36 | "inputs": ["default", "^default"] 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "note-editor", 3 | "type": "module", 4 | "private": true, 5 | "license": "MIT", 6 | "scripts": { 7 | "prepare": "husky", 8 | "lint": "eslint .", 9 | "lint:fix": "eslint . --fix", 10 | "docs:dev": "vitepress dev docs", 11 | "docs:build": "vitepress build docs", 12 | "docs:preview": "vitepress preview docs", 13 | "commit": "git-cz" 14 | }, 15 | "dependencies": { 16 | "@note-editor/vue-kit": "workspace:*", 17 | "vue": "^3.4.21" 18 | }, 19 | "devDependencies": { 20 | "@antfu/eslint-config": "^2.6.4", 21 | "@commitlint/cli": "^19.0.3", 22 | "@commitlint/config-conventional": "^19.0.3", 23 | "@commitlint/cz-commitlint": "^19.2.0", 24 | "@nx/eslint": "19.6.3", 25 | "@nx/js": "19.6.3", 26 | "@nx/rollup": "19.6.3", 27 | "@nx/vite": "19.6.3", 28 | "@nx/vue": "19.6.3", 29 | "@nx/web": "19.6.3", 30 | "@swc-node/register": "1.9.2", 31 | "@swc/cli": "0.3.14", 32 | "@swc/core": "1.5.7", 33 | "@swc/helpers": "0.5.12", 34 | "@types/node": "18.16.9", 35 | "@vitejs/plugin-vue": "^4.5.0", 36 | "@vitest/ui": "1.6.0", 37 | "@vue/test-utils": "^2.4.1", 38 | "commitizen": "^4.3.0", 39 | "eslint": "8.57.0", 40 | "eslint-plugin-format": "^0.1.0", 41 | "eslint-plugin-react": "^7.33.2", 42 | "eslint-plugin-react-hooks": "^4.6.0", 43 | "eslint-plugin-react-refresh": "^0.4.5", 44 | "husky": "^9.0.11", 45 | "inquirer": "9", 46 | "jsdom": "~22.1.0", 47 | "lint-staged": "^15.2.2", 48 | "nx": "19.6.3", 49 | "prettier": "^2.6.2", 50 | "sass": "1.62.1", 51 | "tslib": "^2.6.2", 52 | "typescript": "5.5.4", 53 | "vite": "~5.0.0", 54 | "vite-plugin-dts": "~2.3.0", 55 | "vitepress": "^1.0.1", 56 | "vitest": "1.6.0", 57 | "vue-tsc": "2.0.7" 58 | }, 59 | "lint-staged": { 60 | "*": "eslint --fix" 61 | }, 62 | "config": { 63 | "commitizen": { 64 | "path": "@commitlint/cz-commitlint" 65 | } 66 | }, 67 | "commitlint": { 68 | "extends": [ 69 | "@commitlint/config-conventional" 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/README.md: -------------------------------------------------------------------------------- 1 | # tiptap-extension-block-container 2 | 3 | block container extension for tiptap 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/tiptap-extension-block-container", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "description": "block container extension for tiptap", 6 | "license": "MIT", 7 | "homepage": "https://note-editor.liting.ink/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/liting-yes/note-editor.git", 11 | "directory": "packages/tiptap-extension-block-container" 12 | }, 13 | "keywords": [ 14 | "tiptap", 15 | "tiptap extension" 16 | ], 17 | "exports": { 18 | ".": { 19 | "types": "./dist/index.d.ts", 20 | "import": "./dist/index.js", 21 | "require": "./dist/index.cjs" 22 | } 23 | }, 24 | "main": "./dist/index.cjs", 25 | "module": "./dist/index.js", 26 | "types": "./dist/index.d.ts", 27 | "files": [ 28 | "dist" 29 | ], 30 | "publishConfig": { 31 | "access": "public", 32 | "registry": "https://registry.npmjs.org" 33 | }, 34 | "peerDependencies": { 35 | "@tiptap/core": "^2.2", 36 | "@tiptap/pm": "^2.2" 37 | }, 38 | "devDependencies": { 39 | "@tiptap/core": "^2.2.4", 40 | "@tiptap/extension-document": "^2.2.4", 41 | "@tiptap/pm": "^2.2.4" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiptap-extension-block-container", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/tiptap-extension-block-container/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/vite:build", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "packages/tiptap-extension-block-container/dist", 12 | "main": "packages/tiptap-extension-block-container/src/index.ts", 13 | "tsConfig": "packages/tiptap-extension-block-container/tsconfig.lib.json", 14 | "assets": ["packages/tiptap-extension-block-container/*.md"] 15 | } 16 | } 17 | }, 18 | "tags": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/src/blockContainer.css: -------------------------------------------------------------------------------- 1 | .ProseMirror.tiptap { 2 | padding-left: 0; 3 | padding-right: 32px; 4 | } 5 | 6 | .note-editor__block-container { 7 | position: relative; 8 | padding-left: 32px; 9 | } 10 | 11 | .note-editor__block-container:hover .note-editor__block-container__drag-bar { 12 | display: block; 13 | } 14 | 15 | .note-editor__block-container:hover .note-editor__block-container__content { 16 | background-color: #f1f5f9; 17 | } 18 | 19 | .note-editor__block-container__drag-bar { 20 | display: none; 21 | position: absolute; 22 | left: 4px; 23 | top: 0; 24 | width: 24px; 25 | height: 24px; 26 | cursor: grab; 27 | background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16px' height='16px' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M9 20q-.825 0-1.412-.587T7 18q0-.825.588-1.412T9 16q.825 0 1.413.588T11 18q0 .825-.587 1.413T9 20m6 0q-.825 0-1.412-.587T13 18q0-.825.588-1.412T15 16q.825 0 1.413.588T17 18q0 .825-.587 1.413T15 20m-6-6q-.825 0-1.412-.587T7 12q0-.825.588-1.412T9 10q.825 0 1.413.588T11 12q0 .825-.587 1.413T9 14m6 0q-.825 0-1.412-.587T13 12q0-.825.588-1.412T15 10q.825 0 1.413.588T17 12q0 .825-.587 1.413T15 14M9 8q-.825 0-1.412-.587T7 6q0-.825.588-1.412T9 4q.825 0 1.413.588T11 6q0 .825-.587 1.413T9 8m6 0q-.825 0-1.412-.587T13 6q0-.825.588-1.412T15 4q.825 0 1.413.588T17 6q0 .825-.587 1.413T15 8'/%3E%3C/svg%3E"); 28 | background-position: center; 29 | background-repeat: no-repeat; 30 | } 31 | 32 | .note-editor__block-container__content { 33 | padding: 0 4px; 34 | } 35 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/src/blockContainer.ts: -------------------------------------------------------------------------------- 1 | import { Node, createStyleTag, mergeAttributes } from '@tiptap/core' 2 | import { Fragment, Slice } from '@tiptap/pm/model' 3 | import { TextSelection } from '@tiptap/pm/state' 4 | import document from './extentDocument' 5 | import style from './blockContainer.css?raw' 6 | 7 | export interface BlockContainerOptions { 8 | HTMLAttributes: Record 9 | } 10 | 11 | declare module '@tiptap/core' { 12 | interface Commands { 13 | blockContainer: { 14 | splitBlockContainer: () => ReturnType 15 | } 16 | } 17 | } 18 | 19 | export const blockContainer = Node.create({ 20 | name: 'blockContainer', 21 | content: 'block', 22 | group: 'block top', 23 | draggable: true, 24 | defining: true, 25 | addOptions() { 26 | return { 27 | HTMLAttributes: {}, 28 | } 29 | }, 30 | parseHTML() { 31 | return [ 32 | { 33 | tag: 'div.note-editor__block-container', 34 | }, 35 | ] 36 | }, 37 | renderHTML({ HTMLAttributes }) { 38 | return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0] 39 | }, 40 | addExtensions() { 41 | return [document] 42 | }, 43 | addCommands() { 44 | return { 45 | splitBlockContainer: () => ({ state: { selection, doc, schema, tr }, dispatch }) => { 46 | if (!dispatch) 47 | return false 48 | 49 | const startPos = selection.from 50 | const resolved = doc.resolve(startPos) 51 | const endPos = resolved.end(resolved.depth) 52 | const newBlockContent = tr.doc.cut(startPos, endPos) 53 | const newBlock = schema.nodes[this.name].createAndFill()! 54 | 55 | tr.replace(endPos + 1, endPos + 2, newBlockContent.content.size > 0 ? new Slice(Fragment.from(newBlockContent), 0, 0) : new Slice(Fragment.from(newBlock), 0, 0)) 56 | tr.setSelection(new TextSelection(tr.doc.resolve(endPos + 1))) 57 | tr.delete(startPos, endPos) 58 | 59 | return dispatch(tr) 60 | }, 61 | } 62 | }, 63 | addKeyboardShortcuts() { 64 | const handleEnter = () => this.editor.commands.first(({ commands }) => { 65 | return [ 66 | () => commands.newlineInCode(), 67 | () => commands.splitBlockContainer(), 68 | ] 69 | }) 70 | 71 | return { 72 | Enter: handleEnter, 73 | } 74 | }, 75 | addNodeView() { 76 | return ({ HTMLAttributes }) => { 77 | const dom = window.document.createElement('div') 78 | dom.classList.add('note-editor__block-container') 79 | Object.keys(HTMLAttributes).forEach((key) => { 80 | dom.setAttribute(key, HTMLAttributes[key]) 81 | }) 82 | 83 | const dragBar = window.document.createElement('div') 84 | dragBar.classList.add('note-editor__block-container__drag-bar') 85 | 86 | const content = window.document.createElement('div') 87 | content.classList.add('note-editor__block-container__content') 88 | 89 | createStyleTag(style, undefined, 'block-container') 90 | 91 | dom.append(dragBar, content) 92 | 93 | return { 94 | dom, 95 | contentDOM: content, 96 | } 97 | } 98 | }, 99 | }) 100 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/src/extentDocument.ts: -------------------------------------------------------------------------------- 1 | import { Document } from '@tiptap/extension-document' 2 | 3 | export default Document.extend({ 4 | content: 'top+', 5 | }) 6 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './blockContainer' 2 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "strict": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | } 16 | ], 17 | "files": [], 18 | "include": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client"], 5 | "declaration": true, 6 | "outDir": "../../dist/out-tsc" 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tiptap-extension-block-container/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | cacheDir: '../../node_modules/.vite/packages/tiptap-extension-block-container', 10 | 11 | plugins: [ 12 | nxViteTsPaths(), 13 | dts({ 14 | entryRoot: 'src', 15 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 16 | skipDiagnostics: true, 17 | }), 18 | ], 19 | 20 | // Uncomment this if you are using workers. 21 | // worker: { 22 | // plugins: [ nxViteTsPaths() ], 23 | // }, 24 | 25 | // Configuration for building your library. 26 | // See: https://vitejs.dev/guide/build.html#library-mode 27 | build: { 28 | outDir: 'dist', 29 | reportCompressedSize: true, 30 | commonjsOptions: { 31 | transformMixedEsModules: true, 32 | }, 33 | lib: { 34 | // Could also be a dictionary or array of multiple entry points. 35 | entry: 'src/index.ts', 36 | name: 'tiptap-extension-block-container', 37 | fileName: 'index', 38 | // Change this to the formats you want to support. 39 | // Don't forget to update your package.json as well. 40 | formats: ['es', 'cjs'], 41 | }, 42 | rollupOptions: { 43 | // External packages that should not be bundled into your library. 44 | external: [/^@tiptap\//], 45 | }, 46 | }, 47 | }) 48 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/README.md: -------------------------------------------------------------------------------- 1 | # tiptap-extension-code-block-shiki 2 | 3 | code block extension for tiptap 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/tiptap-extension-code-block-shiki", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "description": "code block extension with shiki for tiptap", 6 | "license": "MIT", 7 | "homepage": "https://note-editor.liting.ink/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/liting-yes/note-editor.git", 11 | "directory": "packages/tiptap-extension-code-block-shiki" 12 | }, 13 | "keywords": [ 14 | "tiptap", 15 | "tiptap extension", 16 | "shiki", 17 | "code block" 18 | ], 19 | "exports": { 20 | ".": { 21 | "types": "./dist/index.d.ts", 22 | "import": "./dist/index.js", 23 | "require": "./dist/index.cjs" 24 | } 25 | }, 26 | "main": "./dist/index.cjs", 27 | "module": "./dist/index.js", 28 | "types": "./dist/index.d.ts", 29 | "files": [ 30 | "dist" 31 | ], 32 | "publishConfig": { 33 | "access": "public", 34 | "registry": "https://registry.npmjs.org" 35 | }, 36 | "dependencies": { 37 | "@tiptap/core": "^2.2.4", 38 | "@tiptap/extension-code-block": "^2.2.4", 39 | "@tiptap/pm": "^2.2.4", 40 | "shiki": "^1.2.0" 41 | }, 42 | "devDependencies": { 43 | "@types/hast": "^3.0.4", 44 | "hast": "^1.0.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiptap-extension-code-block-shiki", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/tiptap-extension-code-block-shiki/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/vite:build", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "packages/tiptap-extension-code-block-shiki/dist", 12 | "main": "packages/tiptap-extension-code-block-shiki/src/index.ts", 13 | "tsConfig": "packages/tiptap-extension-code-block-shiki/tsconfig.lib.json", 14 | "assets": ["packages/tiptap-extension-code-block-shiki/*.md"] 15 | } 16 | } 17 | }, 18 | "tags": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/src/codeBlockShiki.css: -------------------------------------------------------------------------------- 1 | .node-editor__code-block-shiki { 2 | position: relative; 3 | border-radius: 8px; 4 | padding: 4px 8px; 5 | } 6 | 7 | .note-editor__code-block-shiki__lang-tag { 8 | position: absolute; 9 | top: 4px; 10 | right: 4px; 11 | font-size: 12px; 12 | line-height: 16px; 13 | padding: 2px 4px; 14 | border-radius: 4px; 15 | } 16 | 17 | .note-editor__code-block-shiki__select-lang { 18 | position: absolute; 19 | top: 4px; 20 | right: 4px; 21 | font-size: 12px; 22 | line-height: 16px; 23 | cursor: pointer; 24 | padding: 2px 4px; 25 | border-radius: 4px; 26 | border: 1px solid #f1f5f9; 27 | } 28 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/src/codeBlockShiki.ts: -------------------------------------------------------------------------------- 1 | import type { CodeBlockOptions } from '@tiptap/extension-code-block' 2 | import { CodeBlock } from '@tiptap/extension-code-block' 3 | import type { Node as ProsemirrorNode } from '@tiptap/pm/model' 4 | import { Plugin, PluginKey } from '@tiptap/pm/state' 5 | import type { DecorationAttrs } from '@tiptap/pm/view' 6 | import { Decoration, DecorationSet } from '@tiptap/pm/view' 7 | import { createStyleTag, findChildren } from '@tiptap/core' 8 | import type { BundledLanguage, BundledTheme, HighlighterGeneric, StringLiteralUnion } from 'shiki/bundle/web' 9 | import { bundledLanguagesInfo, getHighlighter } from 'shiki/bundle/web' 10 | import type { Element } from 'hast' 11 | import style from './codeBlockShiki.css?raw' 12 | 13 | export interface CodeBlockShikiOptions extends CodeBlockOptions { 14 | theme: StringLiteralUnion 15 | } 16 | 17 | export interface CodeBlockShikiStorage { 18 | highlighter: HighlighterGeneric | null 19 | } 20 | 21 | export const codeBlockShiki = CodeBlock.extend({ 22 | addOptions() { 23 | return { 24 | ...this.parent?.(), 25 | theme: 'vitesse-light', 26 | } 27 | }, 28 | addStorage() { 29 | return { 30 | highlighter: null, 31 | } 32 | }, 33 | async onBeforeCreate() { 34 | createStyleTag(style, undefined, 'code-block-shiki') 35 | this.storage.highlighter = await getHighlighter({ 36 | themes: [this.options.theme], 37 | langs: bundledLanguagesInfo.map(item => item.id), 38 | }) 39 | }, 40 | addProseMirrorPlugins() { 41 | return [ 42 | ...(this.parent?.() ?? []), 43 | new Plugin({ 44 | key: new PluginKey(this.name), 45 | state: { 46 | init: (_, { doc }) => { 47 | return getDecorations({ doc, name: this.name, highlighter: this.storage.highlighter, theme: this.options.theme }) 48 | }, 49 | apply: (transaction, decorationSet, oldState, newState) => { 50 | const oldNodeName = oldState.selection.$head.parent.type.name 51 | const newNodeName = newState.selection.$head.parent.type.name 52 | 53 | if ( 54 | transaction.docChanged 55 | && ([oldNodeName, newNodeName].includes(this.name) 56 | // only toggle language for code block 57 | // @ts-expect-error attr 58 | || transaction.steps.find(item => item.attr === 'language') 59 | ) 60 | ) { 61 | return getDecorations({ 62 | doc: transaction.doc, 63 | name: this.name, 64 | highlighter: this.storage.highlighter, 65 | theme: this.options.theme, 66 | }) 67 | } 68 | 69 | return decorationSet.map(transaction.mapping, transaction.doc) 70 | }, 71 | }, 72 | props: { 73 | decorations(state) { 74 | return this.getState(state) 75 | }, 76 | }, 77 | }), 78 | ] 79 | }, 80 | addNodeView() { 81 | return ({ editor, node, getPos, HTMLAttributes }) => { 82 | const dom = window.document.createElement('pre') 83 | dom.classList.add('note-editor__code-block-shiki') 84 | Object.keys(HTMLAttributes).forEach((key) => { 85 | dom.setAttribute(key, HTMLAttributes[key]) 86 | }) 87 | 88 | const content = window.document.createElement('code') 89 | // @ts-expect-error language 90 | const langClass = this.options.languageClassPrefix + node.attrs.language 91 | content.classList.add(langClass) 92 | dom.append(content) 93 | 94 | if (this.editor.isEditable) { 95 | const selectLang = window.document.createElement('select') 96 | selectLang.classList.add('note-editor__code-block-shiki__select-lang') 97 | selectLang.addEventListener('change', (event) => { 98 | // @ts-expect-error value 99 | const lang = event.target.value 100 | editor.commands.command(({ tr }) => { 101 | const pos = (getPos as () => number)() 102 | tr.setNodeAttribute(pos, 'language', lang) 103 | 104 | return true 105 | }) 106 | }) 107 | const options = bundledLanguagesInfo.map((item) => { 108 | const option = document.createElement('option') 109 | option.setAttribute('value', item.id) 110 | // @ts-expect-error language 111 | if (node.attrs.language === item.id || node.attrs.language === item.name || item.aliases?.includes(node.attrs.language)) 112 | option.setAttribute('selected', '') 113 | 114 | option.textContent = item.id 115 | return option 116 | }) 117 | selectLang.append(...options) 118 | dom.append(selectLang) 119 | } 120 | else { 121 | const langTag = window.document.createElement('div') 122 | langTag.classList.add('note-editor__code-block-shiki__lang-tag') 123 | // @ts-expect-error language 124 | langTag.textContent = node.attrs.language ?? 'text' 125 | dom.append(langTag) 126 | } 127 | 128 | return { 129 | dom, 130 | contentDOM: content, 131 | } 132 | } 133 | }, 134 | }) 135 | 136 | function formatLanguage(lang: string) { 137 | if (!lang) 138 | return null 139 | 140 | return bundledLanguagesInfo.find(item => [item.id, item.name, ...(item.aliases ?? [])])?.id 141 | } 142 | 143 | function getDecorations({ 144 | doc, 145 | name, 146 | highlighter, 147 | theme, 148 | }: { 149 | doc: ProsemirrorNode 150 | name: string 151 | highlighter: CodeBlockShikiStorage['highlighter'] 152 | theme: CodeBlockShikiOptions['theme'] 153 | }) { 154 | let decorations: Decoration[] = [] 155 | if (!highlighter) 156 | return DecorationSet.create(doc, decorations) 157 | 158 | findChildren(doc, node => node.type.name === name).forEach((block) => { 159 | // @ts-expect-error language 160 | block.node.attrs.language = formatLanguage(block.node.attrs.language) ?? 'text' 161 | 162 | const preNode = highlighter!.codeToHast(block.node.textContent, { 163 | theme, 164 | // @ts-expect-error language 165 | lang: block.node.attrs.language, 166 | }).children[0] as Element 167 | 168 | decorations.push(Decoration.node(block.pos, block.pos + block.node.nodeSize, { 169 | // @ts-expect-error class 170 | class: `${preNode.properties?.class} node-editor__code-block-shiki`, 171 | // @ts-expect-error style 172 | style: preNode.properties?.style, 173 | } as DecorationAttrs)) 174 | 175 | let from = block.pos + 1 176 | const lines = (preNode.children[0] as Element).children 177 | for (const line of lines) { 178 | if ((line as Element).children?.length) { 179 | let lineFrom = from 180 | // @ts-expect-error line type 181 | line.children?.forEach((node) => { 182 | const nodeLen = node.children[0].value.length 183 | decorations.push(Decoration.inline(lineFrom, lineFrom + nodeLen, (node as Element).properties as DecorationAttrs)) 184 | lineFrom += nodeLen 185 | }) 186 | 187 | // prosemirror do not support add wrap for line 188 | // decorations.push(Decoration.inline(from, lineFrom, line.properties as DecorationAttrs)) 189 | from = lineFrom 190 | } 191 | else if (line.type === 'text') { 192 | from += line.value.length 193 | } 194 | } 195 | }) 196 | 197 | decorations = decorations.filter(item => !!item) 198 | 199 | return DecorationSet.create(doc, decorations) 200 | } 201 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './codeBlockShiki' 2 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "strict": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | } 16 | ], 17 | "files": [], 18 | "include": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client"], 5 | "declaration": true, 6 | "outDir": "../../dist/out-tsc" 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tiptap-extension-code-block-shiki/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | cacheDir: 10 | '../../node_modules/.vite/packages/tiptap-extension-code-block-shiki', 11 | 12 | plugins: [ 13 | nxViteTsPaths(), 14 | dts({ 15 | entryRoot: 'src', 16 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 17 | skipDiagnostics: true, 18 | }), 19 | ], 20 | 21 | // Uncomment this if you are using workers. 22 | // worker: { 23 | // plugins: [ nxViteTsPaths() ], 24 | // }, 25 | 26 | // Configuration for building your library. 27 | // See: https://vitejs.dev/guide/build.html#library-mode 28 | build: { 29 | outDir: 'dist', 30 | reportCompressedSize: true, 31 | commonjsOptions: { 32 | transformMixedEsModules: true, 33 | }, 34 | lib: { 35 | // Could also be a dictionary or array of multiple entry points. 36 | entry: 'src/index.ts', 37 | name: 'tiptap-extension-code-block-shiki', 38 | fileName: 'index', 39 | // Change this to the formats you want to support. 40 | // Don't forget to update your package.json as well. 41 | formats: ['es', 'cjs'], 42 | }, 43 | rollupOptions: { 44 | // External packages that should not be bundled into your library. 45 | external: [/^@tiptap\//, 'shiki/bundle/web'], 46 | }, 47 | }, 48 | }) 49 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/README.md: -------------------------------------------------------------------------------- 1 | # tiptap-extension-details 2 | 3 | details extension for tiptap 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/eslint.config.js: -------------------------------------------------------------------------------- 1 | const { FlatCompat } = require('@eslint/eslintrc') 2 | const js = require('@eslint/js') 3 | const baseConfig = require('../../eslint.config.js') 4 | 5 | const compat = new FlatCompat({ 6 | baseDirectory: __dirname, 7 | recommendedConfig: js.configs.recommended, 8 | }) 9 | 10 | module.exports = [ 11 | ...baseConfig, 12 | { 13 | files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], 14 | rules: {}, 15 | }, 16 | { 17 | files: ['**/*.ts', '**/*.tsx'], 18 | rules: {}, 19 | }, 20 | { 21 | files: ['**/*.js', '**/*.jsx'], 22 | rules: {}, 23 | }, 24 | ...compat.config({ parser: 'jsonc-eslint-parser' }).map(config => ({ 25 | ...config, 26 | files: ['**/*.json'], 27 | rules: { 28 | '@nx/dependency-checks': [ 29 | 'error', 30 | { 31 | ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'], 32 | }, 33 | ], 34 | }, 35 | })), 36 | ] 37 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/tiptap-extension-details", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "description": "details extension for tiptap", 6 | "license": "MIT", 7 | "homepage": "https://note-editor.liting.ink/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/liting-yes/note-editor.git", 11 | "directory": "packages/tiptap-extension-details" 12 | }, 13 | "keywords": [ 14 | "tiptap", 15 | "tiptap extension", 16 | "details" 17 | ], 18 | "exports": { 19 | ".": { 20 | "types": "./dist/index.d.ts", 21 | "import": "./dist/index.js", 22 | "require": "./dist/index.cjs" 23 | } 24 | }, 25 | "main": "./dist/index.cjs", 26 | "module": "./dist/index.js", 27 | "types": "./dist/index.d.ts", 28 | "files": [ 29 | "dist" 30 | ], 31 | "peerDependencies": { 32 | "@tiptap/core": "^2.2" 33 | }, 34 | "dependencies": { 35 | "@tiptap/pm": "^2.2.4" 36 | }, 37 | "publishConfig": { 38 | "access": "public", 39 | "registry": "https://registry.npmjs.org" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiptap-extension-details", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/tiptap-extension-details/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/vite:build", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "packages/tiptap-extension-details/dist", 12 | "main": "packages/tiptap-extension-details/src/index.ts", 13 | "tsConfig": "packages/tiptap-extension-details/tsconfig.lib.json", 14 | "assets": ["packages/tiptap-extension-details/*.md"] 15 | } 16 | } 17 | }, 18 | "tags": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/src/details.ts: -------------------------------------------------------------------------------- 1 | import { Node, mergeAttributes } from '@tiptap/core' 2 | import type { DetailsSummaryOptions } from './detailsSummary' 3 | import { detailsSummary } from './detailsSummary' 4 | import type { DetailsContentOptions } from './detailsContent' 5 | import { detailsContent } from './detailsContent' 6 | 7 | export interface DetailsOptions { 8 | HTMLAttributes: Record 9 | detailSummaryOptions: Partial 10 | detailContentOptions: Partial 11 | } 12 | 13 | declare module '@tiptap/core' { 14 | interface Commands { 15 | details: { 16 | insertDetails: () => ReturnType 17 | } 18 | } 19 | } 20 | 21 | export const details = Node.create({ 22 | name: 'details', 23 | group: 'block', 24 | content: 'detailsSummary detailsContent', 25 | addOptions() { 26 | return { 27 | HTMLAttributes: {}, 28 | detailSummaryOptions: {}, 29 | detailContentOptions: {}, 30 | } 31 | }, 32 | addAttributes() { 33 | return { 34 | open: { 35 | default: null, 36 | rendered: true, 37 | isRequired: true, 38 | parseHTML: element => element.getAttribute('open'), 39 | renderHTML: (attributes) => { 40 | // @ts-expect-error open 41 | if (attributes.open) { 42 | return { 43 | open: true, 44 | } 45 | } 46 | 47 | return {} 48 | }, 49 | }, 50 | } 51 | }, 52 | parseHTML() { 53 | return [ 54 | { 55 | tag: 'details', 56 | }, 57 | ] 58 | }, 59 | renderHTML({ HTMLAttributes }) { 60 | return ['details', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 61 | class: 'node-editor__details', 62 | }), 0] 63 | }, 64 | addCommands() { 65 | return { 66 | insertDetails: () => ({ commands }) => { 67 | commands.insertContent({ 68 | type: this.name, 69 | content: [ 70 | { 71 | type: detailsSummary.name, 72 | }, 73 | { 74 | type: detailsContent.name, 75 | }, 76 | ], 77 | }) 78 | 79 | return true 80 | }, 81 | } 82 | }, 83 | addExtensions() { 84 | return [ 85 | detailsSummary.configure(this.options.detailSummaryOptions), 86 | detailsContent.configure(this.options.detailContentOptions), 87 | ] 88 | }, 89 | 90 | }) 91 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/src/detailsContent.ts: -------------------------------------------------------------------------------- 1 | import { Node, mergeAttributes } from '@tiptap/core' 2 | 3 | export interface DetailsContentOptions { 4 | HTMLAttributes: Record 5 | } 6 | 7 | export const detailsContent = Node.create({ 8 | name: 'detailsContent', 9 | group: 'details', 10 | content: 'block*', 11 | addOptions() { 12 | return { 13 | HTMLAttributes: {}, 14 | } 15 | }, 16 | parseHTML() { 17 | return [ 18 | { 19 | tag: 'div.node-editor__details-content', 20 | }, 21 | ] 22 | }, 23 | renderHTML({ HTMLAttributes }) { 24 | return ['div', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 25 | class: 'node-editor__details-content', 26 | }), 0] 27 | }, 28 | }) 29 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/src/detailsSummary.ts: -------------------------------------------------------------------------------- 1 | import { Node, mergeAttributes } from '@tiptap/core' 2 | import { Plugin, PluginKey } from '@tiptap/pm/state' 3 | 4 | export interface DetailsSummaryOptions { 5 | HTMLAttributes: Record 6 | } 7 | 8 | export const detailsSummary = Node.create({ 9 | name: 'detailsSummary', 10 | group: 'details', 11 | content: 'inline*', 12 | addOptions() { 13 | return { 14 | HTMLAttributes: {}, 15 | } 16 | }, 17 | parseHTML() { 18 | return [ 19 | { 20 | tag: 'summary', 21 | }, 22 | ] 23 | }, 24 | renderHTML({ HTMLAttributes }) { 25 | return ['summary', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { 26 | class: 'node-editor__details-summary', 27 | }), 0] 28 | }, 29 | addProseMirrorPlugins() { 30 | return [ 31 | new Plugin({ 32 | key: new PluginKey(this.name), 33 | props: { 34 | handleClickOn: (view, pos, node, nodePos, event, direct) => { 35 | if (!direct || node.type.name !== this.name) 36 | return 37 | 38 | const detailsNode = view.state.doc.resolve(nodePos).parent 39 | // @ts-expect-error open 40 | const tr = view.state.tr.setNodeAttribute(nodePos - 1, 'open', !detailsNode.attrs.open) 41 | view.dispatch(tr) 42 | }, 43 | }, 44 | }), 45 | ] 46 | }, 47 | }) 48 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './details' 2 | export * from './detailsContent' 3 | export * from './detailsSummary' 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "strict": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | } 16 | ], 17 | "files": [], 18 | "include": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client"], 5 | "declaration": true, 6 | "outDir": "../../dist/out-tsc" 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tiptap-extension-details/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | cacheDir: '../../node_modules/.vite/packages/tiptap-extension-details', 10 | 11 | plugins: [ 12 | nxViteTsPaths(), 13 | dts({ 14 | entryRoot: 'src', 15 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 16 | skipDiagnostics: true, 17 | }), 18 | ], 19 | 20 | // Uncomment this if you are using workers. 21 | // worker: { 22 | // plugins: [ nxViteTsPaths() ], 23 | // }, 24 | 25 | // Configuration for building your library. 26 | // See: https://vitejs.dev/guide/build.html#library-mode 27 | build: { 28 | outDir: 'dist', 29 | reportCompressedSize: true, 30 | commonjsOptions: { 31 | transformMixedEsModules: true, 32 | }, 33 | lib: { 34 | // Could also be a dictionary or array of multiple entry points. 35 | entry: 'src/index.ts', 36 | name: 'tiptap-extension-details', 37 | fileName: 'index', 38 | // Change this to the formats you want to support. 39 | // Don't forget to update your package.json as well. 40 | formats: ['es', 'cjs'], 41 | }, 42 | rollupOptions: { 43 | // External packages that should not be bundled into your library. 44 | external: [/^@tiptap\//], 45 | }, 46 | }, 47 | }) 48 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/README.md: -------------------------------------------------------------------------------- 1 | # tiptap-extension-emoji 2 | 3 | emoji extension for tiptap 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/tiptap-extension-emoji", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "description": "emoji extension for tiptap", 6 | "license": "MIT", 7 | "homepage": "https://note-editor.liting.ink/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/liting-yes/note-editor.git", 11 | "directory": "packages/tiptap-extension-emoji" 12 | }, 13 | "keywords": [ 14 | "tiptap", 15 | "tiptap extension", 16 | "emoji" 17 | ], 18 | "exports": { 19 | ".": { 20 | "types": "./dist/index.d.ts", 21 | "import": "./dist/index.js", 22 | "require": "./dist/index.cjs" 23 | } 24 | }, 25 | "main": "./dist/index.cjs", 26 | "module": "./dist/index.js", 27 | "types": "./dist/index.d.ts", 28 | "files": [ 29 | "dist" 30 | ], 31 | "dependencies": { 32 | "@tiptap/core": "^2.2.4", 33 | "emojilib": "^3.0.12" 34 | }, 35 | "publishConfig": { 36 | "access": "public", 37 | "registry": "https://registry.npmjs.org" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiptap-extension-emoji", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/tiptap-extension-emoji/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/vite:build", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "packages/tiptap-extension-emoji/dist", 12 | "main": "packages/tiptap-extension-emoji/src/index.ts", 13 | "tsConfig": "packages/tiptap-extension-emoji/tsconfig.lib.json", 14 | "assets": ["packages/tiptap-extension-emoji/*.md"] 15 | } 16 | } 17 | }, 18 | "tags": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/src/emoji.ts: -------------------------------------------------------------------------------- 1 | import { InputRule, Node, PasteRule } from '@tiptap/core' 2 | import emojiJson from 'emojilib' 3 | 4 | const emojiMap = new Map() 5 | Object.entries(emojiJson).forEach(([emoji, names]) => { 6 | names.forEach(name => emojiMap.set(name, emoji)) 7 | }) 8 | 9 | export interface EmojiOptions { 10 | } 11 | 12 | export const emoji = Node.create({ 13 | name: 'emoji', 14 | inline: true, 15 | group: 'inline', 16 | atom: true, 17 | addInputRules() { 18 | return Object.entries(emojiJson).map(([emoji, names]) => new InputRule({ 19 | find: new RegExp(`:(${names.map(name => name.replace(/(\(|\)|\+)/, str => `\\${str}`)).join('|')}):$`), 20 | handler({ state, range }) { 21 | state.tr.insertText(emoji, range.from, range.to) 22 | }, 23 | })) 24 | }, 25 | addPasteRules() { 26 | return Object.entries(emojiJson).map(([emoji, names]) => new PasteRule({ 27 | find: new RegExp(`(:(${names.map(name => name.replace(/(\(|\)|\+)/, str => `\\${str}`)).join('|')}):)`, 'g'), 28 | handler({ state, range }) { 29 | state.tr.insertText(emoji, range.from, range.to) 30 | }, 31 | })) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './emoji' 2 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "strict": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | } 16 | ], 17 | "files": [], 18 | "include": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client"], 5 | "declaration": true, 6 | "outDir": "../../dist/out-tsc" 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tiptap-extension-emoji/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | cacheDir: '../../node_modules/.vite/packages/tiptap-extension-emoji', 10 | 11 | plugins: [ 12 | nxViteTsPaths(), 13 | dts({ 14 | entryRoot: 'src', 15 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 16 | skipDiagnostics: true, 17 | }), 18 | ], 19 | 20 | // Uncomment this if you are using workers. 21 | // worker: { 22 | // plugins: [ nxViteTsPaths() ], 23 | // }, 24 | 25 | // Configuration for building your library. 26 | // See: https://vitejs.dev/guide/build.html#library-mode 27 | build: { 28 | outDir: 'dist', 29 | reportCompressedSize: true, 30 | commonjsOptions: { 31 | transformMixedEsModules: true, 32 | }, 33 | lib: { 34 | // Could also be a dictionary or array of multiple entry points. 35 | entry: 'src/index.ts', 36 | name: 'tiptap-extension-emoji', 37 | fileName: 'index', 38 | // Change this to the formats you want to support. 39 | // Don't forget to update your package.json as well. 40 | formats: ['es', 'cjs'], 41 | }, 42 | rollupOptions: { 43 | // External packages that should not be bundled into your library. 44 | external: [/^@tiptap\//], 45 | }, 46 | }, 47 | }) 48 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/README.md: -------------------------------------------------------------------------------- 1 | # tiptap-extension-unique-id 2 | 3 | unique id extension for tiptap 4 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/eslint.config.js: -------------------------------------------------------------------------------- 1 | const { FlatCompat } = require('@eslint/eslintrc') 2 | const js = require('@eslint/js') 3 | const baseConfig = require('../../eslint.config.js') 4 | 5 | const compat = new FlatCompat({ 6 | baseDirectory: __dirname, 7 | recommendedConfig: js.configs.recommended, 8 | }) 9 | 10 | module.exports = [ 11 | ...baseConfig, 12 | { 13 | files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], 14 | rules: {}, 15 | }, 16 | { 17 | files: ['**/*.ts', '**/*.tsx'], 18 | rules: {}, 19 | }, 20 | { 21 | files: ['**/*.js', '**/*.jsx'], 22 | rules: {}, 23 | }, 24 | ...compat.config({ parser: 'jsonc-eslint-parser' }).map(config => ({ 25 | ...config, 26 | files: ['**/*.json'], 27 | rules: { 28 | '@nx/dependency-checks': [ 29 | 'error', 30 | { 31 | ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'], 32 | }, 33 | ], 34 | }, 35 | })), 36 | ] 37 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/tiptap-extension-unique-id", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "description": "unique id extension for tiptap", 6 | "license": "MIT", 7 | "homepage": "https://note-editor.liting.ink/", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/liting-yes/note-editor.git", 11 | "directory": "packages/tiptap-extension-unique-id" 12 | }, 13 | "keywords": [ 14 | "tiptap", 15 | "tiptap extension" 16 | ], 17 | "exports": { 18 | ".": { 19 | "types": "./dist/index.d.ts", 20 | "import": "./dist/index.js", 21 | "require": "./dist/index.cjs" 22 | } 23 | }, 24 | "main": "./dist/index.cjs", 25 | "module": "./dist/index.js", 26 | "types": "./dist/index.d.ts", 27 | "files": [ 28 | "dist" 29 | ], 30 | "peerDependencies": { 31 | "@tiptap/core": "^2.2", 32 | "@tiptap/pm": "^2.2" 33 | }, 34 | "dependencies": { 35 | "nanoid": "^5.0.6" 36 | }, 37 | "publishConfig": { 38 | "access": "public", 39 | "registry": "https://registry.npmjs.org" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tiptap-extension-unique-id", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/tiptap-extension-unique-id/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/vite:build", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "packages/tiptap-extension-unique-id/dist", 12 | "main": "packages/tiptap-extension-unique-id/src/index.ts", 13 | "tsConfig": "packages/tiptap-extension-unique-id/tsconfig.lib.json", 14 | "assets": ["packages/tiptap-extension-unique-id/*.md"] 15 | } 16 | } 17 | }, 18 | "tags": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './uniqueId' 2 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/src/uniqueId.ts: -------------------------------------------------------------------------------- 1 | import { Extension, combineTransactionSteps, findChildrenInRange, findDuplicates, getChangedRanges } from '@tiptap/core' 2 | import { nanoid } from 'nanoid' 3 | import type { Transaction } from '@tiptap/pm/state' 4 | import { Plugin, PluginKey } from '@tiptap/pm/state' 5 | 6 | export interface UniqueIdOptions { 7 | attributeName: string 8 | types: string[] 9 | generateID: () => string 10 | injectNodeName: boolean 11 | } 12 | 13 | const pluginKey = new PluginKey('uniqueId') 14 | 15 | export const uniqueId = Extension.create({ 16 | name: 'uniqueId', 17 | addOptions() { 18 | return { 19 | attributeName: 'id', 20 | name: 'detailsSummary', 21 | types: ['blockContainer', 'paragraph', 'details', 'detailsSummary', 'detailsContent'], 22 | generateID: () => nanoid(), 23 | injectNodeName: true, 24 | } 25 | }, 26 | addGlobalAttributes() { 27 | const { attributeName, types } = this.options 28 | 29 | return [ 30 | { 31 | types, 32 | attributes: { 33 | [attributeName!]: { 34 | default: null, 35 | rendered: true, 36 | isRequired: true, 37 | keepOnSplit: false, 38 | parseHTML: element => element.getAttribute(`data-${attributeName}`), 39 | renderHTML: (attributes) => { 40 | return { 41 | [`data-${attributeName}`]: attributes[attributeName!], 42 | } 43 | }, 44 | }, 45 | }, 46 | }, 47 | { 48 | types: this.options.injectNodeName ? types : [], 49 | attributes: { 50 | 'data-node-name': { 51 | default: null, 52 | rendered: true, 53 | isRequired: true, 54 | keepOnSplit: false, 55 | parseHTML: element => element.getAttribute('data-node-name'), 56 | renderHTML: (attributes) => { 57 | return { 58 | 'data-node-name': attributes['data-node-name'], 59 | } 60 | }, 61 | 62 | }, 63 | }, 64 | }, 65 | ] 66 | }, 67 | onCreate() { 68 | const { tr, doc } = this.editor.state 69 | const { attributeName, types, generateID, injectNodeName } = this.options 70 | 71 | doc.descendants((node, pos) => { 72 | if (node.type.name === 'text' || !types?.includes(node.type.name)) 73 | return 74 | 75 | if (injectNodeName) 76 | tr.setNodeAttribute(pos, 'data-node-name', node.type.name) 77 | 78 | if (!node.attrs[attributeName!]) 79 | tr.setNodeAttribute(pos, attributeName!, generateID!()) 80 | }) 81 | 82 | this.editor.view.dispatch(tr) 83 | }, 84 | addProseMirrorPlugins() { 85 | const { attributeName, types, generateID, injectNodeName } = this.options 86 | 87 | return [ 88 | new Plugin({ 89 | key: pluginKey, 90 | appendTransaction(trs, { doc: oldDoc }, { doc: newDoc, tr }) { 91 | if (!trs.some(tr => !!tr.docChanged) || oldDoc.eq(newDoc)) 92 | return 93 | 94 | const transform = combineTransactionSteps(oldDoc, trs as Transaction[]) 95 | 96 | getChangedRanges(transform).forEach(({ newRange }) => { 97 | const newNodes = findChildrenInRange(newDoc, newRange, node => types!.includes(node.type.name)) 98 | 99 | const newIds = newNodes.map(({ node }) => node.attrs[attributeName!]).filter(item => !!item) 100 | newNodes.forEach(({ node, pos }) => { 101 | if (injectNodeName && !node.attrs['data-node-name']) 102 | tr.setNodeAttribute(pos, 'data-node-name', node.type.name) 103 | 104 | const uniqueId = node.attrs[attributeName!] 105 | 106 | if (!uniqueId) { 107 | tr.setNodeAttribute(pos, attributeName!, generateID!()) 108 | return 109 | } 110 | 111 | if (tr.mapping.invert().mapResult(pos) && findDuplicates(newIds).includes(uniqueId)) 112 | tr.setNodeAttribute(pos, attributeName!, generateID!()) 113 | }) 114 | }) 115 | 116 | if (!transform.steps.length) 117 | return null 118 | 119 | return tr 120 | }, 121 | }), 122 | ] 123 | }, 124 | }) 125 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "strict": true, 6 | "noFallthroughCasesInSwitch": true, 7 | "noImplicitOverride": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "forceConsistentCasingInFileNames": true 11 | }, 12 | "references": [ 13 | { 14 | "path": "./tsconfig.lib.json" 15 | } 16 | ], 17 | "files": [], 18 | "include": [] 19 | } 20 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["node", "vite/client"], 5 | "declaration": true, 6 | "outDir": "../../dist/out-tsc" 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /packages/tiptap-extension-unique-id/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import dts from 'vite-plugin-dts' 5 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 6 | 7 | export default defineConfig({ 8 | root: __dirname, 9 | cacheDir: '../../node_modules/.vite/packages/tiptap-extension-unique-id', 10 | 11 | plugins: [ 12 | nxViteTsPaths(), 13 | dts({ 14 | entryRoot: 'src', 15 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 16 | skipDiagnostics: true, 17 | }), 18 | ], 19 | 20 | // Uncomment this if you are using workers. 21 | // worker: { 22 | // plugins: [ nxViteTsPaths() ], 23 | // }, 24 | 25 | // Configuration for building your library. 26 | // See: https://vitejs.dev/guide/build.html#library-mode 27 | build: { 28 | outDir: 'dist', 29 | reportCompressedSize: true, 30 | commonjsOptions: { 31 | transformMixedEsModules: true, 32 | }, 33 | lib: { 34 | // Could also be a dictionary or array of multiple entry points. 35 | entry: 'src/index.ts', 36 | name: 'tiptap-extension-unique-id', 37 | fileName: 'index', 38 | // Change this to the formats you want to support. 39 | // Don't forget to update your package.json as well. 40 | formats: ['es', 'cjs'], 41 | }, 42 | rollupOptions: { 43 | // External packages that should not be bundled into your library. 44 | external: [/^@tiptap\//], 45 | }, 46 | }, 47 | }) 48 | -------------------------------------------------------------------------------- /packages/vue-kit/README.md: -------------------------------------------------------------------------------- 1 | # @note-editor/vue-kit 2 | 3 | starter kit for tiptap in vue 4 | -------------------------------------------------------------------------------- /packages/vue-kit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/vue-kit", 3 | "type": "module", 4 | "version": "0.3.1", 5 | "private": false, 6 | "description": "starter kit for tiptap in vue", 7 | "license": "MIT", 8 | "homepage": "https://note-editor.liting.ink/", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/liting-yes/note-editor.git", 12 | "directory": "packages/vue-kit" 13 | }, 14 | "keywords": [ 15 | "tiptap", 16 | "tiptap starter kit", 17 | "vue" 18 | ], 19 | "exports": { 20 | ".": { 21 | "types": "./dist/index.d.ts", 22 | "import": "./dist/index.js", 23 | "require": "./dist/index.cjs" 24 | }, 25 | "./style.css": "./dist/style.css" 26 | }, 27 | "main": "./dist/index.cjs", 28 | "module": "./dist/index.js", 29 | "types": "./dist/index.d.ts", 30 | "files": [ 31 | "dist" 32 | ], 33 | "publishConfig": { 34 | "access": "public", 35 | "registry": "https://registry.npmjs.org" 36 | }, 37 | "peerDependencies": { 38 | "vue": "^3" 39 | }, 40 | "dependencies": { 41 | "@note-editor/tiptap-extension-block-container": "0.3.1", 42 | "@note-editor/tiptap-extension-code-block-shiki": "0.3.1", 43 | "@note-editor/tiptap-extension-details": "0.3.1", 44 | "@note-editor/tiptap-extension-emoji": "0.3.1", 45 | "@note-editor/tiptap-extension-unique-id": "0.3.1", 46 | "@tiptap/core": "^2.2.4", 47 | "@tiptap/extension-blockquote": "^2.2.4", 48 | "@tiptap/extension-bold": "^2.2.4", 49 | "@tiptap/extension-bullet-list": "^2.2.4", 50 | "@tiptap/extension-character-count": "^2.2.4", 51 | "@tiptap/extension-code": "^2.2.4", 52 | "@tiptap/extension-code-block": "^2.2.4", 53 | "@tiptap/extension-color": "^2.2.4", 54 | "@tiptap/extension-document": "^2.2.4", 55 | "@tiptap/extension-dropcursor": "^2.2.4", 56 | "@tiptap/extension-focus": "^2.2.4", 57 | "@tiptap/extension-font-family": "^2.2.4", 58 | "@tiptap/extension-gapcursor": "^2.2.4", 59 | "@tiptap/extension-hard-break": "^2.2.4", 60 | "@tiptap/extension-heading": "^2.2.4", 61 | "@tiptap/extension-highlight": "^2.2.4", 62 | "@tiptap/extension-history": "^2.2.4", 63 | "@tiptap/extension-horizontal-rule": "^2.2.4", 64 | "@tiptap/extension-italic": "^2.2.4", 65 | "@tiptap/extension-list-item": "^2.2.4", 66 | "@tiptap/extension-ordered-list": "^2.2.4", 67 | "@tiptap/extension-paragraph": "^2.2.4", 68 | "@tiptap/extension-placeholder": "^2.2.4", 69 | "@tiptap/extension-strike": "^2.2.4", 70 | "@tiptap/extension-subscript": "^2.2.4", 71 | "@tiptap/extension-superscript": "^2.2.4", 72 | "@tiptap/extension-table": "^2.2.4", 73 | "@tiptap/extension-table-cell": "^2.2.4", 74 | "@tiptap/extension-table-header": "^2.2.4", 75 | "@tiptap/extension-table-row": "^2.2.4", 76 | "@tiptap/extension-task-item": "^2.2.4", 77 | "@tiptap/extension-task-list": "^2.2.4", 78 | "@tiptap/extension-text": "^2.2.4", 79 | "@tiptap/extension-text-style": "^2.2.4", 80 | "@tiptap/extension-typography": "^2.2.4", 81 | "@tiptap/extension-underline": "^2.2.4", 82 | "@tiptap/vue-3": "^2.2.4" 83 | }, 84 | "devDependencies": { 85 | "vue": "^3.4.21" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /packages/vue-kit/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-kit", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "packages/vue-kit/src", 5 | "projectType": "library", 6 | "tags": [], 7 | "targets": {} 8 | } 9 | -------------------------------------------------------------------------------- /packages/vue-kit/src/components/NoteEditor.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 37 | 38 | 73 | -------------------------------------------------------------------------------- /packages/vue-kit/src/composables/useNoteEditor.ts: -------------------------------------------------------------------------------- 1 | import { onBeforeUnmount, onMounted, shallowRef } from 'vue' 2 | import type { EditorOptions } from '@tiptap/vue-3' 3 | import { Editor } from '@tiptap/vue-3' 4 | import type { SetupKitOptions } from '../setupKit' 5 | import { setupKit } from '../setupKit' 6 | 7 | export interface UseNoteEditorOptions { 8 | kitOptions: SetupKitOptions 9 | } 10 | 11 | export function useNoteEditor(editorOptions?: Partial, kitOptions?: Partial) { 12 | const editor = shallowRef() 13 | 14 | onMounted(() => { 15 | editor.value = new Editor({ 16 | content: 'Note editor', 17 | ...editorOptions, 18 | extensions: [...(editorOptions?.extensions ?? []), kitOptions ? setupKit.configure(kitOptions) : setupKit], 19 | }) 20 | }) 21 | onBeforeUnmount(() => { 22 | editor.value?.destroy() 23 | editor.value = undefined 24 | }) 25 | 26 | return { 27 | editor, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/vue-kit/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './setupKit' 2 | export * from './composables/useNoteEditor' 3 | export * from './components/NoteEditor.vue' 4 | export { default as NodeEditor } from './components/NoteEditor.vue' 5 | -------------------------------------------------------------------------------- /packages/vue-kit/src/setupKit.ts: -------------------------------------------------------------------------------- 1 | import type { Extensions } from '@tiptap/core' 2 | import { Extension } from '@tiptap/core' 3 | import type { BlockquoteOptions } from '@tiptap/extension-blockquote' 4 | import { Blockquote } from '@tiptap/extension-blockquote' 5 | import type { BoldOptions } from '@tiptap/extension-bold' 6 | import { Bold } from '@tiptap/extension-bold' 7 | import type { BulletListOptions } from '@tiptap/extension-bullet-list' 8 | import { BulletList } from '@tiptap/extension-bullet-list' 9 | import type { CharacterCountOptions } from '@tiptap/extension-character-count' 10 | import { CharacterCount } from '@tiptap/extension-character-count' 11 | import type { CodeOptions } from '@tiptap/extension-code' 12 | import { Code } from '@tiptap/extension-code' 13 | import type { CodeBlockOptions } from '@tiptap/extension-code-block' 14 | import { CodeBlock } from '@tiptap/extension-code-block' 15 | import type { ColorOptions } from '@tiptap/extension-color' 16 | import { Color } from '@tiptap/extension-color' 17 | import Document from '@tiptap/extension-document' 18 | import type { DropcursorOptions } from '@tiptap/extension-dropcursor' 19 | import { Dropcursor } from '@tiptap/extension-dropcursor' 20 | import type { FocusOptions } from '@tiptap/extension-focus' 21 | import { FocusClasses } from '@tiptap/extension-focus' 22 | import type { FontFamilyOptions } from '@tiptap/extension-font-family' 23 | import { FontFamily } from '@tiptap/extension-font-family' 24 | import Gapcursor from '@tiptap/extension-gapcursor' 25 | import type { HardBreakOptions } from '@tiptap/extension-hard-break' 26 | import { HardBreak } from '@tiptap/extension-hard-break' 27 | import type { HeadingOptions } from '@tiptap/extension-heading' 28 | import { Heading } from '@tiptap/extension-heading' 29 | import type { HighlightOptions } from '@tiptap/extension-highlight' 30 | import { Highlight } from '@tiptap/extension-highlight' 31 | import type { HistoryOptions } from '@tiptap/extension-history' 32 | import { History } from '@tiptap/extension-history' 33 | import type { HorizontalRuleOptions } from '@tiptap/extension-horizontal-rule' 34 | import { HorizontalRule } from '@tiptap/extension-horizontal-rule' 35 | import type { ItalicOptions } from '@tiptap/extension-italic' 36 | import { Italic } from '@tiptap/extension-italic' 37 | import type { ListItemOptions } from '@tiptap/extension-list-item' 38 | import { ListItem } from '@tiptap/extension-list-item' 39 | import type { OrderedListOptions } from '@tiptap/extension-ordered-list' 40 | import { OrderedList } from '@tiptap/extension-ordered-list' 41 | import type { ParagraphOptions } from '@tiptap/extension-paragraph' 42 | import { Paragraph } from '@tiptap/extension-paragraph' 43 | import type { PlaceholderOptions } from '@tiptap/extension-placeholder' 44 | import { Placeholder } from '@tiptap/extension-placeholder' 45 | import type { StrikeOptions } from '@tiptap/extension-strike' 46 | import { Strike } from '@tiptap/extension-strike' 47 | import type { SubscriptExtensionOptions } from '@tiptap/extension-subscript' 48 | import { Subscript } from '@tiptap/extension-subscript' 49 | import type { SuperscriptExtensionOptions } from '@tiptap/extension-superscript' 50 | import { Superscript } from '@tiptap/extension-superscript' 51 | import type { TableOptions } from '@tiptap/extension-table' 52 | import { Table } from '@tiptap/extension-table' 53 | import type { TableCellOptions } from '@tiptap/extension-table-cell' 54 | import { TableCell } from '@tiptap/extension-table-cell' 55 | import type { TableHeaderOptions } from '@tiptap/extension-table-header' 56 | import { TableHeader } from '@tiptap/extension-table-header' 57 | import type { TableRowOptions } from '@tiptap/extension-table-row' 58 | import { TableRow } from '@tiptap/extension-table-row' 59 | import type { TaskItemOptions } from '@tiptap/extension-task-item' 60 | import { TaskItem } from '@tiptap/extension-task-item' 61 | import type { TaskListOptions } from '@tiptap/extension-task-list' 62 | import { TaskList } from '@tiptap/extension-task-list' 63 | import Text from '@tiptap/extension-text' 64 | import type { TextStyleOptions } from '@tiptap/extension-text-style' 65 | import { TextStyle } from '@tiptap/extension-text-style' 66 | import type { TypographyOptions } from '@tiptap/extension-typography' 67 | import { Typography } from '@tiptap/extension-typography' 68 | import type { UnderlineOptions } from '@tiptap/extension-underline' 69 | import { Underline } from '@tiptap/extension-underline' 70 | 71 | import type { UniqueIdOptions } from '@note-editor/tiptap-extension-unique-id' 72 | import { uniqueId } from '@note-editor/tiptap-extension-unique-id' 73 | import type { BlockContainerOptions } from '@note-editor/tiptap-extension-block-container' 74 | import { blockContainer } from '@note-editor/tiptap-extension-block-container' 75 | import type { CodeBlockShikiOptions } from '@note-editor/tiptap-extension-code-block-shiki' 76 | import { codeBlockShiki } from '@note-editor/tiptap-extension-code-block-shiki' 77 | import type { DetailsOptions } from '@note-editor/tiptap-extension-details' 78 | import { details } from '@note-editor/tiptap-extension-details' 79 | import type { EmojiOptions } from '@note-editor/tiptap-extension-emoji' 80 | import { emoji } from '@note-editor/tiptap-extension-emoji' 81 | 82 | export interface SetupKitOptions { 83 | blockquote: Partial | false 84 | bold: Partial | false 85 | bulletList: Partial | false 86 | characterCount: Partial | false 87 | code: Partial | false 88 | codeBlock: Partial | false 89 | color: Partial | false 90 | document: false 91 | dropcursor: Partial | false 92 | focus: Partial | false 93 | fontFamily: Partial | false 94 | gapcursor: false 95 | hardBreak: Partial | false 96 | heading: Partial | false 97 | highlight: Partial | false 98 | history: Partial | false 99 | horizontalRule: Partial | false 100 | italic: Partial | false 101 | listItem: Partial | false 102 | orderedList: Partial | false 103 | paragraph: Partial | false 104 | placeholder: Partial | false 105 | strike: Partial | false 106 | subscript: Partial | false 107 | superscript: Partial | false 108 | table: Partial | false 109 | tableCell: Partial | false 110 | tableHeader: Partial | false 111 | tableRow: Partial | false 112 | taskItem: Partial | false 113 | taskList: Partial | false 114 | text: false 115 | textStyle: Partial | false 116 | typography: Partial | false 117 | underline: Partial | false 118 | uniqueId: Partial | false 119 | blockContainer: Partial | false 120 | codeBlockShiki: Partial | false 121 | details: Partial | false 122 | emoji: Partial | false 123 | } 124 | 125 | export const setupKit = Extension.create({ 126 | name: 'setupKit', 127 | addExtensions() { 128 | const extensions: Extensions = [] 129 | 130 | if (this.options.blockquote !== false) 131 | extensions.push(Blockquote.configure(this.options.blockquote)) 132 | 133 | if (this.options.bold !== false) 134 | extensions.push(Bold.configure(this.options.bold)) 135 | 136 | if (this.options.bulletList !== false) 137 | extensions.push(BulletList.configure(this.options.bulletList)) 138 | 139 | if (this.options.characterCount !== false) 140 | extensions.push(CharacterCount.configure(this.options.characterCount)) 141 | 142 | if (this.options.code !== false) 143 | extensions.push(Code.configure(this.options.code)) 144 | 145 | if (this.options.codeBlockShiki === false && this.options.codeBlock !== false) 146 | extensions.push(CodeBlock.configure(this.options.codeBlock)) 147 | 148 | if (this.options.codeBlockShiki !== false) 149 | extensions.push(codeBlockShiki.configure(this.options.codeBlockShiki)) 150 | 151 | if (this.options.color !== false) 152 | extensions.push(Color.configure(this.options.color)) 153 | 154 | if (this.options.blockContainer !== false) 155 | extensions.push(blockContainer) 156 | 157 | if (this.options.blockContainer === false && this.options.document !== false) 158 | extensions.push(Document) 159 | 160 | if (this.options.dropcursor !== false) 161 | extensions.push(Dropcursor.configure(this.options.dropcursor)) 162 | 163 | if (this.options.focus !== false) 164 | extensions.push(FocusClasses.configure(this.options.focus)) 165 | 166 | if (this.options.fontFamily !== false) 167 | extensions.push(FontFamily.configure(this.options.fontFamily)) 168 | 169 | if (this.options.gapcursor !== false) 170 | extensions.push(Gapcursor) 171 | 172 | if (this.options.hardBreak !== false) 173 | extensions.push(HardBreak.configure(this.options.hardBreak)) 174 | 175 | if (this.options.heading !== false) 176 | extensions.push(Heading.configure(this.options.heading)) 177 | 178 | if (this.options.highlight !== false) 179 | extensions.push(Highlight.configure(this.options.highlight)) 180 | 181 | if (this.options.history !== false) 182 | extensions.push(History.configure(this.options.history)) 183 | 184 | if (this.options.horizontalRule !== false) 185 | extensions.push(HorizontalRule.configure(this.options.horizontalRule)) 186 | 187 | if (this.options.italic !== false) 188 | extensions.push(Italic.configure(this.options.italic)) 189 | 190 | if (this.options.listItem !== false) 191 | extensions.push(ListItem.configure(this.options.listItem)) 192 | 193 | if (this.options.orderedList !== false) 194 | extensions.push(OrderedList.configure(this.options.orderedList)) 195 | 196 | if (this.options.paragraph !== false) 197 | extensions.push(Paragraph.configure(this.options.paragraph)) 198 | 199 | if (this.options.placeholder !== false) 200 | extensions.push(Placeholder.configure(this.options.placeholder)) 201 | 202 | if (this.options.strike !== false) 203 | extensions.push(Strike.configure(this.options.strike)) 204 | 205 | if (this.options.subscript !== false) 206 | extensions.push(Subscript.configure(this.options.subscript)) 207 | 208 | if (this.options.superscript !== false) 209 | extensions.push(Superscript.configure(this.options.superscript)) 210 | 211 | if (this.options.table !== false) 212 | extensions.push(Table.configure(this.options.table)) 213 | 214 | if (this.options.tableCell !== false) 215 | extensions.push(TableCell.configure(this.options.tableCell)) 216 | 217 | if (this.options.tableHeader !== false) 218 | extensions.push(TableHeader.configure(this.options.tableHeader)) 219 | 220 | if (this.options.tableRow !== false) 221 | extensions.push(TableRow.configure(this.options.tableRow)) 222 | if (this.options.taskItem !== false) 223 | 224 | extensions.push(TaskItem.configure(this.options.taskItem)) 225 | 226 | if (this.options.taskList !== false) 227 | extensions.push(TaskList.configure(this.options.taskList)) 228 | 229 | if (this.options.text !== false) 230 | extensions.push(Text) 231 | 232 | if (this.options.textStyle !== false) 233 | extensions.push(TextStyle.configure(this.options.textStyle)) 234 | 235 | if (this.options.typography !== false) 236 | extensions.push(Typography.configure(this.options.typography)) 237 | 238 | if (this.options.underline !== false) 239 | extensions.push(Underline.configure(this.options.underline)) 240 | 241 | if (this.options.uniqueId !== false) 242 | extensions.push(uniqueId.configure(this.options.uniqueId)) 243 | 244 | if (this.options.details !== false) 245 | extensions.push(details.configure(this.options.details)) 246 | 247 | if (this.options.emoji !== false) 248 | extensions.push(emoji.configure(this.options.emoji)) 249 | 250 | return extensions 251 | }, 252 | }) 253 | -------------------------------------------------------------------------------- /packages/vue-kit/src/vue-shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import type { defineComponent } from 'vue' 3 | 4 | const component: ReturnType 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/vue-kit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "jsxImportSource": "vue", 6 | "moduleResolution": "node", 7 | "resolveJsonModule": true, 8 | "allowJs": true, 9 | "strict": true, 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": false, 12 | "verbatimModuleSyntax": true 13 | }, 14 | "references": [ 15 | { 16 | "path": "./tsconfig.lib.json" 17 | } 18 | ], 19 | "files": [], 20 | "include": [] 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue-kit/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["vite/client"], 5 | "outDir": "../../dist/out-tsc" 6 | }, 7 | "include": [ 8 | "src/**/*.js", 9 | "src/**/*.jsx", 10 | "src/**/*.ts", 11 | "src/**/*.tsx", 12 | "src/**/*.vue" 13 | ], 14 | "exclude": [ 15 | "src/**/__tests__/*", 16 | "src/**/*.spec.ts", 17 | "src/**/*.test.ts", 18 | "src/**/*.spec.tsx", 19 | "src/**/*.test.tsx", 20 | "src/**/*.spec.js", 21 | "src/**/*.test.js", 22 | "src/**/*.spec.jsx", 23 | "src/**/*.test.jsx", 24 | "src/**/*.spec.vue", 25 | "src/**/*.test.vue" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /packages/vue-kit/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import * as path from 'node:path' 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | import dts from 'vite-plugin-dts' 6 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 7 | 8 | export default defineConfig({ 9 | root: __dirname, 10 | cacheDir: '../../node_modules/.vite/packages/vue-kit', 11 | 12 | plugins: [ 13 | vue(), 14 | nxViteTsPaths(), 15 | dts({ 16 | entryRoot: 'src', 17 | tsConfigFilePath: path.join(__dirname, 'tsconfig.lib.json'), 18 | skipDiagnostics: true, 19 | }), 20 | ], 21 | 22 | // Uncomment this if you are using workers. 23 | // worker: { 24 | // plugins: [ nxViteTsPaths() ], 25 | // }, 26 | 27 | // Configuration for building your library. 28 | // See: https://vitejs.dev/guide/build.html#library-mode 29 | build: { 30 | outDir: 'dist', 31 | reportCompressedSize: true, 32 | commonjsOptions: { 33 | transformMixedEsModules: true, 34 | }, 35 | lib: { 36 | // Could also be a dictionary or array of multiple entry points. 37 | entry: 'src/index.ts', 38 | name: 'vue-kit', 39 | fileName: 'index', 40 | // Change this to the formats you want to support. 41 | // Don't forget to update your package.json as well. 42 | formats: ['es', 'cjs'], 43 | }, 44 | rollupOptions: { 45 | // External packages that should not be bundled into your library. 46 | external: [/^@tiptap\//, /^@note-editor\//, 'vue'], 47 | }, 48 | }, 49 | }) 50 | -------------------------------------------------------------------------------- /packages/vue-play/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | vue-play 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/vue-play/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@note-editor/vue-play", 3 | "private": false, 4 | "dependencies": { 5 | "@note-editor/vue-kit": "workspace:*", 6 | "@tiptap/starter-kit": "^2.2.4", 7 | "@tiptap/vue-3": "^2.2.4", 8 | "vue": "^3.4.21" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /packages/vue-play/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-play", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "projectType": "application", 5 | "sourceRoot": "packages/vue-play/src", 6 | "targets": {} 7 | } 8 | -------------------------------------------------------------------------------- /packages/vue-play/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /packages/vue-play/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | 4 | const app = createApp(App) 5 | 6 | app.mount('#root') 7 | -------------------------------------------------------------------------------- /packages/vue-play/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["vite/client"], 5 | "outDir": "../../dist/out-tsc" 6 | }, 7 | "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.vue"], 8 | "exclude": [ 9 | "src/**/*.spec.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.vue", 12 | "src/**/*.test.vue" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/vue-play/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "jsx": "preserve", 5 | "jsxImportSource": "vue", 6 | "moduleResolution": "node", 7 | "resolveJsonModule": true, 8 | "allowJs": true, 9 | "strict": true, 10 | "allowSyntheticDefaultImports": true, 11 | "esModuleInterop": false, 12 | "verbatimModuleSyntax": true 13 | }, 14 | "references": [ 15 | { 16 | "path": "./tsconfig.app.json" 17 | } 18 | ], 19 | "files": [], 20 | "include": [] 21 | } 22 | -------------------------------------------------------------------------------- /packages/vue-play/vite.config.ts: -------------------------------------------------------------------------------- 1 | /// 2 | import { defineConfig } from 'vite' 3 | import vue from '@vitejs/plugin-vue' 4 | import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin' 5 | 6 | export default defineConfig({ 7 | root: __dirname, 8 | cacheDir: '../../node_modules/.vite/packages/vue-play', 9 | 10 | server: { 11 | port: 4200, 12 | host: 'localhost', 13 | }, 14 | 15 | preview: { 16 | port: 4300, 17 | host: 'localhost', 18 | }, 19 | 20 | plugins: [vue(), nxViteTsPaths()], 21 | 22 | // Uncomment this if you are using workers. 23 | // worker: { 24 | // plugins: [ nxViteTsPaths() ], 25 | // }, 26 | 27 | build: { 28 | outDir: 'dist', 29 | reportCompressedSize: true, 30 | commonjsOptions: { 31 | transformMixedEsModules: true, 32 | }, 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "target": "es2015", 5 | "lib": ["es2020", "dom"], 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "baseUrl": ".", 9 | "rootDir": ".", 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "paths": { 13 | "tiptap-extension-block-container": [ 14 | "packages/tiptap-extension-block-container/src/index.ts" 15 | ], 16 | "tiptap-extension-code-block-shiki": [ 17 | "packages/tiptap-extension-code-block-shiki/src/index.ts" 18 | ], 19 | "tiptap-extension-details": [ 20 | "packages/tiptap-extension-details/src/index.ts" 21 | ], 22 | "tiptap-extension-emoji": [ 23 | "packages/tiptap-extension-emoji/src/index.ts" 24 | ], 25 | "tiptap-extension-unique-id": [ 26 | "packages/tiptap-extension-unique-id/src/index.ts" 27 | ], 28 | "vue-kit": ["packages/vue-kit/src/index.ts"], 29 | "vue-play": ["packages/vue-play/src/index.ts"] 30 | }, 31 | "declaration": false, 32 | "importHelpers": true, 33 | "sourceMap": true, 34 | "skipDefaultLibCheck": true, 35 | "skipLibCheck": true 36 | }, 37 | "exclude": ["node_modules", "tmp"] 38 | } 39 | --------------------------------------------------------------------------------