@abraca/nuxt 2.10.0 → 2.13.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/dist/module.d.mts +14 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -0
- package/dist/runtime/assets/editor.css +1 -1
- package/dist/runtime/components/AConnectionBadge.d.vue.ts +29 -0
- package/dist/runtime/components/AConnectionBadge.vue +79 -0
- package/dist/runtime/components/AConnectionBadge.vue.d.ts +29 -0
- package/dist/runtime/components/ADocPickerModal.d.vue.ts +31 -0
- package/dist/runtime/components/ADocPickerModal.vue +191 -0
- package/dist/runtime/components/ADocPickerModal.vue.d.ts +31 -0
- package/dist/runtime/components/ADocumentTree.vue +65 -0
- package/dist/runtime/components/AEditor.d.vue.ts +19 -12
- package/dist/runtime/components/AEditor.vue +243 -165
- package/dist/runtime/components/AEditor.vue.d.ts +19 -12
- package/dist/runtime/components/AEncryptionModePicker.d.vue.ts +33 -0
- package/dist/runtime/components/AEncryptionModePicker.vue +211 -0
- package/dist/runtime/components/AEncryptionModePicker.vue.d.ts +33 -0
- package/dist/runtime/components/AModalShell.d.vue.ts +48 -0
- package/dist/runtime/components/AModalShell.vue +105 -0
- package/dist/runtime/components/AModalShell.vue.d.ts +48 -0
- package/dist/runtime/components/ANodePanel.d.vue.ts +17 -7
- package/dist/runtime/components/ANodePanel.vue +550 -451
- package/dist/runtime/components/ANodePanel.vue.d.ts +17 -7
- package/dist/runtime/components/ANodePanelHeader.d.vue.ts +20 -10
- package/dist/runtime/components/ANodePanelHeader.vue +17 -3
- package/dist/runtime/components/ANodePanelHeader.vue.d.ts +20 -10
- package/dist/runtime/components/ANodeSettingsPanel.d.vue.ts +2 -0
- package/dist/runtime/components/ANodeSettingsPanel.vue +21 -1
- package/dist/runtime/components/ANodeSettingsPanel.vue.d.ts +2 -0
- package/dist/runtime/components/ASnapshotPreviewModal.d.vue.ts +33 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue +430 -0
- package/dist/runtime/components/ASnapshotPreviewModal.vue.d.ts +33 -0
- package/dist/runtime/components/ATagsEditor.d.vue.ts +19 -0
- package/dist/runtime/components/ATagsEditor.vue +60 -0
- package/dist/runtime/components/ATagsEditor.vue.d.ts +19 -0
- package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
- package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
- package/dist/runtime/components/chat/AChatInput.d.vue.ts +11 -6
- package/dist/runtime/components/chat/AChatInput.vue +33 -2
- package/dist/runtime/components/chat/AChatInput.vue.d.ts +11 -6
- package/dist/runtime/components/chat/AChatList.d.vue.ts +12 -0
- package/dist/runtime/components/chat/AChatList.vue +76 -32
- package/dist/runtime/components/chat/AChatList.vue.d.ts +12 -0
- package/dist/runtime/components/chat/AChatMessages.d.vue.ts +4 -0
- package/dist/runtime/components/chat/AChatMessages.vue +57 -4
- package/dist/runtime/components/chat/AChatMessages.vue.d.ts +4 -0
- package/dist/runtime/components/chat/AChatPanel.d.vue.ts +6 -2
- package/dist/runtime/components/chat/AChatPanel.vue +17 -1
- package/dist/runtime/components/chat/AChatPanel.vue.d.ts +6 -2
- package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -1
- package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
- package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
- package/dist/runtime/components/editor/ALocationPickerPopover.vue +28 -7
- package/dist/runtime/components/registry/APluginDetail.d.vue.ts +2 -2
- package/dist/runtime/components/registry/APluginDetail.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/AChartRenderer.client.d.vue.ts +17 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue +622 -0
- package/dist/runtime/components/renderers/AChartRenderer.client.vue.d.ts +17 -0
- package/dist/runtime/components/renderers/AGraphRenderer.vue +64 -15
- package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/calendar/ACalendarToolbar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/media/MediaTransportBar.vue.d.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.d.vue.ts +2 -2
- package/dist/runtime/components/renderers/sheets/ASheetsGrid.vue.d.ts +2 -2
- package/dist/runtime/components/settings/ASettingsAppearancePanel.d.vue.ts +3 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue +67 -0
- package/dist/runtime/components/settings/ASettingsAppearancePanel.vue.d.ts +3 -0
- package/dist/runtime/components/settings/ASettingsGroup.d.vue.ts +24 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue +31 -0
- package/dist/runtime/components/settings/ASettingsGroup.vue.d.ts +24 -0
- package/dist/runtime/components/settings/ASettingsModal.vue +84 -53
- package/dist/runtime/components/settings/ASettingsPlaceholder.d.vue.ts +20 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue +32 -0
- package/dist/runtime/components/settings/ASettingsPlaceholder.vue.d.ts +20 -0
- package/dist/runtime/components/settings/ASettingsRow.d.vue.ts +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue +34 -0
- package/dist/runtime/components/settings/ASettingsRow.vue.d.ts +34 -0
- package/dist/runtime/components/settings/sections.d.ts +37 -0
- package/dist/runtime/components/settings/sections.js +45 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +6 -0
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +75 -3
- package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +6 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.d.vue.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue +253 -0
- package/dist/runtime/components/shell/ADocPanelServerSettings.vue.d.ts +17 -0
- package/dist/runtime/components/shell/ADocPanelSettings.d.vue.ts +2 -0
- package/dist/runtime/components/shell/ADocPanelSettings.vue +15 -4
- package/dist/runtime/components/shell/ADocPanelSettings.vue.d.ts +2 -0
- package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
- package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
- package/dist/runtime/composables/useChat.d.ts +22 -1
- package/dist/runtime/composables/useChat.js +79 -8
- package/dist/runtime/composables/useDocBreadcrumb.d.ts +17 -2
- package/dist/runtime/composables/useDocBreadcrumb.js +17 -3
- package/dist/runtime/composables/useDocSnapshots.d.ts +2 -1
- package/dist/runtime/composables/useDocSnapshots.js +5 -0
- package/dist/runtime/composables/useEditor.d.ts +1 -1
- package/dist/runtime/composables/useEditor.js +120 -0
- package/dist/runtime/composables/useEditorToolbar.d.ts +12 -4
- package/dist/runtime/composables/useEditorToolbar.js +78 -56
- package/dist/runtime/composables/useNodeContextMenu.d.ts +14 -0
- package/dist/runtime/composables/useNodeContextMenu.js +59 -1
- package/dist/runtime/composables/useSettingsModal.d.ts +1 -1
- package/dist/runtime/composables/useSwipeGesture.d.ts +48 -0
- package/dist/runtime/composables/useSwipeGesture.js +140 -0
- package/dist/runtime/extensions/document-header.js +16 -6
- package/dist/runtime/extensions/document-meta.js +344 -19
- package/dist/runtime/extensions/meta-field.js +42 -0
- package/dist/runtime/extensions/views/DocumentMetaView.vue +33 -7
- package/dist/runtime/extensions/views/FieldView.vue +51 -19
- package/dist/runtime/extensions/views/MetaFieldView.vue +30 -4
- package/dist/runtime/locale.d.ts +8 -0
- package/dist/runtime/locale.js +9 -1
- package/dist/runtime/middleware/abracadabra-auth.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.d.ts +1 -1
- package/dist/runtime/plugin-abracadabra.client.js +12 -2
- package/dist/runtime/plugin-abracadabra.server.d.ts +1 -1
- package/dist/runtime/plugin-shared-globals.client.d.ts +1 -1
- package/dist/runtime/utils/chatContent.d.ts +20 -2
- package/dist/runtime/utils/chatContent.js +20 -1
- package/dist/runtime/utils/docTypes.js +43 -0
- package/dist/runtime/utils/titleSync.d.ts +130 -0
- package/dist/runtime/utils/titleSync.js +53 -0
- package/package.json +11 -4
|
@@ -87,6 +87,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
87
87
|
"delete-snapshot": (version: number) => any;
|
|
88
88
|
"restore-snapshot": (version: number) => any;
|
|
89
89
|
"fork-snapshot": (version: number) => any;
|
|
90
|
+
"preview-snapshot": (version: number) => any;
|
|
90
91
|
"load-more-snapshots": () => any;
|
|
91
92
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
92
93
|
"onUpdate-meta"?: ((patch: Partial<DocPageMeta>) => any) | undefined;
|
|
@@ -105,6 +106,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
105
106
|
"onDelete-snapshot"?: ((version: number) => any) | undefined;
|
|
106
107
|
"onRestore-snapshot"?: ((version: number) => any) | undefined;
|
|
107
108
|
"onFork-snapshot"?: ((version: number) => any) | undefined;
|
|
109
|
+
"onPreview-snapshot"?: ((version: number) => any) | undefined;
|
|
108
110
|
"onLoad-more-snapshots"?: (() => any) | undefined;
|
|
109
111
|
}>, {
|
|
110
112
|
snapshots: SnapshotMeta[];
|
|
@@ -28,7 +28,7 @@ const props = defineProps({
|
|
|
28
28
|
pendingSnapshotVersion: { type: [Number, null], required: false, default: null },
|
|
29
29
|
creatingSnapshot: { type: Boolean, required: false, default: false }
|
|
30
30
|
});
|
|
31
|
-
const emit = defineEmits(["grant-permission", "change-role", "revoke-permission", "create-invite", "sync-doc", "open-encryption", "user-context-menu", "update-meta", "create-snapshot", "delete-snapshot", "restore-snapshot", "fork-snapshot", "load-more-snapshots"]);
|
|
31
|
+
const emit = defineEmits(["grant-permission", "change-role", "revoke-permission", "create-invite", "sync-doc", "open-encryption", "user-context-menu", "update-meta", "create-snapshot", "delete-snapshot", "restore-snapshot", "fork-snapshot", "preview-snapshot", "load-more-snapshots"]);
|
|
32
32
|
const grantUserId = ref("");
|
|
33
33
|
const grantRole = ref("editor");
|
|
34
34
|
const showManualKeyInput = ref(false);
|
|
@@ -114,6 +114,13 @@ function runSnapConfirm() {
|
|
|
114
114
|
else emit("restore-snapshot", c.version);
|
|
115
115
|
}
|
|
116
116
|
function snapshotMenu(version) {
|
|
117
|
+
const view = [
|
|
118
|
+
{
|
|
119
|
+
label: "View / compare",
|
|
120
|
+
icon: "i-lucide-eye",
|
|
121
|
+
onSelect: () => emit("preview-snapshot", version)
|
|
122
|
+
}
|
|
123
|
+
];
|
|
117
124
|
const manage = [
|
|
118
125
|
{
|
|
119
126
|
label: "Restore",
|
|
@@ -134,7 +141,7 @@ function snapshotMenu(version) {
|
|
|
134
141
|
onSelect: () => askSnapDelete(version)
|
|
135
142
|
}
|
|
136
143
|
];
|
|
137
|
-
return props.isOwner ? [manage, destructive] : [manage];
|
|
144
|
+
return props.isOwner ? [view, manage, destructive] : [view, manage];
|
|
138
145
|
}
|
|
139
146
|
function triggerColor(trigger) {
|
|
140
147
|
switch (trigger) {
|
|
@@ -728,7 +735,11 @@ function patchMeta(key, value) {
|
|
|
728
735
|
:key="snap.version"
|
|
729
736
|
class="flex items-center gap-2.5 p-3 rounded-lg bg-(--ui-bg-elevated)"
|
|
730
737
|
>
|
|
731
|
-
<
|
|
738
|
+
<button
|
|
739
|
+
type="button"
|
|
740
|
+
class="flex-1 min-w-0 text-left cursor-pointer"
|
|
741
|
+
@click="emit('preview-snapshot', snap.version)"
|
|
742
|
+
>
|
|
732
743
|
<div class="flex items-center gap-2">
|
|
733
744
|
<span class="text-sm font-medium text-(--ui-text-highlighted) tabular-nums">
|
|
734
745
|
v{{ snap.version }}
|
|
@@ -749,7 +760,7 @@ function patchMeta(key, value) {
|
|
|
749
760
|
<p class="text-xs text-(--ui-text-dimmed) mt-0.5">
|
|
750
761
|
{{ formatSnapTime(snap.created_at) }} · {{ formatSnapSize(snap.size_bytes) }}
|
|
751
762
|
</p>
|
|
752
|
-
</
|
|
763
|
+
</button>
|
|
753
764
|
<UDropdownMenu
|
|
754
765
|
:items="snapshotMenu(snap.version)"
|
|
755
766
|
:content="{ align: 'end' }"
|
|
@@ -87,6 +87,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
87
87
|
"delete-snapshot": (version: number) => any;
|
|
88
88
|
"restore-snapshot": (version: number) => any;
|
|
89
89
|
"fork-snapshot": (version: number) => any;
|
|
90
|
+
"preview-snapshot": (version: number) => any;
|
|
90
91
|
"load-more-snapshots": () => any;
|
|
91
92
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
92
93
|
"onUpdate-meta"?: ((patch: Partial<DocPageMeta>) => any) | undefined;
|
|
@@ -105,6 +106,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
105
106
|
"onDelete-snapshot"?: ((version: number) => any) | undefined;
|
|
106
107
|
"onRestore-snapshot"?: ((version: number) => any) | undefined;
|
|
107
108
|
"onFork-snapshot"?: ((version: number) => any) | undefined;
|
|
109
|
+
"onPreview-snapshot"?: ((version: number) => any) | undefined;
|
|
108
110
|
"onLoad-more-snapshots"?: (() => any) | undefined;
|
|
109
111
|
}>, {
|
|
110
112
|
snapshots: SnapshotMeta[];
|
|
@@ -37,8 +37,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
37
37
|
name: string;
|
|
38
38
|
online: boolean | null;
|
|
39
39
|
currentDocId: string | null;
|
|
40
|
-
avatarStyle: string;
|
|
41
40
|
isSelf: boolean;
|
|
41
|
+
avatarStyle: string;
|
|
42
42
|
isFollowing: boolean;
|
|
43
43
|
showFollow: boolean;
|
|
44
44
|
currentDocLabel: string | null;
|
|
@@ -37,8 +37,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
37
37
|
name: string;
|
|
38
38
|
online: boolean | null;
|
|
39
39
|
currentDocId: string | null;
|
|
40
|
-
avatarStyle: string;
|
|
41
40
|
isSelf: boolean;
|
|
41
|
+
avatarStyle: string;
|
|
42
42
|
isFollowing: boolean;
|
|
43
43
|
showFollow: boolean;
|
|
44
44
|
currentDocLabel: string | null;
|
|
@@ -16,6 +16,8 @@ export interface ChatMessage {
|
|
|
16
16
|
senderName: string;
|
|
17
17
|
content: string;
|
|
18
18
|
createdAt: number;
|
|
19
|
+
/** Id of the message this one replies to, if any (threaded reply). */
|
|
20
|
+
replyTo?: string;
|
|
19
21
|
}
|
|
20
22
|
export interface ChatChannel {
|
|
21
23
|
id: string;
|
|
@@ -25,6 +27,12 @@ export interface ChatChannel {
|
|
|
25
27
|
unreadCount: number;
|
|
26
28
|
}
|
|
27
29
|
export declare function buildDmChannelId(a: string, b: string): string;
|
|
30
|
+
declare function setMuted(id: string, on: boolean): void;
|
|
31
|
+
declare function setPinned(id: string, on: boolean): void;
|
|
32
|
+
declare function setHidden(id: string, on: boolean): void;
|
|
33
|
+
declare function isMuted(id: string): boolean;
|
|
34
|
+
declare function isPinned(id: string): boolean;
|
|
35
|
+
declare function isHidden(id: string): boolean;
|
|
28
36
|
declare let _publicKeyB64: import("vue").Ref<string, string>;
|
|
29
37
|
declare let _userName: import("vue").Ref<string, string>;
|
|
30
38
|
export declare function _initChat(publicKeyB64Ref: typeof _publicKeyB64, userNameRef: typeof _userName): void;
|
|
@@ -53,6 +61,7 @@ declare function sendTyping(channelId: string): void;
|
|
|
53
61
|
declare function setActiveChannel(channelId: string | null): void;
|
|
54
62
|
export declare function useChat(): {
|
|
55
63
|
channels: import("vue").Ref<Record<string, ChatChannel>, Record<string, ChatChannel>>;
|
|
64
|
+
channelList: import("vue").ComputedRef<ChatChannel[]>;
|
|
56
65
|
activeChannel: import("vue").Ref<string | null, string | null>;
|
|
57
66
|
messagesByChannel: import("vue").Ref<Record<string, ChatMessage[]>, Record<string, ChatMessage[]>>;
|
|
58
67
|
typingByChannel: import("vue").Ref<Record<string, Map<string, string>>, Record<string, Map<string, string>>>;
|
|
@@ -62,13 +71,25 @@ export declare function useChat(): {
|
|
|
62
71
|
sendTyping: typeof sendTyping;
|
|
63
72
|
setActiveChannel: typeof setActiveChannel;
|
|
64
73
|
buildDmChannelId: typeof buildDmChannelId;
|
|
74
|
+
mutedChannels: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
75
|
+
pinnedChannels: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
76
|
+
hiddenChannels: import("vue").Ref<Set<string> & Omit<Set<string>, keyof Set<any>>, Set<string> | (Set<string> & Omit<Set<string>, keyof Set<any>>)>;
|
|
77
|
+
setMuted: typeof setMuted;
|
|
78
|
+
setPinned: typeof setPinned;
|
|
79
|
+
setHidden: typeof setHidden;
|
|
80
|
+
isMuted: typeof isMuted;
|
|
81
|
+
isPinned: typeof isPinned;
|
|
82
|
+
isHidden: typeof isHidden;
|
|
65
83
|
};
|
|
66
84
|
export declare function useChatChannel(channelId: string): {
|
|
67
85
|
messages: import("vue").ComputedRef<ChatMessage[]>;
|
|
68
86
|
channel: import("vue").ComputedRef<ChatChannel | undefined>;
|
|
69
87
|
typingUsers: import("vue").ComputedRef<string[]>;
|
|
70
88
|
unreadCount: import("vue").ComputedRef<number>;
|
|
71
|
-
send: (content: string
|
|
89
|
+
send: (content: string, opts?: {
|
|
90
|
+
mentions?: string[];
|
|
91
|
+
replyTo?: string;
|
|
92
|
+
}) => void;
|
|
72
93
|
loadHistory: (opts?: {
|
|
73
94
|
before?: number;
|
|
74
95
|
limit?: number;
|
|
@@ -33,6 +33,58 @@ const channels = ref({});
|
|
|
33
33
|
const typingByChannel = ref({});
|
|
34
34
|
const activeChannel = ref(null);
|
|
35
35
|
const typingTimers = /* @__PURE__ */ new Map();
|
|
36
|
+
function _loadIdSet(key) {
|
|
37
|
+
if (typeof localStorage === "undefined") return /* @__PURE__ */ new Set();
|
|
38
|
+
try {
|
|
39
|
+
const raw = localStorage.getItem(key);
|
|
40
|
+
return raw ? new Set(JSON.parse(raw)) : /* @__PURE__ */ new Set();
|
|
41
|
+
} catch {
|
|
42
|
+
return /* @__PURE__ */ new Set();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function _saveIdSet(key, set) {
|
|
46
|
+
if (typeof localStorage === "undefined") return;
|
|
47
|
+
try {
|
|
48
|
+
localStorage.setItem(key, JSON.stringify([...set]));
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const mutedChannels = ref(_loadIdSet("abracadabra_chat_muted"));
|
|
53
|
+
const pinnedChannels = ref(_loadIdSet("abracadabra_chat_pinned"));
|
|
54
|
+
const hiddenChannels = ref(_loadIdSet("abracadabra_chat_hidden"));
|
|
55
|
+
function _setPref(ref_, key, id, on) {
|
|
56
|
+
const next = new Set(ref_.value);
|
|
57
|
+
if (on) next.add(id);
|
|
58
|
+
else next.delete(id);
|
|
59
|
+
ref_.value = next;
|
|
60
|
+
_saveIdSet(key, next);
|
|
61
|
+
}
|
|
62
|
+
function setMuted(id, on) {
|
|
63
|
+
_setPref(mutedChannels, "abracadabra_chat_muted", id, on);
|
|
64
|
+
}
|
|
65
|
+
function setPinned(id, on) {
|
|
66
|
+
_setPref(pinnedChannels, "abracadabra_chat_pinned", id, on);
|
|
67
|
+
}
|
|
68
|
+
function setHidden(id, on) {
|
|
69
|
+
_setPref(hiddenChannels, "abracadabra_chat_hidden", id, on);
|
|
70
|
+
}
|
|
71
|
+
function isMuted(id) {
|
|
72
|
+
return mutedChannels.value.has(id);
|
|
73
|
+
}
|
|
74
|
+
function isPinned(id) {
|
|
75
|
+
return pinnedChannels.value.has(id);
|
|
76
|
+
}
|
|
77
|
+
function isHidden(id) {
|
|
78
|
+
return hiddenChannels.value.has(id);
|
|
79
|
+
}
|
|
80
|
+
const channelList = computed(
|
|
81
|
+
() => Object.values(channels.value).filter((c) => !hiddenChannels.value.has(c.id)).sort((a, b) => {
|
|
82
|
+
const pa = pinnedChannels.value.has(a.id) ? 1 : 0;
|
|
83
|
+
const pb = pinnedChannels.value.has(b.id) ? 1 : 0;
|
|
84
|
+
if (pa !== pb) return pb - pa;
|
|
85
|
+
return (b.lastMessage?.createdAt ?? 0) - (a.lastMessage?.createdAt ?? 0);
|
|
86
|
+
})
|
|
87
|
+
);
|
|
36
88
|
let _publicKeyB64 = ref("");
|
|
37
89
|
let _userName = ref("");
|
|
38
90
|
export function _initChat(publicKeyB64Ref, userNameRef) {
|
|
@@ -112,12 +164,13 @@ function addMessage(msg) {
|
|
|
112
164
|
if (chan) {
|
|
113
165
|
const isActive = activeChannel.value === msg.channel;
|
|
114
166
|
const isOwn = msg.senderId === _publicKeyB64.value;
|
|
167
|
+
const suppress = isActive || isOwn || mutedChannels.value.has(msg.channel);
|
|
115
168
|
channels.value = {
|
|
116
169
|
...channels.value,
|
|
117
170
|
[msg.channel]: {
|
|
118
171
|
...chan,
|
|
119
172
|
lastMessage: msg,
|
|
120
|
-
unreadCount:
|
|
173
|
+
unreadCount: suppress ? chan.unreadCount : chan.unreadCount + 1
|
|
121
174
|
}
|
|
122
175
|
};
|
|
123
176
|
}
|
|
@@ -148,7 +201,8 @@ export function _handleStatelessChat(payload) {
|
|
|
148
201
|
// as "chat is broken / messages aren't syncing".
|
|
149
202
|
senderName: rec.sender_name ?? resolveSenderName(senderId),
|
|
150
203
|
content: rec.content ?? "",
|
|
151
|
-
createdAt: tsMs
|
|
204
|
+
createdAt: tsMs,
|
|
205
|
+
...rec.reply_to ? { replyTo: rec.reply_to } : {}
|
|
152
206
|
};
|
|
153
207
|
ensureChannel(msg.channel, resolveChannelLabel(msg.channel, msg.senderName, msg.senderId));
|
|
154
208
|
addMessage(msg);
|
|
@@ -234,7 +288,8 @@ function sendMessage(channelId, content, opts) {
|
|
|
234
288
|
senderId: _publicKeyB64.value,
|
|
235
289
|
senderName: userName?.value ?? _userName.value,
|
|
236
290
|
content: trimmed,
|
|
237
|
-
createdAt: Date.now()
|
|
291
|
+
createdAt: Date.now(),
|
|
292
|
+
...opts?.replyTo ? { replyTo: opts.replyTo } : {}
|
|
238
293
|
});
|
|
239
294
|
provider.value.sendStateless(JSON.stringify({
|
|
240
295
|
type: "messages:send",
|
|
@@ -284,7 +339,9 @@ async function _attachPeriodProvider(channel, rootProv, periodId) {
|
|
|
284
339
|
senderId: f.senderId,
|
|
285
340
|
senderName: "",
|
|
286
341
|
content,
|
|
287
|
-
createdAt: f.createdAt
|
|
342
|
+
createdAt: f.createdAt,
|
|
343
|
+
// Best-effort: the SDK's folded record may carry reply linkage.
|
|
344
|
+
...f.reply_to || f.replyTo ? { replyTo: f.reply_to ?? f.replyTo } : {}
|
|
288
345
|
});
|
|
289
346
|
}
|
|
290
347
|
};
|
|
@@ -360,11 +417,15 @@ function setActiveChannel(channelId) {
|
|
|
360
417
|
}
|
|
361
418
|
}
|
|
362
419
|
const totalUnreadCount = computed(
|
|
363
|
-
() => Object.values(channels.value).reduce(
|
|
420
|
+
() => Object.values(channels.value).reduce(
|
|
421
|
+
(sum, ch) => sum + (mutedChannels.value.has(ch.id) ? 0 : ch.unreadCount),
|
|
422
|
+
0
|
|
423
|
+
)
|
|
364
424
|
);
|
|
365
425
|
export function useChat() {
|
|
366
426
|
return {
|
|
367
427
|
channels,
|
|
428
|
+
channelList,
|
|
368
429
|
activeChannel,
|
|
369
430
|
messagesByChannel,
|
|
370
431
|
typingByChannel,
|
|
@@ -373,7 +434,17 @@ export function useChat() {
|
|
|
373
434
|
fetchHistory,
|
|
374
435
|
sendTyping,
|
|
375
436
|
setActiveChannel,
|
|
376
|
-
buildDmChannelId
|
|
437
|
+
buildDmChannelId,
|
|
438
|
+
// Channel preferences
|
|
439
|
+
mutedChannels,
|
|
440
|
+
pinnedChannels,
|
|
441
|
+
hiddenChannels,
|
|
442
|
+
setMuted,
|
|
443
|
+
setPinned,
|
|
444
|
+
setHidden,
|
|
445
|
+
isMuted,
|
|
446
|
+
isPinned,
|
|
447
|
+
isHidden
|
|
377
448
|
};
|
|
378
449
|
}
|
|
379
450
|
export function useChatChannel(channelId) {
|
|
@@ -392,8 +463,8 @@ export function useChatChannel(channelId) {
|
|
|
392
463
|
stop();
|
|
393
464
|
});
|
|
394
465
|
}
|
|
395
|
-
function send(content) {
|
|
396
|
-
sendMessage(key, content);
|
|
466
|
+
function send(content, opts) {
|
|
467
|
+
sendMessage(key, content, opts);
|
|
397
468
|
}
|
|
398
469
|
function loadHistory(opts) {
|
|
399
470
|
fetchHistory(key, opts);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Caps depth at `maxDepth` (default 8) to handle malformed cycles
|
|
7
7
|
* defensively. The last item is the current doc and has no `to`.
|
|
8
8
|
*/
|
|
9
|
-
import { type ComputedRef, type
|
|
9
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
10
10
|
export interface DocBreadcrumbItem {
|
|
11
11
|
id: string;
|
|
12
12
|
label: string;
|
|
@@ -14,8 +14,23 @@ export interface DocBreadcrumbItem {
|
|
|
14
14
|
/** Navigation target — undefined for the current doc */
|
|
15
15
|
to?: string;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The trail split for single-line rendering: when the full trail is longer
|
|
19
|
+
* than `maxVisible`, the middle collapses into `hidden` (shown behind a "…"
|
|
20
|
+
* overflow menu), keeping the first crumb (`head`) and the last
|
|
21
|
+
* `maxVisible - 2` crumbs (`tail`). `overflowed` is false when no collapse is
|
|
22
|
+
* needed — then `head` holds the whole trail and `hidden`/`tail` are empty.
|
|
23
|
+
*/
|
|
24
|
+
export interface DocBreadcrumbCollapsed {
|
|
25
|
+
head: DocBreadcrumbItem[];
|
|
26
|
+
hidden: DocBreadcrumbItem[];
|
|
27
|
+
tail: DocBreadcrumbItem[];
|
|
28
|
+
overflowed: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare function useDocBreadcrumb(docId: MaybeRefOrGetter<string | null | undefined>, options?: {
|
|
18
31
|
maxDepth?: number;
|
|
32
|
+
maxVisible?: number;
|
|
19
33
|
}): {
|
|
20
34
|
items: ComputedRef<DocBreadcrumbItem[]>;
|
|
35
|
+
collapsed: ComputedRef<DocBreadcrumbCollapsed>;
|
|
21
36
|
};
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { computed,
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
2
|
import { resolveDocType } from "../utils/docTypes.js";
|
|
3
3
|
import { useRuntimeConfig } from "#imports";
|
|
4
4
|
import { useDocTree } from "./useDocTree.js";
|
|
5
5
|
export function useDocBreadcrumb(docId, options = {}) {
|
|
6
6
|
const maxDepth = options.maxDepth ?? 8;
|
|
7
|
+
const maxVisible = options.maxVisible ?? 0;
|
|
7
8
|
const config = useRuntimeConfig();
|
|
8
9
|
const docBasePath = config.public?.abracadabra?.docBasePath ?? "/doc";
|
|
9
10
|
const tree = useDocTree();
|
|
10
11
|
const items = computed(() => {
|
|
11
|
-
const startId =
|
|
12
|
+
const startId = toValue(docId);
|
|
12
13
|
if (!startId) return [];
|
|
13
14
|
const trail = [];
|
|
14
15
|
let id = startId;
|
|
@@ -29,5 +30,18 @@ export function useDocBreadcrumb(docId, options = {}) {
|
|
|
29
30
|
}
|
|
30
31
|
return trail;
|
|
31
32
|
});
|
|
32
|
-
|
|
33
|
+
const collapsed = computed(() => {
|
|
34
|
+
const all = items.value;
|
|
35
|
+
if (maxVisible <= 0 || all.length <= maxVisible) {
|
|
36
|
+
return { head: all, hidden: [], tail: [], overflowed: false };
|
|
37
|
+
}
|
|
38
|
+
const tailCount = Math.max(1, maxVisible - 2);
|
|
39
|
+
return {
|
|
40
|
+
head: all.slice(0, 1),
|
|
41
|
+
hidden: all.slice(1, all.length - tailCount),
|
|
42
|
+
tail: all.slice(all.length - tailCount),
|
|
43
|
+
overflowed: true
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
return { items, collapsed };
|
|
33
47
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* onMounted(() => snaps.fetchList())
|
|
20
20
|
*/
|
|
21
21
|
import { type ComputedRef, type InjectionKey, type Ref } from 'vue';
|
|
22
|
-
import type { SnapshotMeta } from '@abraca/dabra';
|
|
22
|
+
import type { SnapshotData, SnapshotMeta } from '@abraca/dabra';
|
|
23
23
|
import type { AbracadabraLocale } from '../locale.js';
|
|
24
24
|
export type DocSnapshotsCtx = ReturnType<typeof useDocSnapshots>;
|
|
25
25
|
export declare const DOC_SNAPSHOTS_KEY: InjectionKey<DocSnapshotsCtx>;
|
|
@@ -72,6 +72,7 @@ export declare function useDocSnapshots(docId: Ref<string> | ComputedRef<string>
|
|
|
72
72
|
pending: Ref<Record<number, "delete" | "restore" | "fork" | undefined>, Record<number, "delete" | "restore" | "fork" | undefined>>;
|
|
73
73
|
fetchList: () => Promise<void>;
|
|
74
74
|
loadMore: () => Promise<void>;
|
|
75
|
+
getSnapshot: (version: number) => Promise<SnapshotData | null>;
|
|
75
76
|
create: (label?: string) => Promise<void>;
|
|
76
77
|
remove: (version: number) => Promise<void>;
|
|
77
78
|
restore: (version: number) => Promise<void>;
|
|
@@ -120,6 +120,10 @@ export function useDocSnapshots(docId, overrides) {
|
|
|
120
120
|
loading.value = false;
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
+
async function getSnapshot(version) {
|
|
124
|
+
if (!client.value || !docId.value) return null;
|
|
125
|
+
return client.value.getSnapshot(docId.value, version, { include: "files" });
|
|
126
|
+
}
|
|
123
127
|
async function create(label) {
|
|
124
128
|
if (!client.value || !docId.value) return;
|
|
125
129
|
creating.value = true;
|
|
@@ -226,6 +230,7 @@ export function useDocSnapshots(docId, overrides) {
|
|
|
226
230
|
// Actions
|
|
227
231
|
fetchList,
|
|
228
232
|
loadMore,
|
|
233
|
+
getSnapshot,
|
|
229
234
|
create,
|
|
230
235
|
remove,
|
|
231
236
|
restore,
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Ported from cou-sh/app/composables/useEditorCollaboration.ts.
|
|
16
16
|
*/
|
|
17
17
|
import { type Ref, type ShallowRef } from 'vue';
|
|
18
|
-
import type
|
|
18
|
+
import { type Extensions } from '@tiptap/core';
|
|
19
19
|
import type { CollaborationUser } from '../types.js';
|
|
20
20
|
export { type CollaborationUser } from '../types.js';
|
|
21
21
|
export interface UseEditorOptions {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ref, shallowRef, watch, onUnmounted } from "vue";
|
|
2
|
+
import { Extension } from "@tiptap/core";
|
|
2
3
|
import { XmlElement } from "yjs";
|
|
3
4
|
import { useNuxtApp } from "#imports";
|
|
4
5
|
export function useEditor(options) {
|
|
@@ -7,10 +8,21 @@ export function useEditor(options) {
|
|
|
7
8
|
const connectedUsers = ref([]);
|
|
8
9
|
const extensions = shallowRef([]);
|
|
9
10
|
const ready = ref(false);
|
|
11
|
+
const activeColors = ref(/* @__PURE__ */ new Set());
|
|
12
|
+
const colorTimeouts = /* @__PURE__ */ new Map();
|
|
13
|
+
const CARET_ACTIVITY_TIMEOUT = 3e3;
|
|
10
14
|
let cleanup = null;
|
|
15
|
+
let cursorBroadcastTimer = null;
|
|
11
16
|
watch(childProvider, async (prov) => {
|
|
12
17
|
cleanup?.();
|
|
13
18
|
cleanup = null;
|
|
19
|
+
if (cursorBroadcastTimer) {
|
|
20
|
+
clearTimeout(cursorBroadcastTimer);
|
|
21
|
+
cursorBroadcastTimer = null;
|
|
22
|
+
}
|
|
23
|
+
colorTimeouts.forEach((t) => clearTimeout(t));
|
|
24
|
+
colorTimeouts.clear();
|
|
25
|
+
activeColors.value = /* @__PURE__ */ new Set();
|
|
14
26
|
if (!prov) {
|
|
15
27
|
ready.value = false;
|
|
16
28
|
extensions.value = [];
|
|
@@ -34,6 +46,23 @@ export function useEditor(options) {
|
|
|
34
46
|
CollaborationCaret.configure({
|
|
35
47
|
provider: prov,
|
|
36
48
|
user,
|
|
49
|
+
// Custom caret element: a thin coloured bar with a floating name label.
|
|
50
|
+
// Visibility is activity-gated — the `.is-active` class (added here when
|
|
51
|
+
// the author is in activeColors, and toggled live by the watcher below)
|
|
52
|
+
// is what makes the caret visible (editor.css defaults it to opacity:0).
|
|
53
|
+
render: (u) => {
|
|
54
|
+
const cursor = document.createElement("span");
|
|
55
|
+
cursor.classList.add("collaboration-carets__caret");
|
|
56
|
+
cursor.setAttribute("style", `border-color: ${u.color}`);
|
|
57
|
+
cursor.dataset.userColor = u.color;
|
|
58
|
+
const label = document.createElement("div");
|
|
59
|
+
label.classList.add("collaboration-carets__label");
|
|
60
|
+
label.setAttribute("style", `background-color: ${u.color}`);
|
|
61
|
+
label.insertBefore(document.createTextNode(u.name), null);
|
|
62
|
+
cursor.insertBefore(label, null);
|
|
63
|
+
if (activeColors.value.has(u.color)) cursor.classList.add("is-active");
|
|
64
|
+
return cursor;
|
|
65
|
+
},
|
|
37
66
|
selectionRender: (u) => {
|
|
38
67
|
const color = u.color || "#999";
|
|
39
68
|
const selectionColor = color.startsWith("hsl") ? color.replace("hsl", "hsla").replace(")", ", 0.4)") : `${color}66`;
|
|
@@ -43,6 +72,20 @@ export function useEditor(options) {
|
|
|
43
72
|
};
|
|
44
73
|
}
|
|
45
74
|
}),
|
|
75
|
+
// Broadcast the local cursor position to child awareness (throttled,
|
|
76
|
+
// 150ms trailing) so presence/follow consumers can track the caret
|
|
77
|
+
// without coupling to the CollaborationCaret extension internals.
|
|
78
|
+
Extension.create({
|
|
79
|
+
name: "cursor-position-broadcast",
|
|
80
|
+
onSelectionUpdate() {
|
|
81
|
+
const { from, to } = this.editor.state.selection;
|
|
82
|
+
if (cursorBroadcastTimer) clearTimeout(cursorBroadcastTimer);
|
|
83
|
+
cursorBroadcastTimer = setTimeout(() => {
|
|
84
|
+
cursorBroadcastTimer = null;
|
|
85
|
+
prov.awareness?.setLocalStateField("cursorPos", { from, to });
|
|
86
|
+
}, 150);
|
|
87
|
+
}
|
|
88
|
+
}),
|
|
46
89
|
...extraExtensions
|
|
47
90
|
];
|
|
48
91
|
const ydoc = prov.document;
|
|
@@ -92,6 +135,13 @@ export function useEditor(options) {
|
|
|
92
135
|
dedupeDocumentMeta();
|
|
93
136
|
ensureDocumentMeta();
|
|
94
137
|
}
|
|
138
|
+
const onProviderSynced = () => {
|
|
139
|
+
dedupeHeaders();
|
|
140
|
+
dedupeDocumentMeta();
|
|
141
|
+
ensureDocumentMeta();
|
|
142
|
+
};
|
|
143
|
+
prov.on?.("synced", onProviderSynced);
|
|
144
|
+
if (prov.isSynced) Promise.resolve().then(onProviderSynced);
|
|
95
145
|
ready.value = true;
|
|
96
146
|
const updateUsers = () => {
|
|
97
147
|
const states = prov.awareness?.getStates() ?? /* @__PURE__ */ new Map();
|
|
@@ -104,14 +154,84 @@ export function useEditor(options) {
|
|
|
104
154
|
});
|
|
105
155
|
connectedUsers.value = users;
|
|
106
156
|
};
|
|
157
|
+
const markActive = (color) => {
|
|
158
|
+
activeColors.value.add(color);
|
|
159
|
+
activeColors.value = new Set(activeColors.value);
|
|
160
|
+
if (colorTimeouts.has(color)) clearTimeout(colorTimeouts.get(color));
|
|
161
|
+
colorTimeouts.set(color, setTimeout(() => {
|
|
162
|
+
activeColors.value.delete(color);
|
|
163
|
+
activeColors.value = new Set(activeColors.value);
|
|
164
|
+
colorTimeouts.delete(color);
|
|
165
|
+
}, CARET_ACTIVITY_TIMEOUT));
|
|
166
|
+
};
|
|
167
|
+
const onDocUpdate = (_update, _origin, _doc, transaction) => {
|
|
168
|
+
const beforeState = transaction.beforeState;
|
|
169
|
+
const afterState = transaction.afterState;
|
|
170
|
+
if (!beforeState || !afterState) return;
|
|
171
|
+
const localClientId = ydoc.clientID;
|
|
172
|
+
const states = prov.awareness?.getStates() ?? /* @__PURE__ */ new Map();
|
|
173
|
+
for (const [clientId, clock] of afterState) {
|
|
174
|
+
if (clientId === localClientId) continue;
|
|
175
|
+
const beforeClock = beforeState.get(clientId) ?? 0;
|
|
176
|
+
if (clock > beforeClock) {
|
|
177
|
+
const state = states.get(clientId);
|
|
178
|
+
const color = state?.user?.color;
|
|
179
|
+
if (color) markActive(color);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
ydoc?.on?.("update", onDocUpdate);
|
|
107
184
|
prov.awareness?.on("change", updateUsers);
|
|
108
185
|
updateUsers();
|
|
186
|
+
const fadeOutTimeouts = /* @__PURE__ */ new Map();
|
|
187
|
+
let caretSyncTimer = null;
|
|
188
|
+
const stopActiveWatch = watch(activeColors, (colors) => {
|
|
189
|
+
if (caretSyncTimer) clearTimeout(caretSyncTimer);
|
|
190
|
+
caretSyncTimer = setTimeout(() => {
|
|
191
|
+
caretSyncTimer = null;
|
|
192
|
+
const carets = document.querySelectorAll(".collaboration-carets__caret[data-user-color]");
|
|
193
|
+
carets.forEach((el) => {
|
|
194
|
+
const color = el.dataset.userColor;
|
|
195
|
+
if (!color) return;
|
|
196
|
+
if (colors.has(color)) {
|
|
197
|
+
if (fadeOutTimeouts.has(color)) {
|
|
198
|
+
clearTimeout(fadeOutTimeouts.get(color));
|
|
199
|
+
fadeOutTimeouts.delete(color);
|
|
200
|
+
}
|
|
201
|
+
el.classList.remove("is-hidden");
|
|
202
|
+
requestAnimationFrame(() => el.classList.add("is-active"));
|
|
203
|
+
} else {
|
|
204
|
+
el.classList.remove("is-active");
|
|
205
|
+
if (!fadeOutTimeouts.has(color)) {
|
|
206
|
+
fadeOutTimeouts.set(color, setTimeout(() => {
|
|
207
|
+
el.classList.add("is-hidden");
|
|
208
|
+
fadeOutTimeouts.delete(color);
|
|
209
|
+
}, 300));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}, 100);
|
|
214
|
+
});
|
|
109
215
|
cleanup = () => {
|
|
216
|
+
ydoc?.off?.("update", onDocUpdate);
|
|
217
|
+
prov.off?.("synced", onProviderSynced);
|
|
110
218
|
prov.awareness?.off("change", updateUsers);
|
|
219
|
+
stopActiveWatch();
|
|
220
|
+
if (caretSyncTimer) {
|
|
221
|
+
clearTimeout(caretSyncTimer);
|
|
222
|
+
caretSyncTimer = null;
|
|
223
|
+
}
|
|
224
|
+
fadeOutTimeouts.forEach((t) => clearTimeout(t));
|
|
225
|
+
fadeOutTimeouts.clear();
|
|
111
226
|
if (fragment) {
|
|
112
227
|
fragment.unobserve(dedupeHeaders);
|
|
113
228
|
fragment.unobserve(dedupeDocumentMeta);
|
|
114
229
|
}
|
|
230
|
+
if (cursorBroadcastTimer) {
|
|
231
|
+
clearTimeout(cursorBroadcastTimer);
|
|
232
|
+
cursorBroadcastTimer = null;
|
|
233
|
+
}
|
|
234
|
+
prov.awareness?.setLocalStateField("cursorPos", null);
|
|
115
235
|
};
|
|
116
236
|
}, { immediate: true });
|
|
117
237
|
onUnmounted(() => cleanup?.());
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useEditorToolbar
|
|
3
3
|
*
|
|
4
|
-
* Returns pre-built toolbar item groups for UEditorToolbar,
|
|
5
|
-
*
|
|
4
|
+
* Returns pre-built toolbar item groups for UEditorToolbar, merging the plugin
|
|
5
|
+
* registry's contributions with standard formatting items.
|
|
6
|
+
*
|
|
7
|
+
* Three building blocks, all individually usable:
|
|
8
|
+
* - `items` full toolbar incl. undo/redo — for a docked/main toolbar.
|
|
9
|
+
* - `bubbleItems` selection bubble — same formatting groups WITHOUT undo/redo
|
|
10
|
+
* (undo/redo belongs in the panel header, not a text bubble).
|
|
11
|
+
* - `getTableToolbarItems(editor)` table-context actions (row/column/table ops).
|
|
6
12
|
*
|
|
7
13
|
* Usage:
|
|
8
|
-
* const {
|
|
9
|
-
* <UEditorToolbar :editor="editor" :items="
|
|
14
|
+
* const { bubbleItems } = useEditorToolbar({ editor, docId })
|
|
15
|
+
* <UEditorToolbar :editor="editor" :items="bubbleItems" layout="bubble" />
|
|
10
16
|
*/
|
|
11
17
|
import type { Editor } from '@tiptap/vue-3';
|
|
12
18
|
export interface UseEditorToolbarOptions {
|
|
@@ -19,4 +25,6 @@ export interface UseEditorToolbarOptions {
|
|
|
19
25
|
}
|
|
20
26
|
export declare function useEditorToolbar(options?: UseEditorToolbarOptions): {
|
|
21
27
|
items: import("vue").ComputedRef<any[][]>;
|
|
28
|
+
bubbleItems: import("vue").ComputedRef<any[][]>;
|
|
29
|
+
getTableToolbarItems: (editor: Editor) => any[][];
|
|
22
30
|
};
|