@domternal/vue 0.9.1 → 0.11.0
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.
- package/README.md +3 -3
- package/dist/index.js +24 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -21,14 +21,14 @@ See <u>[Packages & Bundle Size](https://domternal.dev/v1/packages)</u> for a ful
|
|
|
21
21
|
- **Vue components** - composable `Domternal` component, `useEditor`/`useEditorState` composables, toolbar, bubble menu, floating menu, emoji picker, notion color picker, custom node views (Vue 3.3+)
|
|
22
22
|
- **Vanilla wrapper** - framework-free class-based API for Astro, Svelte, Solid, plain HTML, and Web Components - editor, toolbar, bubble menu, floating menu, emoji picker, notion color picker
|
|
23
23
|
- **Notion-style block UX** - drag-to-reorder, block context menu, slash command, smart paste, keyboard reorder, floating Table of Contents
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
24
|
+
- **70+ extensions across 16 packages** - nodes, marks, and behavior extensions
|
|
25
|
+
- **125+ chainable commands** - `editor.chain().focus().toggleBold().run()`
|
|
26
26
|
- **Full table support** - cell merging, column resize, row/column controls, cell toolbar, all free and MIT licensed
|
|
27
27
|
- **Tree-shakeable** - import only what you use, your bundler strips the rest
|
|
28
28
|
- **~44 KB gzipped** (own code), <u>[see Packages](https://domternal.dev/v1/packages)</u> for full bundle breakdown with ProseMirror
|
|
29
29
|
- **TypeScript first** - 100% typed, zero `any`
|
|
30
30
|
- **15,000+ tests** - 4,000+ unit and 11,000+ E2E across 230+ Playwright specs and 4 demo apps
|
|
31
|
-
- **Light and dark theme** -
|
|
31
|
+
- **Light and dark theme** - 120+ CSS custom properties for full visual control
|
|
32
32
|
- **Inline styles export** - `getHTML({ styled: true })` produces inline CSS ready for email clients, CMS, and Google Docs
|
|
33
33
|
- **SSR helpers** - `generateHTML`, `generateJSON`, `generateText` for server-side rendering
|
|
34
34
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineComponent, h, computed, Fragment, ref, watch, shallowRef, onMounted, nextTick, onScopeDispose, watchEffect, Teleport, inject, provide, getCurrentInstance, customRef, markRaw, shallowReactive, render } from 'vue';
|
|
2
|
-
import { positionFloatingOnce, PluginKey, positionFloating, ToolbarController, createFloatingMenuPlugin, FloatingMenuController, defaultIcons, defaultBubbleContexts, createBubbleMenuPlugin, Editor, Document, Paragraph, Text, BaseKeymap, History } from '@domternal/core';
|
|
2
|
+
import { positionFloatingOnce, PluginKey, positionFloating, ToolbarController, refocusEditorAfterCommand, createFloatingMenuPlugin, FloatingMenuController, defaultIcons, defaultBubbleContexts, createBubbleMenuPlugin, Editor, Document, Paragraph, Text, BaseKeymap, History } from '@domternal/core';
|
|
3
3
|
export { Editor, generateHTML, generateJSON, generateText } from '@domternal/core';
|
|
4
4
|
|
|
5
5
|
// src/useEditor.ts
|
|
@@ -10,7 +10,7 @@ function useEditor(options = {}) {
|
|
|
10
10
|
let pendingContent = null;
|
|
11
11
|
function wireEvents(ed) {
|
|
12
12
|
ed.on("transaction", ({ transaction }) => {
|
|
13
|
-
if (transaction.docChanged) {
|
|
13
|
+
if (transaction.docChanged && !transaction.getMeta("skipUpdate")) {
|
|
14
14
|
options.onUpdate?.({ editor: ed });
|
|
15
15
|
}
|
|
16
16
|
if (!transaction.docChanged && transaction.selectionSet) {
|
|
@@ -40,17 +40,19 @@ function useEditor(options = {}) {
|
|
|
40
40
|
options.onCreate?.(ed);
|
|
41
41
|
return ed;
|
|
42
42
|
}
|
|
43
|
-
function destroyCurrentEditor() {
|
|
43
|
+
function destroyCurrentEditor(insertClone = true) {
|
|
44
44
|
const current = editor.value;
|
|
45
45
|
if (current && !current.isDestroyed) {
|
|
46
46
|
pendingContent = current.getJSON();
|
|
47
47
|
options.onDestroy?.();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
if (insertClone) {
|
|
49
|
+
const dom = current.view.dom;
|
|
50
|
+
const parent = dom.parentNode;
|
|
51
|
+
if (parent) {
|
|
52
|
+
const clone = dom.cloneNode(true);
|
|
53
|
+
clone.style.pointerEvents = "none";
|
|
54
|
+
parent.insertBefore(clone, dom);
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
current.destroy();
|
|
56
58
|
}
|
|
@@ -61,7 +63,14 @@ function useEditor(options = {}) {
|
|
|
61
63
|
createEditorInstance(element, options.content ?? "", options.autofocus ?? false);
|
|
62
64
|
}
|
|
63
65
|
onMounted(() => {
|
|
64
|
-
|
|
66
|
+
const ed = editor.value;
|
|
67
|
+
if (ed) {
|
|
68
|
+
const mount = editorRef.value;
|
|
69
|
+
if (mount && ed.view.dom.parentElement !== mount) {
|
|
70
|
+
mount.appendChild(ed.view.dom);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
65
74
|
const element = editorRef.value ?? document.createElement("div");
|
|
66
75
|
const initialContent = pendingContent ?? options.content ?? "";
|
|
67
76
|
pendingContent = null;
|
|
@@ -85,7 +94,7 @@ function useEditor(options = {}) {
|
|
|
85
94
|
if (!editor.value || editor.value.isDestroyed) return;
|
|
86
95
|
if (newExtensions === oldExtensions) return;
|
|
87
96
|
const element = editor.value.view.dom.parentElement ?? document.createElement("div");
|
|
88
|
-
destroyCurrentEditor();
|
|
97
|
+
destroyCurrentEditor(false);
|
|
89
98
|
const initialContent = pendingContent ?? "";
|
|
90
99
|
pendingContent = null;
|
|
91
100
|
createEditorInstance(element, initialContent, false);
|
|
@@ -858,9 +867,7 @@ var DomternalToolbar = defineComponent({
|
|
|
858
867
|
return;
|
|
859
868
|
}
|
|
860
869
|
executeCommand(item);
|
|
861
|
-
|
|
862
|
-
editor.view.focus();
|
|
863
|
-
});
|
|
870
|
+
refocusEditorAfterCommand(editor.view);
|
|
864
871
|
}
|
|
865
872
|
function onDropdownItemClick(item, event) {
|
|
866
873
|
const editor = props.editor ?? contextEditor.value;
|
|
@@ -876,9 +883,7 @@ var DomternalToolbar = defineComponent({
|
|
|
876
883
|
} else {
|
|
877
884
|
executeCommand(item);
|
|
878
885
|
}
|
|
879
|
-
|
|
880
|
-
editor.view.focus();
|
|
881
|
-
});
|
|
886
|
+
refocusEditorAfterCommand(editor.view);
|
|
882
887
|
}
|
|
883
888
|
function onButtonFocus(name) {
|
|
884
889
|
const index = controllerRef.current?.getFlatIndex(name) ?? -1;
|
|
@@ -1385,9 +1390,7 @@ var DomternalBubbleMenu = defineComponent({
|
|
|
1385
1390
|
const ed = editorRef.value;
|
|
1386
1391
|
if (!ed) return;
|
|
1387
1392
|
ToolbarController.executeItem(ed, sub);
|
|
1388
|
-
|
|
1389
|
-
ed.view.focus();
|
|
1390
|
-
});
|
|
1393
|
+
refocusEditorAfterCommand(ed.view);
|
|
1391
1394
|
};
|
|
1392
1395
|
const colorBtnRef = ref();
|
|
1393
1396
|
const blockMenuBtnRef = ref();
|
|
@@ -1700,9 +1703,7 @@ var DomternalFloatingMenu = defineComponent({
|
|
|
1700
1703
|
const ed = currentEditor;
|
|
1701
1704
|
if (!ctl || !ed) return;
|
|
1702
1705
|
ctl.execute(item);
|
|
1703
|
-
|
|
1704
|
-
ed.view.focus();
|
|
1705
|
-
});
|
|
1706
|
+
refocusEditorAfterCommand(ed.view);
|
|
1706
1707
|
};
|
|
1707
1708
|
const onMenuKeyDown = (e) => {
|
|
1708
1709
|
const ctl = controller.value;
|