@abraca/nuxt 0.1.0 → 0.2.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 +216 -56
- package/dist/module.json +1 -1
- package/dist/runtime/components/ADocumentTree.d.vue.ts +8 -43
- package/dist/runtime/components/ADocumentTree.vue +1239 -274
- package/dist/runtime/components/ADocumentTree.vue.d.ts +8 -43
- package/dist/runtime/components/AEditor.d.vue.ts +5 -0
- package/dist/runtime/components/AEditor.vue +85 -29
- package/dist/runtime/components/AEditor.vue.d.ts +5 -0
- package/dist/runtime/components/AFloatingWindow.vue +1 -1
- package/dist/runtime/components/ANodePanel.vue +1 -1
- package/dist/runtime/components/AWindowLayer.vue +1 -1
- package/dist/runtime/composables/useConnectionStatus.d.ts +5 -1
- package/dist/runtime/composables/useConnectionStatus.js +36 -11
- package/dist/runtime/composables/useEditorSuggestions.js +10 -0
- package/dist/runtime/extensions/meta-field.d.ts +16 -0
- package/dist/runtime/extensions/meta-field.js +110 -0
- package/dist/runtime/extensions/views/MetaFieldView.d.vue.ts +4 -0
- package/dist/runtime/extensions/views/MetaFieldView.vue +489 -0
- package/dist/runtime/extensions/views/MetaFieldView.vue.d.ts +4 -0
- package/dist/runtime/plugin-abracadabra.client.js +55 -4
- package/dist/runtime/plugins/core.plugin.js +7 -3
- package/dist/runtime/server/plugins/abracadabra-service.d.ts +1 -1
- package/dist/runtime/server/plugins/abracadabra-service.js +3 -0
- package/dist/runtime/utils/docDragDrop.d.ts +13 -0
- package/dist/runtime/utils/docDragDrop.js +26 -0
- package/package.json +14 -12
package/README.md
CHANGED
|
@@ -1,84 +1,244 @@
|
|
|
1
|
-
|
|
2
|
-
Get your module up and running quickly.
|
|
3
|
-
|
|
4
|
-
Find and replace all on all files (CMD+SHIFT+F):
|
|
5
|
-
- Name: My Module
|
|
6
|
-
- Package name: my-module
|
|
7
|
-
- Description: My new Nuxt module
|
|
8
|
-
-->
|
|
9
|
-
|
|
10
|
-
# My Module
|
|
1
|
+
# @abraca/nuxt
|
|
11
2
|
|
|
12
3
|
[![npm version][npm-version-src]][npm-version-href]
|
|
13
4
|
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
14
5
|
[![License][license-src]][license-href]
|
|
15
6
|
[![Nuxt][nuxt-src]][nuxt-href]
|
|
16
7
|
|
|
17
|
-
|
|
8
|
+
First-class Nuxt 4 module for the [Abracadabra](https://abra.cou.sh) CRDT collaboration platform. Drop real-time collaborative documents, multi-user awareness, offline-first sync, and a full rich-text editor into any Nuxt app.
|
|
18
9
|
|
|
19
|
-
- [
|
|
20
|
-
<!-- - [🏀 Online playground](https://stackblitz.com/github/your-org/my-module?file=playground%2Fapp.vue) -->
|
|
21
|
-
<!-- - [📖 Documentation](https://example.com) -->
|
|
10
|
+
- [Release Notes](/CHANGELOG.md)
|
|
22
11
|
|
|
23
12
|
## Features
|
|
24
13
|
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
14
|
+
- Real-time collaborative editing via WebSocket + Yjs CRDT
|
|
15
|
+
- Offline-first with IndexedDB persistence and background sync queue
|
|
16
|
+
- Multi-user awareness — cursors, presence, typing indicators, voice/video
|
|
17
|
+
- TipTap rich-text editor with 30+ built-in extensions
|
|
18
|
+
- Built-in page renderers: Kanban, Table, Calendar, Gallery, Outline
|
|
19
|
+
- Full-text search with trigram indexing
|
|
20
|
+
- File uploads with offline blob caching
|
|
21
|
+
- Passkey (WebAuthn) authentication
|
|
22
|
+
- Server-side rendering with Nitro plugin system and doc cache
|
|
23
|
+
- Extensible plugin architecture
|
|
24
|
+
|
|
25
|
+
## Requirements
|
|
29
26
|
|
|
30
|
-
|
|
27
|
+
- Nuxt >= 4
|
|
28
|
+
- `@abraca/dabra` >= 1.0.0
|
|
29
|
+
- `@tiptap/core`, `@tiptap/vue-3`, `@tiptap/extension-collaboration`, `@tiptap/extension-collaboration-caret`
|
|
30
|
+
- `yjs` >= 13
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
## Setup
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
|
|
35
|
+
pnpm add @abraca/nuxt @abraca/dabra yjs @tiptap/core @tiptap/vue-3 @tiptap/extension-collaboration @tiptap/extension-collaboration-caret
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// nuxt.config.ts
|
|
40
|
+
export default defineNuxtConfig({
|
|
41
|
+
modules: ['@abraca/nuxt'],
|
|
42
|
+
abracadabra: {
|
|
43
|
+
url: 'https://your-abracadabra-server.example.com',
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Wrap your app with `<AProvider>` and you're live:
|
|
49
|
+
|
|
50
|
+
```vue
|
|
51
|
+
<template>
|
|
52
|
+
<AProvider>
|
|
53
|
+
<NuxtPage />
|
|
54
|
+
</AProvider>
|
|
55
|
+
</template>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
abracadabra: {
|
|
62
|
+
// Connection
|
|
63
|
+
url?: string // Server URL (default: 'https://abra.cou.sh')
|
|
64
|
+
entryDocId?: string // Root doc ID (skips space discovery)
|
|
65
|
+
|
|
66
|
+
// Auth
|
|
67
|
+
persistAuth?: boolean // Persist JWT in localStorage (default: true)
|
|
68
|
+
authStorageKey?: string // localStorage key (default: 'abracadabra:auth')
|
|
69
|
+
auth?: {
|
|
70
|
+
middleware?: boolean // Register abracadabra-auth middleware
|
|
71
|
+
globalMiddleware?: boolean // Apply to all routes
|
|
72
|
+
loginPath?: string // Redirect target (default: '/login')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Features (control what code is included)
|
|
76
|
+
features?: {
|
|
77
|
+
editor?: boolean // TipTap editor (default: true)
|
|
78
|
+
search?: boolean // Full-text search (default: true)
|
|
79
|
+
backgroundSync?: boolean // Offline sync queue (default: true)
|
|
80
|
+
renderers?: boolean // Built-in page renderers (default: true)
|
|
81
|
+
serverCache?: boolean // Server doc-tree cache runner (default: true)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// UI
|
|
85
|
+
prefix?: string // Component name prefix (default: '')
|
|
86
|
+
locale?: Partial<AbracadabraLocale>
|
|
87
|
+
docBasePath?: string // Doc route base (default: '/doc')
|
|
88
|
+
|
|
89
|
+
// Server-side service account (for Nitro runners)
|
|
90
|
+
service?: {
|
|
91
|
+
publicKey?: string // Ed25519 public key (base64url)
|
|
92
|
+
privateKey?: string // Ed25519 private key (base64url)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
debug?: boolean
|
|
96
|
+
}
|
|
36
97
|
```
|
|
37
98
|
|
|
38
|
-
|
|
99
|
+
## Auto-imported Composables
|
|
100
|
+
|
|
101
|
+
| Composable | Description |
|
|
102
|
+
|---|---|
|
|
103
|
+
| `useAbracadabra()` | Full collaboration state (client, provider, identity, docs) |
|
|
104
|
+
| `useAbracadabraAuth()` | Auth — login, passkey, identity management |
|
|
105
|
+
| `useAwareness()` | All connected users' raw awareness states |
|
|
106
|
+
| `useAwarenessPeers()` | Typed peer list with idle detection |
|
|
107
|
+
| `useAAField(key)` | Per-field interaction awareness (hover, press, focus) |
|
|
108
|
+
| `useYDoc(ydoc)` | Reactive Yjs primitives — `useSyncedMap`, `useSyncedArray`, `useAwarenessOf`, `useSmoothedCursors` |
|
|
109
|
+
| `useEditor(ydoc, opts)` | TipTap setup with collaboration + cursor extensions |
|
|
110
|
+
| `useChildTree(docId)` | Document tree scoped to a parent |
|
|
111
|
+
| `useDocumentPermissions(role)` | RBAC flags (canWrite, canDelete, etc.) |
|
|
112
|
+
| `useChat(channel)` | Real-time group & DM chat |
|
|
113
|
+
| `useNotifications()` | Server-pushed notifications |
|
|
114
|
+
| `useSearchIndex()` | Full-text search over synced docs |
|
|
115
|
+
| `useBackgroundSync()` | Offline sync queue status |
|
|
116
|
+
| `useDocExport()` | Export docs as markdown, HTML, or ZIP |
|
|
117
|
+
| `useDocImport()` | Import .md, .txt, .html files |
|
|
118
|
+
| `useFileBlobStore()` | Offline file blob cache (IndexedDB) |
|
|
119
|
+
| `useVoice()` | WebRTC voice/video state |
|
|
120
|
+
| `useWindowManager()` | Floating window (PiP/panel) management |
|
|
121
|
+
| `useCommandPalette()` | ⌘K command palette state & commands |
|
|
122
|
+
| `useConnectionStatus()` | Connection status as UI-ready label + color |
|
|
123
|
+
| `useRendererBase(docId)` | Shared setup for custom page renderers |
|
|
124
|
+
| `useTrash()` | Document trash (move, restore, permanent delete) |
|
|
125
|
+
| `usePasskeyAccounts()` | WebAuthn passkey account management |
|
|
126
|
+
| `useFollowUser(userId)` | Cursor following for pair programming |
|
|
127
|
+
|
|
128
|
+
## Auto-imported Components
|
|
129
|
+
|
|
130
|
+
### Core
|
|
131
|
+
| Component | Description |
|
|
132
|
+
|---|---|
|
|
133
|
+
| `<AProvider>` | Root wrapper — initializes SDK and syncs root doc |
|
|
134
|
+
| `<AEditor>` | Full TipTap collaborative editor |
|
|
135
|
+
| `<ADocumentTree>` | Hierarchical doc tree with drag-drop |
|
|
136
|
+
| `<ANodePanel>` | Slide-over panel with doc metadata and children |
|
|
137
|
+
| `<ACommandPalette>` | ⌘K search and command palette |
|
|
138
|
+
| `<AConnectionStatus>` | Connection state badge |
|
|
139
|
+
| `<APresence>` | Connected users presence indicator |
|
|
140
|
+
| `<ANotifications>` | Notification center |
|
|
141
|
+
| `<AVoiceBar>` | Voice/video call controls |
|
|
142
|
+
| `<ADocTypeSelect>` | Page type selector |
|
|
143
|
+
| `<APermissionGuard>` | Conditional render based on role |
|
|
144
|
+
| `<ARoleBadge>` | Role badge (Owner, Editor, Viewer, etc.) |
|
|
145
|
+
| `<AFloatingWindow>` | Floating/PiP window container |
|
|
146
|
+
| `<AWindowLayer>` | Portal for floating windows |
|
|
147
|
+
|
|
148
|
+
### Aware Interaction Components
|
|
149
|
+
Interaction components that broadcast awareness state to other users:
|
|
150
|
+
|
|
151
|
+
`<AArea>` `<AAvatar>` `<AButton>` `<AInput>` `<ATextarea>` `<ASelect>` `<ACursorLabel>` `<AFacepile>` `<AUserList>` `<ADocBadge>`
|
|
152
|
+
|
|
153
|
+
### Page Renderers (requires `features.renderers`)
|
|
154
|
+
`<AKanbanRenderer>` `<ATableRenderer>` `<ACalendarRenderer>` `<AGalleryRenderer>` `<AOutlineRenderer>`
|
|
155
|
+
|
|
156
|
+
## Server-Side Usage
|
|
157
|
+
|
|
158
|
+
Configure a service account for server-side doc access:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
// nuxt.config.ts
|
|
162
|
+
export default defineNuxtConfig({
|
|
163
|
+
modules: ['@abraca/nuxt'],
|
|
164
|
+
runtimeConfig: {
|
|
165
|
+
abracadabra: {
|
|
166
|
+
servicePublicKey: process.env.ABRA_SERVICE_PUBLIC_KEY,
|
|
167
|
+
servicePrivateKey: process.env.ABRA_SERVICE_PRIVATE_KEY,
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
```
|
|
39
172
|
|
|
173
|
+
Register custom server runners via the Nitro hook:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
// server/plugins/my-runner.ts
|
|
177
|
+
export default defineNitroPlugin((nitro) => {
|
|
178
|
+
nitro.hooks.hook('abracadabra:before-runners', (ctx) => {
|
|
179
|
+
registerServerPlugin({
|
|
180
|
+
name: 'my-runner',
|
|
181
|
+
runners: [{
|
|
182
|
+
name: 'my-background-task',
|
|
183
|
+
run: async ({ provider, client }) => {
|
|
184
|
+
// background work
|
|
185
|
+
return () => { /* cleanup */ }
|
|
186
|
+
}
|
|
187
|
+
}]
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
})
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Plugin System
|
|
194
|
+
|
|
195
|
+
Extend the editor, add toolbar items, slash commands, and page types:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import type { AbracadabraPlugin } from '@abraca/nuxt'
|
|
199
|
+
|
|
200
|
+
const myPlugin: AbracadabraPlugin = {
|
|
201
|
+
name: 'my-plugin',
|
|
202
|
+
extensions: () => [/* TipTap extensions */],
|
|
203
|
+
toolbarItems: () => [/* toolbar groups */],
|
|
204
|
+
suggestionItems: () => [/* slash commands */],
|
|
205
|
+
pageTypes: [{ type: 'my-type', label: 'My Page', component: MyRenderer }],
|
|
206
|
+
clientSetup: async (state) => { /* init */ }
|
|
207
|
+
}
|
|
208
|
+
```
|
|
40
209
|
|
|
41
210
|
## Contribution
|
|
42
211
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
```bash
|
|
47
|
-
# Install dependencies
|
|
48
|
-
npm install
|
|
49
|
-
|
|
50
|
-
# Generate type stubs
|
|
51
|
-
npm run dev:prepare
|
|
52
|
-
|
|
53
|
-
# Develop with the playground
|
|
54
|
-
npm run dev
|
|
55
|
-
|
|
56
|
-
# Build the playground
|
|
57
|
-
npm run dev:build
|
|
58
|
-
|
|
59
|
-
# Run ESLint
|
|
60
|
-
npm run lint
|
|
61
|
-
|
|
62
|
-
# Run Vitest
|
|
63
|
-
npm run test
|
|
64
|
-
npm run test:watch
|
|
65
|
-
|
|
66
|
-
# Release new version
|
|
67
|
-
npm run release
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
</details>
|
|
212
|
+
```bash
|
|
213
|
+
# Install dependencies
|
|
214
|
+
pnpm install
|
|
71
215
|
|
|
216
|
+
# Generate type stubs
|
|
217
|
+
pnpm dev:prepare
|
|
218
|
+
|
|
219
|
+
# Develop with the playground
|
|
220
|
+
pnpm dev
|
|
221
|
+
|
|
222
|
+
# Build
|
|
223
|
+
pnpm prepack
|
|
224
|
+
|
|
225
|
+
# Lint
|
|
226
|
+
pnpm lint
|
|
227
|
+
|
|
228
|
+
# Test
|
|
229
|
+
pnpm test
|
|
230
|
+
pnpm test:watch
|
|
231
|
+
```
|
|
72
232
|
|
|
73
233
|
<!-- Badges -->
|
|
74
|
-
[npm-version-src]: https://img.shields.io/npm/v/
|
|
75
|
-
[npm-version-href]: https://npmjs.com/package/
|
|
234
|
+
[npm-version-src]: https://img.shields.io/npm/v/@abraca/nuxt/latest.svg?style=flat&colorA=020420&colorB=00DC82
|
|
235
|
+
[npm-version-href]: https://npmjs.com/package/@abraca/nuxt
|
|
76
236
|
|
|
77
|
-
[npm-downloads-src]: https://img.shields.io/npm/dm/
|
|
78
|
-
[npm-downloads-href]: https://npm.chart.dev/
|
|
237
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/@abraca/nuxt.svg?style=flat&colorA=020420&colorB=00DC82
|
|
238
|
+
[npm-downloads-href]: https://npm.chart.dev/@abraca/nuxt
|
|
79
239
|
|
|
80
|
-
[license-src]: https://img.shields.io/npm/l/
|
|
81
|
-
[license-href]: https://npmjs.com/package/
|
|
240
|
+
[license-src]: https://img.shields.io/npm/l/@abraca/nuxt.svg?style=flat&colorA=020420&colorB=00DC82
|
|
241
|
+
[license-href]: https://npmjs.com/package/@abraca/nuxt
|
|
82
242
|
|
|
83
243
|
[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
|
|
84
244
|
[nuxt-href]: https://nuxt.com
|
package/dist/module.json
CHANGED
|
@@ -1,53 +1,18 @@
|
|
|
1
|
-
import type { AbracadabraLocale } from '../locale.js';
|
|
2
1
|
type __VLS_Props = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
draggable?: boolean;
|
|
2
|
+
collapsed?: boolean;
|
|
3
|
+
editable?: boolean;
|
|
6
4
|
selectedId?: string | null;
|
|
7
|
-
labels?: Partial<AbracadabraLocale['documentTree']>;
|
|
8
5
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
meta?: Record<string, any>;
|
|
14
|
-
depth: number;
|
|
15
|
-
parentId: string | null;
|
|
16
|
-
order: number;
|
|
17
|
-
isExpanded: boolean;
|
|
18
|
-
hasChildren: boolean;
|
|
19
|
-
}
|
|
20
|
-
declare var __VLS_1: {}, __VLS_20: {
|
|
21
|
-
entry: FlatItem;
|
|
22
|
-
depth: number;
|
|
23
|
-
isExpanded: boolean;
|
|
24
|
-
}, __VLS_42: {}, __VLS_85: {};
|
|
25
|
-
type __VLS_Slots = {} & {
|
|
26
|
-
header?: (props: typeof __VLS_1) => any;
|
|
27
|
-
} & {
|
|
28
|
-
item?: (props: typeof __VLS_20) => any;
|
|
29
|
-
} & {
|
|
30
|
-
empty?: (props: typeof __VLS_42) => any;
|
|
31
|
-
} & {
|
|
32
|
-
footer?: (props: typeof __VLS_85) => any;
|
|
33
|
-
};
|
|
34
|
-
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
35
|
-
select: (docId: string) => any;
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
|
|
7
|
+
handleExternalDrop: (e: DragEvent, parentId?: string | null) => any;
|
|
8
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
9
|
+
navigate: (id: string) => any;
|
|
36
10
|
create: (parentId: string | null) => any;
|
|
37
11
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
38
|
-
|
|
12
|
+
onNavigate?: ((id: string) => any) | undefined;
|
|
39
13
|
onCreate?: ((parentId: string | null) => any) | undefined;
|
|
40
14
|
}>, {
|
|
41
|
-
|
|
42
|
-
showTrash: boolean;
|
|
43
|
-
allowFileDrop: boolean;
|
|
44
|
-
selectedId: string | null;
|
|
15
|
+
editable: boolean;
|
|
45
16
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
46
|
-
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
47
17
|
declare const _default: typeof __VLS_export;
|
|
48
18
|
export default _default;
|
|
49
|
-
type __VLS_WithSlots<T, S> = T & {
|
|
50
|
-
new (): {
|
|
51
|
-
$slots: S;
|
|
52
|
-
};
|
|
53
|
-
};
|