@abraca/nuxt 2.11.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.
Files changed (74) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +7 -0
  3. package/dist/runtime/components/ADocPickerModal.d.vue.ts +31 -0
  4. package/dist/runtime/components/ADocPickerModal.vue +191 -0
  5. package/dist/runtime/components/ADocPickerModal.vue.d.ts +31 -0
  6. package/dist/runtime/components/ADocumentTree.vue +65 -0
  7. package/dist/runtime/components/AEditor.d.vue.ts +17 -10
  8. package/dist/runtime/components/AEditor.vue +232 -164
  9. package/dist/runtime/components/AEditor.vue.d.ts +17 -10
  10. package/dist/runtime/components/ANodePanel.d.vue.ts +9 -1
  11. package/dist/runtime/components/ANodePanel.vue +547 -473
  12. package/dist/runtime/components/ANodePanel.vue.d.ts +9 -1
  13. package/dist/runtime/components/ATagsEditor.d.vue.ts +19 -0
  14. package/dist/runtime/components/ATagsEditor.vue +60 -0
  15. package/dist/runtime/components/ATagsEditor.vue.d.ts +19 -0
  16. package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
  17. package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
  18. package/dist/runtime/components/chat/AChatInput.d.vue.ts +11 -6
  19. package/dist/runtime/components/chat/AChatInput.vue +33 -2
  20. package/dist/runtime/components/chat/AChatInput.vue.d.ts +11 -6
  21. package/dist/runtime/components/chat/AChatList.d.vue.ts +12 -0
  22. package/dist/runtime/components/chat/AChatList.vue +76 -32
  23. package/dist/runtime/components/chat/AChatList.vue.d.ts +12 -0
  24. package/dist/runtime/components/chat/AChatMessages.d.vue.ts +4 -0
  25. package/dist/runtime/components/chat/AChatMessages.vue +57 -4
  26. package/dist/runtime/components/chat/AChatMessages.vue.d.ts +4 -0
  27. package/dist/runtime/components/chat/AChatPanel.d.vue.ts +6 -2
  28. package/dist/runtime/components/chat/AChatPanel.vue +17 -1
  29. package/dist/runtime/components/chat/AChatPanel.vue.d.ts +6 -2
  30. package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -1
  31. package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
  32. package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
  33. package/dist/runtime/components/renderers/AChartRenderer.client.d.vue.ts +17 -0
  34. package/dist/runtime/components/renderers/AChartRenderer.client.vue +622 -0
  35. package/dist/runtime/components/renderers/AChartRenderer.client.vue.d.ts +17 -0
  36. package/dist/runtime/components/renderers/AGraphRenderer.vue +64 -15
  37. package/dist/runtime/components/renderers/calendar/ACalendarToolbar.d.vue.ts +2 -2
  38. package/dist/runtime/components/renderers/calendar/ACalendarToolbar.vue.d.ts +2 -2
  39. package/dist/runtime/components/renderers/media/MediaTransportBar.d.vue.ts +2 -2
  40. package/dist/runtime/components/renderers/media/MediaTransportBar.vue.d.ts +2 -2
  41. package/dist/runtime/components/renderers/sheets/ASheetsGrid.d.vue.ts +2 -2
  42. package/dist/runtime/components/renderers/sheets/ASheetsGrid.vue.d.ts +2 -2
  43. package/dist/runtime/components/settings/ASettingsAppearancePanel.d.vue.ts +3 -0
  44. package/dist/runtime/components/settings/ASettingsAppearancePanel.vue +67 -0
  45. package/dist/runtime/components/settings/ASettingsAppearancePanel.vue.d.ts +3 -0
  46. package/dist/runtime/components/settings/ASettingsGroup.d.vue.ts +24 -0
  47. package/dist/runtime/components/settings/ASettingsGroup.vue +31 -0
  48. package/dist/runtime/components/settings/ASettingsGroup.vue.d.ts +24 -0
  49. package/dist/runtime/components/settings/ASettingsModal.vue +84 -53
  50. package/dist/runtime/components/settings/ASettingsPlaceholder.d.vue.ts +20 -0
  51. package/dist/runtime/components/settings/ASettingsPlaceholder.vue +32 -0
  52. package/dist/runtime/components/settings/ASettingsPlaceholder.vue.d.ts +20 -0
  53. package/dist/runtime/components/settings/ASettingsRow.d.vue.ts +34 -0
  54. package/dist/runtime/components/settings/ASettingsRow.vue +34 -0
  55. package/dist/runtime/components/settings/ASettingsRow.vue.d.ts +34 -0
  56. package/dist/runtime/components/settings/sections.d.ts +37 -0
  57. package/dist/runtime/components/settings/sections.js +45 -0
  58. package/dist/runtime/components/shell/AUserMenu.d.vue.ts +2 -2
  59. package/dist/runtime/components/shell/AUserMenu.vue.d.ts +2 -2
  60. package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
  61. package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
  62. package/dist/runtime/composables/useChat.d.ts +22 -1
  63. package/dist/runtime/composables/useChat.js +79 -8
  64. package/dist/runtime/composables/useNodeContextMenu.d.ts +4 -0
  65. package/dist/runtime/composables/useNodeContextMenu.js +18 -0
  66. package/dist/runtime/composables/useSettingsModal.d.ts +1 -1
  67. package/dist/runtime/locale.d.ts +8 -0
  68. package/dist/runtime/locale.js +9 -1
  69. package/dist/runtime/utils/chatContent.d.ts +20 -2
  70. package/dist/runtime/utils/chatContent.js +20 -1
  71. package/dist/runtime/utils/docTypes.js +43 -0
  72. package/dist/runtime/utils/titleSync.d.ts +130 -0
  73. package/dist/runtime/utils/titleSync.js +53 -0
  74. package/package.json +11 -1
