xdd-rich-editor-vue3 2.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +430 -0
  3. package/README.md +219 -0
  4. package/README.zh-CN.md +430 -0
  5. package/dist/.nojekyll +0 -0
  6. package/dist/assets/icons/index.d.ts +3 -0
  7. package/dist/components/bubble-menu/ImageBubbleMenu.vue.d.ts +31 -0
  8. package/dist/components/bubble-menu/index.vue.d.ts +25 -0
  9. package/dist/components/color/BackgroundColorPopover.vue.d.ts +77 -0
  10. package/dist/components/color/ColorPopover.vue.d.ts +77 -0
  11. package/dist/components/emoji/EmojiIcon.vue.d.ts +34 -0
  12. package/dist/components/emoji/EmojiList.vue.d.ts +28 -0
  13. package/dist/components/emoji/suggestion.d.ts +9 -0
  14. package/dist/components/image/ImageIcon.vue.d.ts +94 -0
  15. package/dist/components/image/ImageNodeViewWrapper.vue.d.ts +93 -0
  16. package/dist/components/image/UploadImageModal.vue.d.ts +47 -0
  17. package/dist/components/imports/index.vue.d.ts +77 -0
  18. package/dist/components/layout/Contents.vue.d.ts +51 -0
  19. package/dist/components/link/AddLinkButton.vue.d.ts +51 -0
  20. package/dist/components/table/ContextMenu.vue.d.ts +62 -0
  21. package/dist/components/table/TableIcon.vue.d.ts +36 -0
  22. package/dist/components/task/TaskIcon.vue.d.ts +43 -0
  23. package/dist/components/text/HeadingPopselect.vue.d.ts +97 -0
  24. package/dist/components/text/TextAlignPopselect.vue.d.ts +88 -0
  25. package/dist/components/text/TextLineHeightPopselect.vue.d.ts +88 -0
  26. package/dist/components/toolbar/ButtonIcon.vue.d.ts +55 -0
  27. package/dist/components/toolbar/CodeBlockLowlight.vue.d.ts +127 -0
  28. package/dist/components/toolbar/Toolbar.vue.d.ts +55 -0
  29. package/dist/constants/default-config.d.ts +1 -0
  30. package/dist/constants/toolbar-schema.d.ts +1 -0
  31. package/dist/core/Editor.vue.d.ts +207 -0
  32. package/dist/core/EditorContent.vue.d.ts +112 -0
  33. package/dist/core/editor-props.d.ts +143 -0
  34. package/dist/core/useEditor.d.ts +49 -0
  35. package/dist/core/useEditorEvents.d.ts +36 -0
  36. package/dist/css/style.css +1 -0
  37. package/dist/extensions/code/Code.d.ts +2 -0
  38. package/dist/extensions/code/CodeBlock.d.ts +2 -0
  39. package/dist/extensions/code/CodeBlockLowlight.d.ts +2 -0
  40. package/dist/extensions/emoji/Emoji.d.ts +7 -0
  41. package/dist/extensions/image/Image.d.ts +1 -0
  42. package/dist/extensions/imports/Imports.d.ts +3 -0
  43. package/dist/extensions/index.d.ts +29 -0
  44. package/dist/extensions/link/Link.d.ts +2 -0
  45. package/dist/extensions/list/BulletList.d.ts +2 -0
  46. package/dist/extensions/list/OrderedList.d.ts +2 -0
  47. package/dist/extensions/marks/Bold.d.ts +2 -0
  48. package/dist/extensions/marks/Color.d.ts +2 -0
  49. package/dist/extensions/marks/Highlight.d.ts +2 -0
  50. package/dist/extensions/marks/Italic.d.ts +2 -0
  51. package/dist/extensions/marks/Strike.d.ts +2 -0
  52. package/dist/extensions/marks/Subscript.d.ts +2 -0
  53. package/dist/extensions/marks/Superscript.d.ts +2 -0
  54. package/dist/extensions/marks/TextAlignment.d.ts +2 -0
  55. package/dist/extensions/marks/Underline.d.ts +2 -0
  56. package/dist/extensions/table/Table.d.ts +2 -0
  57. package/dist/extensions/task/TaskItem.d.ts +7 -0
  58. package/dist/extensions/task/TaskList.d.ts +2 -0
  59. package/dist/extensions/title/Heading.d.ts +49 -0
  60. package/dist/extensions/utils/BackgroundColor.d.ts +31 -0
  61. package/dist/extensions/utils/Blockquote.d.ts +2 -0
  62. package/dist/extensions/utils/Clear.d.ts +3 -0
  63. package/dist/extensions/utils/History.d.ts +2 -0
  64. package/dist/extensions/utils/HorizontalRule.d.ts +2 -0
  65. package/dist/extensions/utils/LineHeight.d.ts +39 -0
  66. package/dist/favicon.svg +1 -0
  67. package/dist/hooks/useContextMenu.d.ts +17 -0
  68. package/dist/hooks/useDiscreteApi.d.ts +12 -0
  69. package/dist/hooks/useTev3I18n.d.ts +7 -0
  70. package/dist/hooks/useTheme.d.ts +16 -0
  71. package/dist/icons.svg +24 -0
  72. package/dist/index.d.ts +22 -0
  73. package/dist/install.d.ts +2 -0
  74. package/dist/locales/en-US.d.ts +106 -0
  75. package/dist/locales/index.d.ts +19 -0
  76. package/dist/locales/zh-CN.d.ts +106 -0
  77. package/dist/theme/index.d.ts +7 -0
  78. package/dist/typings/index.d.ts +47 -0
  79. package/dist/utils/color.d.ts +1 -0
  80. package/dist/utils/config.d.ts +11 -0
  81. package/dist/utils/header.d.ts +16 -0
  82. package/dist/utils/image.d.ts +16 -0
  83. package/dist/utils/index.d.ts +5 -0
  84. package/dist/xdd-rich-editor-vue3.es.js +163670 -0
  85. package/dist/xdd-rich-editor-vue3.umd.js +2675 -0
  86. package/package.json +114 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ZekoFront
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.
package/README.en.md ADDED
@@ -0,0 +1,430 @@
1
+ # tiptap-editor-vue3
2
+
3
+ [简体中文](./README.zh-CN.md) | English
4
+
5
+ > A high-quality rich text editor component library built on [Tiptap 3](https://tiptap.dev/) + Vue 3 + TypeScript + Vite.
6
+
7
+ - Batteries included: toolbar, bubble menu, table context menu, outline sidebar, floatable image selection
8
+ - Built-in i18n (Chinese / English, powered by vue-i18n)
9
+ - Light / dark / follow-system theme, fully customisable via CSS variables
10
+ - Full TypeScript types, supports tree-shaking and Hooks-based composition
11
+ - Live demo: **https://zekofront.github.io/tiptap-editor-vue3/**
12
+
13
+ ---
14
+
15
+ ## Features
16
+
17
+ | Category | Items |
18
+ | -------- | ----- |
19
+ | **Text marks** | Bold, Italic, Underline, Strike, Highlight, Text color, Background color, Subscript, Superscript, Inline code |
20
+ | **Block nodes** | Heading H1–H6, Paragraph, Bullet list, Ordered list, **Task list** (checkable), Blockquote, Horizontal rule, **Code block** (lowlight syntax highlight), Image, Table, Link, **Emoji** (`:` trigger) |
21
+ | **Layout & behaviour** | Text alignment (left / center / right / justify), Line height, Drag handle (move blocks), RTL support |
22
+ | **Editor UX** | Top toolbar, Selection bubble menu, Image bubble menu, Table context menu, Outline / table-of-contents sidebar, Placeholder, Character count limit, Undo / redo, Clear document, **Import documents** (TXT, DOC, DOCX), Export to **DOCX** |
23
+ | **Component-level** | Read-only view (`XddRichEditorView`), `useEditor` / `useEditorEvents` Hooks, Light / dark / system theme, zh-CN / en-US i18n, Customizable bubble menu items, CSS variables for theming |
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install tiptap-editor-vue3
31
+ # or
32
+ pnpm add tiptap-editor-vue3
33
+ # or
34
+ yarn add tiptap-editor-vue3
35
+ ```
36
+
37
+ > Requires **Vue 3** in your project (the only external dependency; all other deps — Tiptap, naive-ui, vue-i18n, etc. — are bundled into the dist).
38
+
39
+ ---
40
+
41
+ ## Quick Start
42
+
43
+ ### Option 1: Install as a plugin (recommended)
44
+
45
+ ```ts
46
+ // main.ts
47
+ import { createApp } from "vue";
48
+ import XddRichEditorVue3 from "tiptap-editor-vue3";
49
+ import "tiptap-editor-vue3/dist/css/style.css";
50
+ import App from "./App.vue";
51
+
52
+ const app = createApp(App);
53
+ app.use(XddRichEditorVue3);
54
+ app.mount("#app");
55
+ ```
56
+
57
+ ```vue
58
+ <!-- App.vue -->
59
+ <template>
60
+ <XddRichEditorVue3
61
+ v-model="content"
62
+ :is-editable="true"
63
+ :character-count="20000"
64
+ locale="en-US"
65
+ placeholder="Start typing..."
66
+ @ready="onReady"
67
+ @update="onUpdate"
68
+ />
69
+ </template>
70
+
71
+ <script setup lang="ts">
72
+ import { ref } from "vue";
73
+ import type { Editor, EditorUpdatePayload } from "tiptap-editor-vue3";
74
+
75
+ const content = ref("<p>Initial content</p>");
76
+
77
+ const onReady = (editor: Editor) => {
78
+ console.log("editor ready", editor);
79
+ };
80
+
81
+ const onUpdate = ({ html, json }: EditorUpdatePayload) => {
82
+ console.log(html, json);
83
+ };
84
+ </script>
85
+ ```
86
+
87
+ > Use `v-model` to two-way bind content. Pass an HTML string (default) or a Tiptap JSON object; toggle the format emitted by `update:modelValue` via the `outputFormat` prop.
88
+
89
+ ### Option 2: On-demand import
90
+
91
+ ```vue
92
+ <template>
93
+ <XddRichEditorVue3 v-model:is-editable="editable" @update="onUpdate" />
94
+ </template>
95
+
96
+ <script setup lang="ts">
97
+ import { ref } from "vue";
98
+ import { XddRichEditorVue3, type EditorUpdatePayload } from "tiptap-editor-vue3";
99
+ import "tiptap-editor-vue3/dist/css/style.css";
100
+
101
+ const editable = ref(true);
102
+ const onUpdate = (p: EditorUpdatePayload) => console.log(p.html);
103
+ </script>
104
+ ```
105
+
106
+ ### Read-only view
107
+
108
+ ```vue
109
+ <template>
110
+ <XddRichEditorView :editor="editor" />
111
+ </template>
112
+
113
+ <script setup lang="ts">
114
+ import { XddRichEditorView, useEditor } from "tiptap-editor-vue3";
115
+ import StarterKit from "@tiptap/starter-kit";
116
+
117
+ const { editor } = useEditor({
118
+ extensions: () => [StarterKit],
119
+ content: () => "<p>Hello</p>",
120
+ editable: () => false
121
+ });
122
+ </script>
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Props
128
+
129
+ | Name | Type | Default | Description |
130
+ | ---- | ---- | ------- | ----------- |
131
+ | `modelValue` (`v-model`) | `string \| JSONContent \| null` | `""` | Editor content. HTML string or Tiptap JSON |
132
+ | `outputFormat` | `'html' \| 'json'` | `'html'` | Format of the value emitted by `update:modelValue` |
133
+ | `defaultConfig` | `Record<string, any> \| null` | `null` | Extra options forwarded to the underlying `new Editor(...)` |
134
+ | `extensions` | `AnyExtension[]` | `[]` | Custom extensions; falls back to the built-in full set when empty |
135
+ | `isEditable` | `boolean` | `true` | Whether the editor is editable |
136
+ | `isShowToolbar` | `boolean` | `true` | Show the top toolbar |
137
+ | `isEnabledContent` | `boolean` | `true` | Render the content area (toolbar-only when `false`) |
138
+ | `characterCount` | `number \| string` | `10000` | Maximum character count; further input is blocked |
139
+ | `locale` | `'zh-CN' \| 'en-US'` | `'zh-CN'` | UI locale (toolbar tooltips, table menus, placeholder, etc.) |
140
+ | `theme` | `'system' \| 'light' \| 'dark'` | `'system'` | Color theme; `system` follows OS `prefers-color-scheme` |
141
+ | `placeholder` | `string` | i18n default | Placeholder for empty document; falls back to the current locale |
142
+ | `customDubbleMenus` | `IDubbleMenu[]` | `[]` | Custom buttons for the bubble menu |
143
+ | `editorWrapperClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the outermost wrapper |
144
+ | `editorToolkitClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the toolbar |
145
+ | `editorContentClass` | `string` | `'custom-tiptap-content'` | Class for the ProseMirror content container |
146
+ | `editorContentsNavClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the outline sidebar |
147
+
148
+ > Types like `IDubbleMenu` are exported from the package: `import type { IDubbleMenu, EditorProps } from "tiptap-editor-vue3"`.
149
+
150
+ ---
151
+
152
+ ## Events
153
+
154
+ | Event | Payload | Description |
155
+ | ----- | ----- | ----------- |
156
+ | `update:modelValue` | `string \| JSONContent` | Content changed (`v-model` sync). HTML string by default, or JSON when `outputFormat="json"` |
157
+ | `ready` | `editor: Editor` | Fired once the editor instance is ready (equivalent to Tiptap's `create`) |
158
+ | `update` | `{ editor, html, json }` | Content changed; `html` / `json` are pre-computed |
159
+ | `selection-update` | `{ editor }` | Caret / selection changed |
160
+ | `transaction` | `{ editor, transaction }` | Any ProseMirror transaction |
161
+ | `focus` | `{ editor, event: FocusEvent }` | Editor gained focus |
162
+ | `blur` | `{ editor, event: FocusEvent }` | Editor lost focus |
163
+ | `before-create` | `{ editor }` | Before the instance is created |
164
+ | `content-error` | `{ editor, error }` | Failed to parse initial content |
165
+ | `destroy` | — | Instance destroyed |
166
+
167
+ `update` payload type:
168
+
169
+ ```ts
170
+ import type { EditorUpdatePayload } from "tiptap-editor-vue3";
171
+
172
+ interface EditorUpdatePayload {
173
+ editor: Editor;
174
+ html: string;
175
+ json: JSONContent;
176
+ }
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Import Documents (TXT, Word)
182
+
183
+ The editor supports importing content from TXT and Word (DOC, DOCX) files via the import button in the toolbar. When clicked, a dropdown menu appears with options to import TXT or Word files. After selecting a file, the content is parsed and inserted into the editor. Success and error messages are displayed using localized notifications.
184
+
185
+
186
+ ## Image upload
187
+
188
+ All image-upload customisation lives under `defaultConfig.uploadImage`. The rule is simple:
189
+
190
+ - If `imageLink` / `customUpload` are **functions**, the modal hands the URL / files to your code and you call `editor.commands.setImage(...)` yourself.
191
+ - Otherwise the editor falls back to its built-in behaviour (URL → `setImage({ src })`, file → base64 → `setImage`).
192
+
193
+ `accept` / `maxSize` / `maxCount` always run first — invalid files are rejected with a localised toast before your callback is invoked, and clicking "Upload" with nothing selected shows a warning.
194
+
195
+ > Custom image upload — **the structure below must be respected exactly, otherwise the callbacks won't fire**:
196
+
197
+ ```vue
198
+ <template>
199
+ <XddRichEditorVue3
200
+ v-model="content"
201
+ :default-config="defaultConfig"
202
+ @ready="onReady"
203
+ />
204
+ </template>
205
+
206
+ <script setup lang="ts">
207
+ import { shallowRef } from "vue";
208
+ import type { Editor, Tev3DefaultConfig } from "tiptap-editor-vue3";
209
+
210
+ const editors = shallowRef<Editor | null>(null);
211
+
212
+ const onReady = (editor: Editor) => {
213
+ editors.value = editor;
214
+ };
215
+
216
+ const defaultConfig: Tev3DefaultConfig = {
217
+ uploadImage: {
218
+ accept: "image/png,image/jpeg,image/webp",
219
+ maxSize: 5 * 1024 * 1024, // 5 MB per file
220
+ maxCount: 9,
221
+ imageLink: (link: string) => {
222
+ console.log(link, editors.value, "imageLink");
223
+ editors.value?.commands.setImage({ src: link });
224
+ },
225
+ customUpload: async (files) => {
226
+ console.log(files, editors.value, "customUpload");
227
+ for (let i = 0; i < files.length; i++) {
228
+ if (files[i]) setImageOne(files[i] as File);
229
+ }
230
+ }
231
+ }
232
+ };
233
+
234
+ const setImageOne = (file: File) => {
235
+ const reader = new FileReader();
236
+ reader.onload = event => {
237
+ const base64 = event.target?.result as string;
238
+ editors.value?.commands.setImage({ src: base64 });
239
+ };
240
+ reader.readAsDataURL(file);
241
+ };
242
+ </script>
243
+ ```
244
+
245
+ | Field | Type | Default | Description |
246
+ | ----- | ---- | ------- | ----------- |
247
+ | `accept` | `string` | `image/png,image/jpeg,image/gif,image/webp,image/svg+xml` | HTML `accept` syntax; filters the file picker and validates types |
248
+ | `maxSize` | `number` | `10 * 1024 * 1024` | Max bytes per file. Oversized files are rejected with a toast |
249
+ | `maxCount` | `number` | `Infinity` | Max files per upload session |
250
+ | `imageLink` | `(url: string) => void` | — | "Insert by URL" callback. Defined → custom path; otherwise default `setImage({ src })` |
251
+ | `customUpload` | `(files: File[] \| FileList) => void \| Promise<void>` | — | "Upload" callback. Defined → custom path; otherwise files are inlined as base64 |
252
+
253
+ Exported types: `Tev3DefaultConfig`, `Tev3UploadImageConfig`.
254
+
255
+ ---
256
+
257
+ ## Theme (light / dark)
258
+
259
+ Controlled by the `theme` prop:
260
+
261
+ ```vue
262
+ <XddRichEditorVue3 theme="system" />
263
+ <XddRichEditorVue3 theme="light" />
264
+ <XddRichEditorVue3 theme="dark" />
265
+ ```
266
+
267
+ - `system`: follows the OS `prefers-color-scheme` and reacts in real time;
268
+ - `light` / `dark`: pinned to that theme.
269
+
270
+ Internally a `data-tev3-theme="light|dark"` attribute is applied to the wrapper and all colors are driven by CSS variables. To customise the palette, override variables in your stylesheet:
271
+
272
+ ```css
273
+ .vue3-tiptap-editor[data-tev3-theme="light"] {
274
+ --theme-color: #2080f0;
275
+ --tev3-toolbar-bg: #fafbfc;
276
+ }
277
+
278
+ .vue3-tiptap-editor[data-tev3-theme="dark"] {
279
+ --theme-color: #36ad6a;
280
+ --tev3-editor-bg: #15161a;
281
+ }
282
+ ```
283
+
284
+ You can also drive themes programmatically with `useTheme()`:
285
+
286
+ ```ts
287
+ import { ref } from "vue";
288
+ import { useTheme, type Tev3Theme } from "tiptap-editor-vue3";
289
+
290
+ const theme = ref<Tev3Theme>("system");
291
+ const { resolvedTheme } = useTheme(() => theme.value); // -> 'light' | 'dark'
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Internationalization
297
+
298
+ Built-in `zh-CN` / `en-US` messages. Switch via the `locale` prop, or call `setLocale()` programmatically.
299
+
300
+ ```ts
301
+ import { setLocale, t } from "tiptap-editor-vue3";
302
+
303
+ setLocale("en-US");
304
+ console.log(t("toolbar.bold")); // "Bold"
305
+ ```
306
+
307
+ ```vue
308
+ <XddRichEditorVue3 locale="en-US" />
309
+ ```
310
+
311
+ > The toolbar, table menus, outline sidebar and placeholder refresh automatically when `locale` changes.
312
+
313
+ To override or extend messages, call `tev3I18n.global.mergeLocaleMessage('en-US', { ... })` from your app.
314
+
315
+ ---
316
+
317
+ ## Advanced: Compose with Hooks
318
+
319
+ If the built-in toolbar does not fit your needs, build your own UI on top of `useEditor` / `useEditorEvents`:
320
+
321
+ ```vue
322
+ <template>
323
+ <div>
324
+ <button @click="editor?.chain().focus().toggleBold().run()">Bold</button>
325
+ <XddRichEditorView :editor="editor" />
326
+ </div>
327
+ </template>
328
+
329
+ <script setup lang="ts">
330
+ import {
331
+ XddRichEditorView,
332
+ useEditor,
333
+ useEditorEvents,
334
+ type EditorUpdatePayload
335
+ } from "tiptap-editor-vue3";
336
+ import StarterKit from "@tiptap/starter-kit";
337
+
338
+ const emit = defineEmits<{ (e: "update", p: EditorUpdatePayload): void }>();
339
+
340
+ const { editor, editable, toggleEditable } = useEditor({
341
+ extensions: () => [StarterKit],
342
+ content: () => "<p>Hello</p>",
343
+ editable: () => true
344
+ });
345
+
346
+ useEditorEvents(editor, { emit });
347
+ </script>
348
+ ```
349
+
350
+ `useEditor` returns:
351
+
352
+ | Field | Type | Description |
353
+ | ----- | ---- | ----------- |
354
+ | `editor` | `ShallowRef<Editor \| null>` | Instance (ready after `onMounted`) |
355
+ | `editable` | `Ref<boolean>` | Editable state |
356
+ | `rtl` | `Ref<boolean>` | RTL layout flag |
357
+ | `toggleEditable` | `() => void` | Toggle editable state |
358
+ | `toggleRtl` | `() => void` | Toggle RTL |
359
+ | `create` / `destroy` | `() => void` | Manual lifecycle control |
360
+
361
+ ---
362
+
363
+ ## Public API
364
+
365
+ ```ts
366
+ // Components
367
+ export { XddRichEditorVue3, XddRichEditorView };
368
+
369
+ // Composables
370
+ export { useEditor, useEditorEvents, useTev3I18n };
371
+
372
+ // Props / Types
373
+ export { editorProps };
374
+ export type {
375
+ EditorProps,
376
+ UseEditorOptions,
377
+ UseEditorReturn,
378
+ EditorUpdatePayload,
379
+ EditorEventName,
380
+ Tev3Locale
381
+ };
382
+
383
+ // i18n
384
+ export { tev3I18n, t, setLocale, getLocale, installTev3I18n, SUPPORTED_LOCALES, zhCN, enUS };
385
+
386
+ // Theme
387
+ export { SUPPORTED_THEMES, DEFAULT_THEME, resolveTheme, useTheme };
388
+ export type { Tev3Theme, Tev3ResolvedTheme };
389
+
390
+ // Re-exported Tiptap APIs (avoid double installs)
391
+ export { Editor, EditorContent, NodeViewWrapper, mergeAttributes };
392
+ export type { XddRichEditor, JSONContent, Content, AnyExtension };
393
+ ```
394
+
395
+ ---
396
+
397
+ ## Scripts
398
+
399
+ ```bash
400
+ npm run dev # Start the local playground
401
+ npm run build # Build the component library (dist/)
402
+ npm run build:demo # Build the playground demo site (dist-demo/)
403
+ npm run preview:demo # Preview the demo build locally
404
+ npm run fmt # Format (oxfmt)
405
+ npm run lint # Lint (oxlint)
406
+ ```
407
+
408
+ ---
409
+
410
+ ## Live Demo (GitHub Pages)
411
+
412
+ `.github/workflows/deploy-pages.yml` automatically builds and publishes `dist-demo` after every push to `main`.
413
+
414
+ In the GitHub repository, set `Settings → Pages → Source` to **GitHub Actions**. Demo URL:
415
+
416
+ **https://zekofront.github.io/tiptap-editor-vue3/**
417
+
418
+ ---
419
+
420
+ ## References
421
+
422
+ - [Tiptap 3 Documentation](https://tiptap.dev/docs)
423
+ - [ProseMirror Reference](https://prosemirror.net/docs/ref/)
424
+ - [Vue 3 + TypeScript Guide](https://vuejs.org/guide/typescript/overview.html)
425
+
426
+ ---
427
+
428
+ ## License
429
+
430
+ [MIT](./LICENSE)
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # tiptap-editor-vue3
2
+
3
+ [![npm](https://img.shields.io/npm/v/tiptap-editor-vue3.svg)](https://www.npmjs.com/package/tiptap-editor-vue3)
4
+ [![license](https://img.shields.io/npm/l/tiptap-editor-vue3.svg)](./LICENSE)
5
+
6
+ > A high-quality rich text editor component library built on **[Tiptap 3](https://tiptap.dev/) + Vue 3 + TypeScript**.
7
+ >
8
+ > 基于 **Tiptap 3 + Vue 3 + TypeScript** 的高质量富文本编辑器组件库。
9
+
10
+ - Batteries included: toolbar, bubble menu, table context menu, outline sidebar
11
+ - Built-in **i18n** (zh-CN / en-US) and **theme** (light / dark / system)
12
+ - Full TypeScript types, tree-shakable, Hooks-friendly
13
+ - **Live demo**: https://zekofront.github.io/tiptap-editor-vue3/
14
+
15
+ ## Features
16
+
17
+ **Text formatting** — Bold · Italic · Underline · Strike · Highlight · Text color · Background color · Subscript · Superscript · Inline code
18
+
19
+ **Blocks** — Heading (H1–H6) · Paragraph · Bullet list · Ordered list · Task list (checkable) · Blockquote · Horizontal rule · Code block (with syntax highlight via lowlight) · Image · Table · Link · Emoji (`:` trigger)
20
+
21
+ **Layout** — Text alignment (left / center / right / justify) · Line height · Drag handle (move blocks) · RTL support
22
+
23
+ **Editor UX** — Top toolbar · Selection bubble menu · Image bubble menu · Table context menu · Outline / table-of-contents sidebar · Placeholder · Character count limit · Undo / redo · Clear document · Export to **DOCX** · **Import TXT and Word documents**
24
+
25
+ **Component-level** — Read-only view (`XddRichEditorView`) · `useEditor` / `useEditorEvents` Hooks for custom UI · Light / dark / system theme · Chinese / English i18n · Customizable bubble menu items · CSS variables for theming
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ npm install tiptap-editor-vue3
31
+ ```
32
+
33
+ > Requires **Vue 3** in your project (the only external dependency; all other deps are bundled).
34
+
35
+ ## Usage
36
+
37
+ ```ts
38
+ // main.ts
39
+ import { createApp } from "vue";
40
+ import XddRichEditorVue3 from "tiptap-editor-vue3";
41
+ import "tiptap-editor-vue3/dist/css/style.css";
42
+ import App from "./App.vue";
43
+
44
+ createApp(App).use(XddRichEditorVue3).mount("#app");
45
+ ```
46
+
47
+ ```vue
48
+ <template>
49
+ <XddRichEditorVue3
50
+ v-model="content"
51
+ :is-editable="true"
52
+ :character-count="20000"
53
+ locale="zh-CN"
54
+ theme="system"
55
+ placeholder="Start typing..."
56
+ @ready="onReady"
57
+ @update="onUpdate"
58
+ />
59
+ </template>
60
+
61
+ <script setup lang="ts">
62
+ import { ref } from "vue";
63
+ import type { Editor, EditorUpdatePayload } from "tiptap-editor-vue3";
64
+
65
+ const content = ref("<p>Hello world</p>");
66
+
67
+ const onReady = (editor: Editor) => console.log("ready", editor);
68
+ const onUpdate = ({ html, json }: EditorUpdatePayload) => console.log(html, json);
69
+ </script>
70
+ ```
71
+
72
+ > Use `v-model` to two-way bind content. Pass an HTML string (default) or a Tiptap JSON object; toggle the format of `update:modelValue` via the `outputFormat` prop.
73
+
74
+ ## Props
75
+
76
+ | Name | Type | Default | Description |
77
+ | ---- | ---- | ------- | ----------- |
78
+ | `modelValue` (`v-model`) | `string \| JSONContent \| null` | `""` | Editor content. HTML string or Tiptap JSON |
79
+ | `outputFormat` | `'html' \| 'json'` | `'html'` | Format of the value emitted by `update:modelValue` |
80
+ | `defaultConfig` | `Record<string, any> \| null` | `null` | Extra options forwarded to the underlying `new Editor(...)` |
81
+ | `extensions` | `AnyExtension[]` | `[]` | Custom extensions; falls back to the built-in full set when empty |
82
+ | `isEditable` | `boolean` | `true` | Whether the editor is editable |
83
+ | `isShowToolbar` | `boolean` | `true` | Show the top toolbar |
84
+ | `isEnabledContent` | `boolean` | `true` | Render the content area (toolbar-only when `false`) |
85
+ | `characterCount` | `number \| string` | `10000` | Maximum character count; further input is blocked |
86
+ | `locale` | `'zh-CN' \| 'en-US'` | `'zh-CN'` | UI locale (toolbar tooltips, table menus, placeholder, etc.) |
87
+ | `theme` | `'system' \| 'light' \| 'dark'` | `'system'` | Color theme; `system` follows OS `prefers-color-scheme` |
88
+ | `placeholder` | `string` | i18n default | Placeholder for empty document |
89
+ | `customDubbleMenus` | `IDubbleMenu[]` | `[]` | Custom buttons for the bubble menu |
90
+ | `editorWrapperClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the outermost wrapper |
91
+ | `editorToolkitClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the toolbar |
92
+ | `editorContentClass` | `string` | `'custom-tiptap-content'` | Class for the ProseMirror content container |
93
+ | `editorContentsNavClass` | `string \| any[] \| Record<string, any>` | `undefined` | Class for the outline sidebar |
94
+
95
+ ## Events
96
+
97
+ | Event | Payload | Description |
98
+ | ----- | ------- | ----------- |
99
+ | `update:modelValue` | `string \| JSONContent` | Content changed (`v-model` sync). HTML string by default, or JSON when `outputFormat="json"` |
100
+ | `ready` | `editor: Editor` | Editor instance is ready (Tiptap `create`) |
101
+ | `update` | `{ editor, html, json }` | Content changed; `html` / `json` are pre-computed |
102
+ | `selection-update` | `{ editor }` | Caret / selection changed |
103
+ | `transaction` | `{ editor, transaction }` | Any ProseMirror transaction |
104
+ | `focus` | `{ editor, event: FocusEvent }` | Editor gained focus |
105
+ | `blur` | `{ editor, event: FocusEvent }` | Editor lost focus |
106
+ | `before-create` | `{ editor }` | Before the instance is created |
107
+ | `content-error` | `{ editor, error }` | Failed to parse initial content |
108
+ | `destroy` | — | Instance destroyed |
109
+
110
+ `update` payload type:
111
+
112
+ ```ts
113
+ import type { EditorUpdatePayload } from "tiptap-editor-vue3";
114
+
115
+ interface EditorUpdatePayload {
116
+ editor: Editor;
117
+ html: string;
118
+ json: JSONContent;
119
+ }
120
+ ```
121
+
122
+ ## Import Documents (TXT and Word)
123
+
124
+ The editor supports importing content from TXT and Word documents directly. This feature allows users to easily bring content from external documents into the editor. To use this feature, click on the import button in the toolbar and select either "Import TXT file" or "Import Word file".
125
+
126
+ ## Image upload
127
+
128
+ Custom image uploading is configured through `defaultConfig.uploadImage`. The rule is simple:
129
+
130
+ - If `imageLink` / `customUpload` are **functions**, the modal hands the URL / files to your code and you call `editor.commands.setImage(...)` yourself.
131
+ - Otherwise the editor falls back to the built-in behaviour (URL → `setImage({ src })`, file → base64 → `setImage`).
132
+
133
+ `accept` / `maxSize` / `maxCount` always run first — invalid files are rejected with a localised toast before your callback is invoked, and clicking "Upload" with nothing selected shows a warning.
134
+
135
+ ```vue
136
+ <template>
137
+ <XddRichEditorVue3
138
+ v-model="content"
139
+ :default-config="defaultConfig"
140
+ @ready="onReady"
141
+ />
142
+ </template>
143
+
144
+ <script setup lang="ts">
145
+ import { shallowRef } from "vue";
146
+ import type { Editor, Tev3DefaultConfig } from "tiptap-editor-vue3";
147
+
148
+ const editors = shallowRef<Editor | null>(null);
149
+
150
+ const onReady = (editor: Editor) => {
151
+ editors.value = editor;
152
+ };
153
+
154
+ // Custom image upload — must follow this exact shape, otherwise the callbacks won't fire
155
+ const defaultConfig: Tev3DefaultConfig = {
156
+ uploadImage: {
157
+ accept: "image/png,image/jpeg,image/webp",
158
+ maxSize: 5 * 1024 * 1024, // 5 MB per file
159
+ maxCount: 9,
160
+ imageLink: (link: string) => {
161
+ console.log(link, editors.value, "imageLink");
162
+ editors.value?.commands.setImage({ src: link });
163
+ },
164
+ customUpload: async (files) => {
165
+ console.log(files, editors.value, "customUpload");
166
+ for (let i = 0; i < files.length; i++) {
167
+ if (files[i]) setImageOne(files[i] as File);
168
+ }
169
+ }
170
+ }
171
+ };
172
+
173
+ const setImageOne = (file: File) => {
174
+ const reader = new FileReader();
175
+ reader.onload = event => {
176
+ const base64 = event.target?.result as string;
177
+ editors.value?.commands.setImage({ src: base64 });
178
+ };
179
+ reader.readAsDataURL(file);
180
+ };
181
+ </script>
182
+ ```
183
+
184
+ | Field | Type | Default | Description |
185
+ | ----- | ---- | ------- | ----------- |
186
+ | `accept` | `string` | `image/png,image/jpeg,image/gif,image/webp,image/svg+xml` | HTML `accept` syntax; filters the file picker and validates types |
187
+ | `maxSize` | `number` | `10 * 1024 * 1024` | Max bytes per file. Oversized files are rejected with a toast |
188
+ | `maxCount` | `number` | `Infinity` | Max files per upload session |
189
+ | `imageLink` | `(url: string) => void` | — | Callback for the "Insert by URL" tab. Defined → custom path; otherwise default `setImage({ src })` |
190
+ | `customUpload` | `(files: File[] \| FileList) => void \| Promise<void>` | — | Callback for the "Upload" tab. Defined → custom path; otherwise files are inlined as base64 |
191
+
192
+ Exported types: `Tev3DefaultConfig`, `Tev3UploadImageConfig`.
193
+
194
+ ## Theme & i18n
195
+
196
+ ```vue
197
+ <XddRichEditorVue3 theme="dark" locale="en-US" />
198
+ ```
199
+
200
+ - `theme`: `'system' | 'light' | 'dark'` — applied via `data-tev3-theme` on the wrapper, all colors driven by CSS variables (override `--theme-color`, `--tev3-editor-bg`, `--tev3-toolbar-bg`, etc.)
201
+ - `locale`: `'zh-CN' | 'en-US'` — toolbar / menus / placeholder switch reactively
202
+
203
+ ```ts
204
+ import { setLocale, useTheme, type Tev3Theme } from "tiptap-editor-vue3";
205
+
206
+ setLocale("en-US");
207
+ const { resolvedTheme } = useTheme(() => "system"); // -> 'light' | 'dark'
208
+ ```
209
+
210
+ ## Documentation
211
+
212
+ Full documentation including theme customisation, Hooks-based composition (`useEditor` / `useEditorEvents`) and the public API surface:
213
+
214
+ - [English](https://github.com/ZekoFront/tiptap-editor-vue3/blob/main/README.en.md)
215
+ - [简体中文](https://github.com/ZekoFront/tiptap-editor-vue3/blob/main/README.zh-CN.md)
216
+
217
+ ## License
218
+
219
+ [MIT](./LICENSE) © ZekoFront