@@ -5,8 +5,11 @@ import { Fragment } from "@tiptap/pm/model";
5
5
  import { useSyncedMap } from "../composables/useYDoc";
6
6
  import { resolveDocType, GEO_TYPE_META_SCHEMAS } from "../utils/docTypes";
7
7
  import { schemaFieldToAttrs, userFieldToAttrs } from "../extensions/meta-field";
8
+ import { decideTitleSync, setHeaderText as applyHeaderText, UNTITLED } from "../utils/titleSync";
8
9
  import { useEditor } from "../composables/useEditor";
9
10
  import { useDocTree } from "../composables/useDocTree";
11
+ import { useDocBreadcrumb } from "../composables/useDocBreadcrumb";
12
+ import { useDocSlugs } from "../composables/useDocSlugs";
10
13
  import { useEditorToolbar } from "../composables/useEditorToolbar";
11
14
  import { useEditorSuggestions } from "../composables/useEditorSuggestions";
12
15
  import { useEditorDragHandle } from "../composables/useEditorDragHandle";
@@ -28,7 +31,8 @@ const props = defineProps({
28
31
  parentType: { type: String, required: false },
29
32
  metaSchema: { type: Array, required: false },
30
33
  variant: { type: String, required: false, default: "doc" },
31
- showSourceToggle: { type: Boolean, required: false, default: false }
34
+ showSourceToggle: { type: Boolean, required: false, default: false },
35
+ showBreadcrumb: { type: Boolean, required: false, default: true }
32
36
  });
33
37
  const viewMode = ref("rich");
34
38
  const emit = defineEmits(["ready", "update", "rename", "updateMeta"]);
@@ -167,79 +171,93 @@ function initDocumentMeta(ed) {
167
171
  metaInitDone = true;
168
172
  }
169
173
  let syncingFromEditor = false;
170
- const _lastEmittedHeader = ref("");
174
+ let lastSyncedLabel = null;
171
175
  function getHeaderText(ed) {
172
176
  const first = ed.state.doc.firstChild;
173
177
  if (!first || first.type.name !== "documentHeader") return "";
174
178
  return first.textContent;
175
179
  }
176
- function setHeaderText(ed, text) {
177
- const first = ed.state.doc.firstChild;
178
- if (!first || first.type.name !== "documentHeader") return;
179
- if (first.textContent === text) return;
180
- const { tr, schema } = ed.state;
181
- const to = 1 + first.content.size;
182
- if (text) {
183
- tr.replaceWith(1, to, schema.text(text));
184
- } else {
185
- tr.delete(1, to);
186
- }
187
- ed.view.dispatch(tr);
180
+ function currentTreeLabel() {
181
+ return _treeMap.data[props.docId]?.label ?? props.docLabel ?? "";
188
182
  }
189
- function syncHeaderToTree(ed) {
190
- const text = getHeaderText(ed);
191
- if (text === _lastEmittedHeader.value) return;
192
- _lastEmittedHeader.value = text;
183
+ function writeTreeLabel(label) {
184
+ const e = _treeMap.data[props.docId];
185
+ const next = label || UNTITLED;
186
+ if (!e || e.label === next) return;
193
187
  syncingFromEditor = true;
194
- emit("rename", text || "Untitled");
188
+ lastSyncedLabel = next;
189
+ _treeMap.set(props.docId, { ...e, label: next, updatedAt: Date.now() });
190
+ emit("rename", next);
195
191
  nextTick(() => {
196
192
  syncingFromEditor = false;
197
193
  });
198
194
  }
195
+ function syncHeader(ed, isRemoteUpdate, initialSyncDone) {
196
+ const action = decideTitleSync({
197
+ headerText: getHeaderText(ed),
198
+ treeLabel: currentTreeLabel(),
199
+ isRemoteUpdate,
200
+ initialSyncDone
201
+ });
202
+ if (action.kind === "noop") return;
203
+ if (action.kind === "header-from-tree") {
204
+ applyHeaderText(ed, action.text);
205
+ return;
206
+ }
207
+ writeTreeLabel(action.label);
208
+ }
199
209
  watchEffect((onCleanup) => {
200
210
  const ed = editorRef.value?.editor;
201
211
  if (!ed || !ready.value) return;
202
212
  let initialSyncDone = false;
203
- function doInitialSync() {
204
- if (initialSyncDone) return;
205
- initialSyncDone = true;
206
- const headerText = getHeaderText(ed);
207
- const treeLabel = props.docLabel ?? "";
208
- if (headerText !== treeLabel) {
209
- const treeMeansEmpty = !treeLabel || treeLabel === "Untitled";
210
- const headerMeansEmpty = !headerText;
211
- if (treeMeansEmpty && headerMeansEmpty) return;
212
- if (!treeMeansEmpty && headerMeansEmpty) {
213
- setHeaderText(ed, treeLabel);
214
- return;
213
+ let headerTimer = null;
214
+ const runSync = (isRemote) => {
215
+ const wasInitial = !initialSyncDone;
216
+ if (wasInitial) initialSyncDone = true;
217
+ syncHeader(ed, isRemote, !wasInitial);
218
+ };
219
+ function onUpdate({ transaction }) {
220
+ const isRemote = !!transaction?.getMeta?.("y-sync$")?.isChangeOrigin;
221
+ initDocumentMeta(ed);
222
+ if (isRemote || !initialSyncDone) {
223
+ if (headerTimer) {
224
+ clearTimeout(headerTimer);
225
+ headerTimer = null;
215
226
  }
216
- _lastEmittedHeader.value = headerText;
217
- syncingFromEditor = true;
218
- emit("rename", headerText);
219
- nextTick(() => {
220
- syncingFromEditor = false;
221
- });
227
+ runSync(isRemote);
228
+ } else {
229
+ if (headerTimer) clearTimeout(headerTimer);
230
+ headerTimer = setTimeout(() => {
231
+ headerTimer = null;
232
+ runSync(false);
233
+ }, 200);
222
234
  }
223
235
  }
224
- function onUpdate() {
225
- syncHeaderToTree(ed);
226
- initDocumentMeta(ed);
227
- }
228
236
  nextTick(() => {
229
- doInitialSync();
237
+ runSync(false);
230
238
  initDocumentMeta(ed);
231
239
  });
232
240
  ed.on("update", onUpdate);
233
- onCleanup(() => ed.off("update", onUpdate));
234
- });
235
- watch(() => props.docLabel, (newLabel) => {
236
- if (syncingFromEditor) return;
237
- if (newLabel === _lastEmittedHeader.value) return;
238
- if (!_treeMap.lastUpdateLocal.value) return;
239
- const ed = editorRef.value?.editor;
240
- if (!ed || !ready.value) return;
241
- setHeaderText(ed, newLabel || "");
241
+ onCleanup(() => {
242
+ if (headerTimer) clearTimeout(headerTimer);
243
+ ed.off("update", onUpdate);
244
+ });
242
245
  });
246
+ watch(
247
+ () => _treeMap.data[props.docId]?.label ?? props.docLabel,
248
+ (newLabel) => {
249
+ if (syncingFromEditor) return;
250
+ if (lastSyncedLabel !== null && newLabel === lastSyncedLabel) {
251
+ lastSyncedLabel = null;
252
+ return;
253
+ }
254
+ lastSyncedLabel = null;
255
+ if (newLabel === void 0 || newLabel === "" || newLabel === UNTITLED) return;
256
+ const ed = editorRef.value?.editor;
257
+ if (!ed || !ready.value) return;
258
+ applyHeaderText(ed, newLabel);
259
+ }
260
+ );
243
261
  function insertNode(editor, type, attrs, content) {
244
262
  const node = { type, attrs };
245
263
  if (content) node.content = content;
@@ -357,6 +375,11 @@ const editorHandlers = {
357
375
  const _mentionItems = computed(
358
376
  () => registry.getAllMentionProviders().flatMap((p) => p.label ? [p] : [])
359
377
  );
378
+ const { items: _breadcrumbItems } = useDocBreadcrumb(() => props.docId);
379
+ const { getDocUrl } = useDocSlugs();
380
+ const ancestorChain = computed(
381
+ () => _breadcrumbItems.value.slice(0, -1).map((a) => ({ ...a, to: getDocUrl(a.id) }))
382
+ );
360
383
  function onPlusClick(e, onClick) {
361
384
  e.stopPropagation();
362
385
  onClick();
@@ -387,7 +410,10 @@ function onPlusClick(e, onClick) {
387
410
  >
388
411
  <div class="aeditor-source-toolbar">
389
412
  <span class="aeditor-source-toolbar__label">
390
- <UIcon name="i-lucide-code-xml" class="size-3.5" />
413
+ <UIcon
414
+ name="i-lucide-code-xml"
415
+ class="size-3.5"
416
+ />
391
417
  XML source — read-only mirror of <code>getXmlFragment('default')</code>
392
418
  </span>
393
419
  <UButton
@@ -408,136 +434,178 @@ function onPlusClick(e, onClick) {
408
434
  />
409
435
  </div>
410
436
 
411
- <UEditor
437
+ <!-- Editor canvas: ancestor breadcrumb (cou-sh parity) + the TipTap editor,
438
+ stacked in one scroll container (the parent's overflow class falls
439
+ through to this wrapper). -->
440
+ <div
412
441
  v-else
413
- :class="{ 'prose-variant': variant === 'prose' }"
414
- ref="editorRef"
415
- v-slot="{ editor }"
416
- v-model="model"
417
- :content-type="contentType"
418
- :editable="editable"
419
- :extensions="extensions"
420
- :starter-kit="{ undoRedo: false, codeBlock: false, document: false }"
421
- :handlers="editorHandlers"
422
- :placeholder="placeholder"
423
- @update:model-value="emit('update', $event)"
442
+ class="aeditor-canvas"
424
443
  >
425
- <!-- Floating source-view toggle (opt-in via :show-source-toggle="true") -->
426
- <UButton
427
- v-if="showSourceToggle"
428
- class="aeditor-source-toggle"
429
- icon="i-lucide-code-xml"
430
- size="xs"
431
- variant="ghost"
432
- color="neutral"
433
- :title="'View XML source'"
434
- @click="viewMode = 'source'"
435
- />
436
- <!-- Default slot: app can override entire editor content -->
437
- <slot
438
- :editor="editor"
439
- :connected-users="connectedUsers"
440
- :ready="ready"
444
+ <nav
445
+ v-if="showBreadcrumb && ancestorChain.length"
446
+ aria-label="Breadcrumb"
447
+ class="aeditor-breadcrumb"
441
448
  >
442
- <!-- ── Bubble toolbar (appears when text is selected) ─────────────── -->
443
- <!-- 4 named slots are forwarded to consumers:
444
- #link / #doc-link defaulted to ALinkPopover / ADocLinkPopover
445
- #create-child-doc / #send-to-chat — empty by default; app-defined -->
446
- <UEditorToolbar
447
- v-if="showToolbar"
448
- :editor="editor"
449
- :items="toolbarItems"
450
- layout="bubble"
451
- :should-show="({ view, state }) => view.hasFocus() && !state.selection.empty"
452
- >
453
- <template #link>
454
- <slot
455
- name="link"
456
- :editor="editor"
457
- >
458
- <ALinkPopover :editor="editor" />
459
- </slot>
460
- </template>
461
- <template #doc-link>
462
- <slot
463
- name="doc-link"
464
- :editor="editor"
449
+ <ol class="flex items-center gap-0.5 min-w-0">
450
+ <template
451
+ v-for="(ancestor, idx) in ancestorChain"
452
+ :key="ancestor.id"
453
+ >
454
+ <li
455
+ v-if="idx > 0"
456
+ class="flex shrink-0"
465
457
  >
466
- <ADocLinkPopover :editor="editor" />
467
- </slot>
468
- </template>
469
- <template #create-child-doc>
470
- <slot
471
- name="create-child-doc"
472
- :editor="editor"
473
- />
458
+ <UIcon
459
+ name="i-lucide-chevron-right"
460
+ class="size-4 text-(--ui-text-dimmed)"
461
+ />
462
+ </li>
463
+ <li class="flex min-w-0">
464
+ <ULink
465
+ :to="ancestor.to"
466
+ class="flex items-center gap-1.5 px-1.5 py-0.5 rounded-md text-sm text-(--ui-text-muted) font-medium hover:bg-(--ui-bg-elevated)/60 hover:text-(--ui-text) transition-colors min-w-0 select-none"
467
+ >
468
+ <UIcon
469
+ :name="ancestor.icon"
470
+ class="size-4 shrink-0"
471
+ />
472
+ <span class="truncate">{{ ancestor.label }}</span>
473
+ </ULink>
474
+ </li>
474
475
  </template>
475
- <template #send-to-chat>
476
- <slot
477
- name="send-to-chat"
478
- :editor="editor"
479
- />
480
- </template>
481
- </UEditorToolbar>
476
+ </ol>
477
+ </nav>
482
478
 
483
- <!-- ── Slash command menu ──────────────────────────────────────────── -->
484
- <UEditorSuggestionMenu
485
- v-if="showSuggestionMenu"
486
- :editor="editor"
487
- :items="suggestionItems"
479
+ <UEditor
480
+ ref="editorRef"
481
+ v-slot="{ editor }"
482
+ v-model="model"
483
+ :class="{ 'prose-variant': variant === 'prose' }"
484
+ :content-type="contentType"
485
+ :editable="editable"
486
+ :extensions="extensions"
487
+ :starter-kit="{ undoRedo: false, codeBlock: false, document: false }"
488
+ :handlers="editorHandlers"
489
+ :placeholder="placeholder"
490
+ @update:model-value="emit('update', $event)"
491
+ >
492
+ <!-- Floating source-view toggle (opt-in via :show-source-toggle="true") -->
493
+ <UButton
494
+ v-if="showSourceToggle"
495
+ class="aeditor-source-toggle"
496
+ icon="i-lucide-code-xml"
497
+ size="xs"
498
+ variant="ghost"
499
+ color="neutral"
500
+ :title="'View XML source'"
501
+ @click="viewMode = 'source'"
488
502
  />
489
-
490
- <!-- ── Emoji menu (`:` trigger) ───────────────────────────────────── -->
491
- <UEditorEmojiMenu
503
+ <!-- Default slot: app can override entire editor content -->
504
+ <slot
492
505
  :editor="editor"
493
- :items="emojiItems"
494
- />
506
+ :connected-users="connectedUsers"
507
+ :ready="ready"
508
+ >
509
+ <!-- ── Bubble toolbar (appears when text is selected) ─────────────── -->
510
+ <!-- 4 named slots are forwarded to consumers:
511
+ #link / #doc-link — defaulted to ALinkPopover / ADocLinkPopover
512
+ #create-child-doc / #send-to-chat — empty by default; app-defined -->
513
+ <UEditorToolbar
514
+ v-if="showToolbar"
515
+ :editor="editor"
516
+ :items="toolbarItems"
517
+ layout="bubble"
518
+ :should-show="({ view, state }) => view.hasFocus() && !state.selection.empty"
519
+ >
520
+ <template #link>
521
+ <slot
522
+ name="link"
523
+ :editor="editor"
524
+ >
525
+ <ALinkPopover :editor="editor" />
526
+ </slot>
527
+ </template>
528
+ <template #doc-link>
529
+ <slot
530
+ name="doc-link"
531
+ :editor="editor"
532
+ >
533
+ <ADocLinkPopover :editor="editor" />
534
+ </slot>
535
+ </template>
536
+ <template #create-child-doc>
537
+ <slot
538
+ name="create-child-doc"
539
+ :editor="editor"
540
+ />
541
+ </template>
542
+ <template #send-to-chat>
543
+ <slot
544
+ name="send-to-chat"
545
+ :editor="editor"
546
+ />
547
+ </template>
548
+ </UEditorToolbar>
495
549
 
496
- <!-- ── Mention menu (`@` trigger) — users + docs + plugin providers ── -->
497
- <UEditorMentionMenu
498
- :editor="editor"
499
- :items="mentionItems"
500
- />
550
+ <!-- ── Slash command menu ──────────────────────────────────────────── -->
551
+ <UEditorSuggestionMenu
552
+ v-if="showSuggestionMenu"
553
+ :editor="editor"
554
+ :items="suggestionItems"
555
+ />
501
556
 
502
- <!-- ── Drag handle plus button + grip dropdown ───────────────────── -->
503
- <UEditorDragHandle
504
- v-if="showDragHandle"
505
- v-slot="{ ui, onClick }"
506
- :editor="editor"
507
- @node-change="dragHandle.onNodeChange"
508
- >
509
- <!-- Plus: insert block via slash menu -->
510
- <UButton
511
- icon="i-lucide-plus"
512
- color="neutral"
513
- variant="ghost"
514
- size="sm"
515
- :class="ui.handle()"
516
- @click="(e) => onPlusClick(e, onClick)"
557
+ <!-- ── Emoji menu (`:` trigger) ───────────────────────────────────── -->
558
+ <UEditorEmojiMenu
559
+ :editor="editor"
560
+ :items="emojiItems"
561
+ />
562
+
563
+ <!-- ── Mention menu (`@` trigger) — users + docs + plugin providers ── -->
564
+ <UEditorMentionMenu
565
+ :editor="editor"
566
+ :items="mentionItems"
517
567
  />
518
568
 
519
- <!-- Grip: block context menu -->
520
- <UDropdownMenu
521
- v-slot="{ open }"
522
- :modal="false"
523
- :items="dragHandle.getItems(editor)"
524
- :content="{ side: 'left' }"
525
- :ui="{ content: 'w-48', label: 'text-xs' }"
526
- @update:open="(v) => editor.chain().setMeta('lockDragHandle', v).run()"
569
+ <!-- ── Drag handle plus button + grip dropdown ───────────────────── -->
570
+ <UEditorDragHandle
571
+ v-if="showDragHandle"
572
+ v-slot="{ ui, onClick }"
573
+ :editor="editor"
574
+ @node-change="dragHandle.onNodeChange"
527
575
  >
576
+ <!-- Plus: insert block via slash menu -->
528
577
  <UButton
578
+ icon="i-lucide-plus"
529
579
  color="neutral"
530
580
  variant="ghost"
531
- :active-variant="'soft'"
532
581
  size="sm"
533
- icon="i-lucide-grip-vertical"
534
- :active="open"
535
582
  :class="ui.handle()"
583
+ @click="(e) => onPlusClick(e, onClick)"
536
584
  />
537
- </UDropdownMenu>
538
- </UEditorDragHandle>
539
- </slot>
540
- </UEditor>
585
+
586
+ <!-- Grip: block context menu -->
587
+ <UDropdownMenu
588
+ v-slot="{ open }"
589
+ :modal="false"
590
+ :items="dragHandle.getItems(editor)"
591
+ :content="{ side: 'left' }"
592
+ :ui="{ content: 'w-48', label: 'text-xs' }"
593
+ @update:open="(v) => editor.chain().setMeta('lockDragHandle', v).run()"
594
+ >
595
+ <UButton
596
+ color="neutral"
597
+ variant="ghost"
598
+ :active-variant="'soft'"
599
+ size="sm"
600
+ icon="i-lucide-grip-vertical"
601
+ :active="open"
602
+ :class="ui.handle()"
603
+ />
604
+ </UDropdownMenu>
605
+ </UEditorDragHandle>
606
+ </slot>
607
+ </UEditor>
608
+ </div>
541
609
 
542
610
  <template #fallback>
543
611
  <div
@@ -553,5 +621,5 @@ function onPlusClick(e, onClick) {
553
621
  </template>
554
622
 
555
623
  <style scoped>
556
- .prose-variant :deep(.tiptap){color:var(--ui-text);font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;font-size:1.0625rem;line-height:1.75}.prose-variant :deep(.tiptap p){margin-bottom:1em;margin-top:0}.prose-variant :deep(.tiptap h1),.prose-variant :deep(.tiptap h2),.prose-variant :deep(.tiptap h3),.prose-variant :deep(.tiptap h4){font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;letter-spacing:-.01em;line-height:1.25;margin-bottom:.5em;margin-top:1.75em}.prose-variant :deep(.tiptap h1){font-size:2rem;font-weight:700}.prose-variant :deep(.tiptap h2){font-size:1.5rem;font-weight:700}.prose-variant :deep(.tiptap h3){font-size:1.25rem;font-weight:600}.prose-variant :deep(.tiptap blockquote){border-left:3px solid var(--ui-border);color:var(--ui-text-muted);font-style:italic;margin-left:0;padding-left:1em}.prose-variant :deep(.tiptap ol),.prose-variant :deep(.tiptap ul){margin-bottom:1em;padding-left:1.5em}.prose-variant :deep(.tiptap .document-header){font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;font-size:2.75rem;font-weight:700;letter-spacing:-.02em;line-height:1.15;margin-bottom:1.5rem}.aeditor-source-wrap{display:flex;flex:1 1 0;flex-direction:column;min-height:0}.aeditor-source-toolbar{align-items:center;background:var(--ui-bg);border-bottom:1px solid var(--ui-border);display:flex;flex-shrink:0;justify-content:space-between;padding:.375rem .75rem}.aeditor-source-toolbar__label{align-items:center;color:var(--ui-text-muted);display:inline-flex;font-size:.75rem;gap:.375rem}.aeditor-source-toolbar__label code{background:var(--ui-bg-elevated);border:1px solid var(--ui-border);border-radius:var(--ui-radius);font-family:ui-monospace,SF Mono,Menlo,Monaco,Consolas,monospace;font-size:.7rem;padding:.05rem .3rem}.aeditor-source-toggle{opacity:.6;position:absolute;right:.375rem;top:.375rem;transition:opacity .12s ease;z-index:5}.aeditor-source-toggle:hover{opacity:1}
624
+ .aeditor-canvas{display:flex;flex-direction:column;min-height:0}.aeditor-breadcrumb{flex-shrink:0;padding:.75rem 1rem 0}@media (min-width:640px){.aeditor-breadcrumb{padding-left:1.5rem;padding-right:1.5rem}}.prose-variant :deep(.tiptap){color:var(--ui-text);font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;font-size:1.0625rem;line-height:1.75}.prose-variant :deep(.tiptap p){margin-bottom:1em;margin-top:0}.prose-variant :deep(.tiptap h1),.prose-variant :deep(.tiptap h2),.prose-variant :deep(.tiptap h3),.prose-variant :deep(.tiptap h4){font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;letter-spacing:-.01em;line-height:1.25;margin-bottom:.5em;margin-top:1.75em}.prose-variant :deep(.tiptap h1){font-size:2rem;font-weight:700}.prose-variant :deep(.tiptap h2){font-size:1.5rem;font-weight:700}.prose-variant :deep(.tiptap h3){font-size:1.25rem;font-weight:600}.prose-variant :deep(.tiptap blockquote){border-left:3px solid var(--ui-border);color:var(--ui-text-muted);font-style:italic;margin-left:0;padding-left:1em}.prose-variant :deep(.tiptap ol),.prose-variant :deep(.tiptap ul){margin-bottom:1em;padding-left:1.5em}.prose-variant :deep(.tiptap .document-header){font-family:ui-serif,Georgia,Cambria,Times New Roman,Times,serif;font-size:2.75rem;font-weight:700;letter-spacing:-.02em;line-height:1.15;margin-bottom:1.5rem}.aeditor-source-wrap{display:flex;flex:1 1 0;flex-direction:column;min-height:0}.aeditor-source-toolbar{align-items:center;background:var(--ui-bg);border-bottom:1px solid var(--ui-border);display:flex;flex-shrink:0;justify-content:space-between;padding:.375rem .75rem}.aeditor-source-toolbar__label{align-items:center;color:var(--ui-text-muted);display:inline-flex;font-size:.75rem;gap:.375rem}.aeditor-source-toolbar__label code{background:var(--ui-bg-elevated);border:1px solid var(--ui-border);border-radius:var(--ui-radius);font-family:ui-monospace,SF Mono,Menlo,Monaco,Consolas,monospace;font-size:.7rem;padding:.05rem .3rem}.aeditor-source-toggle{opacity:.6;position:absolute;right:.375rem;top:.375rem;transition:opacity .12s ease;z-index:5}.aeditor-source-toggle:hover{opacity:1}
557
625
  </style>
@@ -35,12 +35,18 @@ type __VLS_Props = {
35
35
  * Useful for inspecting CRDT state during development. Default: false.
36
36
  */
37
37
  showSourceToggle?: boolean;
38
+ /**
39
+ * Show the in-canvas ancestor breadcrumb above the document (matching
40
+ * cou-sh's DocRenderer). Only renders when the doc actually has ancestors,
41
+ * so root/space docs show nothing. Set false for embeds/previews.
42
+ */
43
+ showBreadcrumb?: boolean;
38
44
  };
39
45
  type __VLS_ModelProps = {
40
46
  modelValue?: any;
41
47
  };
42
48
  type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
43
- declare var __VLS_42: {
49
+ declare var __VLS_58: {
44
50
  editor: any;
45
51
  connectedUsers: {
46
52
  name: string;
@@ -49,25 +55,25 @@ declare var __VLS_42: {
49
55
  docId?: string | undefined;
50
56
  }[];
51
57
  ready: boolean;
52
- }, __VLS_51: {
58
+ }, __VLS_67: {
53
59
  editor: any;
54
- }, __VLS_59: {
60
+ }, __VLS_75: {
55
61
  editor: any;
56
- }, __VLS_67: {
62
+ }, __VLS_83: {
57
63
  editor: any;
58
- }, __VLS_70: {
64
+ }, __VLS_86: {
59
65
  editor: any;
60
66
  };
61
67
  type __VLS_Slots = {} & {
62
- default?: (props: typeof __VLS_42) => any;
68
+ default?: (props: typeof __VLS_58) => any;
63
69
  } & {
64
- link?: (props: typeof __VLS_51) => any;
70
+ link?: (props: typeof __VLS_67) => any;
65
71
  } & {
66
- 'doc-link'?: (props: typeof __VLS_59) => any;
72
+ 'doc-link'?: (props: typeof __VLS_75) => any;
67
73
  } & {
68
- 'create-child-doc'?: (props: typeof __VLS_67) => any;
74
+ 'create-child-doc'?: (props: typeof __VLS_83) => any;
69
75
  } & {
70
- 'send-to-chat'?: (props: typeof __VLS_70) => any;
76
+ 'send-to-chat'?: (props: typeof __VLS_86) => any;
71
77
  };
72
78
  declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
73
79
  editor: import("vue").ComputedRef<any>;
@@ -91,6 +97,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
91
97
  showDragHandle: boolean;
92
98
  variant: "doc" | "prose";
93
99
  showSourceToggle: boolean;
100
+ showBreadcrumb: boolean;
94
101
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
95
102
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
96
103
  declare const _default: typeof __VLS_export;
@@ -16,12 +16,20 @@ type __VLS_Props = {
16
16
  * slots are unaffected.
17
17
  */
18
18
  tabs?: Array<'editor' | 'properties' | 'chat' | 'settings' | 'serverSettings'>;
19
+ /**
20
+ * Build the URL the "open as full page" (expand) button navigates to.
21
+ * Defaults to a slug-aware path derived from the configured `docBasePath`
22
+ * (`useDocSlugs().getDocUrl`), which resolves to the doc's slug when it has
23
+ * one and falls back to the raw id. Override to target a custom route shape.
24
+ */
25
+ docHref?: (id: string) => string;
19
26
  };
20
27
  declare var __VLS_11: {
21
28
  nodeId: string | null;
22
- nodeLabel: string | undefined;
29
+ nodeLabel: any;
23
30
  editor: any;
24
31
  meta: DocPageMeta;
32
+ activeTab: string;
25
33
  docTypeDef: import("../utils/docTypes.js").DocTypeDefinition;
26
34
  };
27
35
  type __VLS_Slots = {} & {