@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
@@ -138,6 +138,19 @@ export const DOC_TYPES = {
138
138
  () => import("../components/renderers/ATableRenderer.vue")
139
139
  )
140
140
  },
141
+ sheets: {
142
+ key: "sheets",
143
+ label: "Sheets",
144
+ icon: "i-lucide-grid-3x3",
145
+ description: "Spreadsheet \u2014 cells, formulas, and formatting in a collaborative grid",
146
+ available: true,
147
+ supportsChildren: true,
148
+ childLabel: "Column",
149
+ grandchildLabel: "Cell",
150
+ component: defineDocComponent(
151
+ () => import("../components/renderers/ASheetsRenderer.client.vue")
152
+ )
153
+ },
141
154
  outline: {
142
155
  key: "outline",
143
156
  label: "Outline",
@@ -226,6 +239,24 @@ export const DOC_TYPES = {
226
239
  () => import("../components/renderers/AGraphRenderer.vue")
227
240
  )
228
241
  },
242
+ chart: {
243
+ key: "chart",
244
+ label: "Chart",
245
+ icon: "i-lucide-bar-chart-3",
246
+ description: "Charts \u2014 manual data points or aggregation over document trees",
247
+ available: true,
248
+ supportsChildren: true,
249
+ childLabel: "Data Point",
250
+ grandchildLabel: "Data Point",
251
+ component: defineDocComponent(
252
+ () => import("../components/renderers/AChartRenderer.client.vue")
253
+ ),
254
+ metaSchema: [
255
+ { type: "number", key: "number", step: 0.01, label: "Value" },
256
+ { type: "colorPreset", key: "color", presets: ["#6366f1", "#ec4899", "#f97316", "#22c55e", "#3b82f6", "#a855f7", "#14b8a6", "#eab308"], label: "Color" },
257
+ { type: "tags", key: "tags", label: "Tags" }
258
+ ]
259
+ },
229
260
  dashboard: {
230
261
  key: "dashboard",
231
262
  label: "Dashboard",
@@ -271,6 +302,18 @@ export const DOC_TYPES = {
271
302
  { type: "select", key: "slidesTransition", options: ["none", "fade", "slide"], label: "Transition" },
272
303
  { type: "colorPreset", key: "color", presets: ["#6366f1", "#ec4899", "#f97316", "#22c55e", "#3b82f6", "#a855f7"], label: "Accent" }
273
304
  ]
305
+ },
306
+ overview: {
307
+ key: "overview",
308
+ label: "Overview",
309
+ icon: "i-lucide-radar",
310
+ description: "Space home \u2014 activity, people, stats, and health at a glance",
311
+ available: true,
312
+ supportsChildren: true,
313
+ childLabel: "Page",
314
+ component: defineDocComponent(
315
+ () => import("../components/renderers/AOverviewRenderer.vue")
316
+ )
274
317
  }
275
318
  };
276
319
  export const DEFAULT_DOC_TYPE = DOC_TYPES.doc;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * titleSync — pure decision logic for keeping the H1 documentHeader and the
3
+ * tree-entry `label` field in agreement, plus a defensive `setHeaderText`.
4
+ *
5
+ * The two sources of truth are:
6
+ * - the `documentHeader` Y.XmlElement inside the child doc's Y.XmlFragment
7
+ * (rendered by TipTap as the H1 at the top of the page);
8
+ * - the `label` field on the doc's tree entry in the root provider's treeMap
9
+ * (rendered by the sidebar, breadcrumb, browser title, etc.).
10
+ *
11
+ * Past regressions in this area lost user titles because:
12
+ * - the editor mounted on an empty Y.XmlFragment, y-prosemirror seeded an
13
+ * empty documentHeader, then the server snapshot arrived with the real
14
+ * title and the local empty got merged in — sometimes winning the
15
+ * "canonical pick" inside enforceDocumentShape;
16
+ * - the post-sync flow only wrote header → tree on LOCAL updates, so a
17
+ * server-delivered title never reflected back into the tree label and the
18
+ * sidebar stayed stuck on "Untitled";
19
+ * - the tree-label → header watcher unconditionally called
20
+ * `setHeaderText(editor, newLabel || '')`, which on a transient
21
+ * `newLabel = undefined` would erase the user's title.
22
+ *
23
+ * `decideTitleSync` is the canonical answer for "what should I do given the
24
+ * current state of both sides?", returning one of three actions. It is pure
25
+ * so it can be exhaustively table-tested.
26
+ *
27
+ * `setHeaderText` is the only sanctioned way for the renderer to write into
28
+ * the documentHeader. It refuses to overwrite a non-empty header with an
29
+ * empty string unless the caller passes `force: true`.
30
+ *
31
+ * Ported 1:1 from cou-sh/app/utils/titleSync.ts.
32
+ */
33
+ /** Sentinel placeholder label used by the tree when no real label has been set. */
34
+ export declare const UNTITLED = "Untitled";
35
+ /**
36
+ * The tree label is "empty" — meaning it carries no user-supplied title —
37
+ * when it's the empty string, null/undefined, or the literal placeholder
38
+ * `"Untitled"`. The two former cases come from a freshly-created tree row
39
+ * (no label yet); the latter comes from `useChildTree.renameEntry`
40
+ * canonicalising a cleared title to `"Untitled"` so the UI never has to
41
+ * render `null`.
42
+ */
43
+ export declare function isEmptyTreeLabel(label: string | null | undefined): boolean;
44
+ export type TitleSyncAction = {
45
+ kind: 'noop';
46
+ } | {
47
+ kind: 'header-from-tree';
48
+ text: string;
49
+ } | {
50
+ kind: 'tree-from-header';
51
+ label: string;
52
+ };
53
+ export interface TitleSyncInput {
54
+ /** Text content of the `documentHeader` node (what TipTap renders). */
55
+ headerText: string;
56
+ /**
57
+ * Current tree-entry label, or null/undefined if the entry hasn't loaded.
58
+ * Caller is expected to fall back to `props.docLabel` before passing in.
59
+ */
60
+ treeLabel: string | null | undefined;
61
+ /**
62
+ * True when the originating ProseMirror transaction was driven by a Yjs
63
+ * remote update (i.e. `transaction.getMeta('y-sync$')?.isChangeOrigin`).
64
+ * Used to disambiguate "the user just typed this" from "the server told
65
+ * us this".
66
+ */
67
+ isRemoteUpdate: boolean;
68
+ /**
69
+ * Whether `syncHeader` has already performed its first-mount reconciliation
70
+ * for this editor instance. Set by the caller; the first call must pass
71
+ * `false` and every subsequent call must pass `true`.
72
+ */
73
+ initialSyncDone: boolean;
74
+ }
75
+ /**
76
+ * Decide what (if anything) needs to change to keep the header and the tree
77
+ * label in agreement.
78
+ *
79
+ * The truth table — every cell is pinned by `test/title-sync-decision.test.ts`:
80
+ *
81
+ * ┌──────────────┬───────────────────┬───────────────────────────────────────┐
82
+ * │ headerText │ treeLabel │ result │
83
+ * ├──────────────┼───────────────────┼───────────────────────────────────────┤
84
+ * │ empty │ empty/Untitled │ noop (no information either way) │
85
+ * │ same │ same │ noop │
86
+ * │ has text │ empty/Untitled │ tree-from-header (RESCUE — incl. │
87
+ * │ │ │ remote: server delivered the title │
88
+ * │ │ │ via the doc fragment, tree needs │
89
+ * │ │ │ to catch up) │
90
+ * │ empty │ has text │ initial OR remote → header-from-tree │
91
+ * │ │ │ local + post-initial → tree-from- │
92
+ * │ │ │ header('Untitled') (user emptied │
93
+ * │ │ │ the title, so canonicalise) │
94
+ * │ different │ different │ initial OR local → tree-from-header │
95
+ * │ │ │ remote + post-initial → noop (the │
96
+ * │ │ │ label watcher reconciles header │
97
+ * │ │ │ from tree if needed) │
98
+ * └──────────────┴───────────────────┴───────────────────────────────────────┘
99
+ */
100
+ export declare function decideTitleSync(input: TitleSyncInput): TitleSyncAction;
101
+ export interface SetHeaderTextOptions {
102
+ /**
103
+ * Allow overwriting a non-empty `documentHeader` with an empty string.
104
+ * Default `false`. The watcher on the tree label MUST NOT pass `true` — a
105
+ * transient `newLabel = undefined` during reload would otherwise erase the
106
+ * user's title. Setting `force: true` is reserved for the explicit "user
107
+ * emptied the title locally" path.
108
+ */
109
+ force?: boolean;
110
+ }
111
+ /**
112
+ * Replace the inline text content of the first `documentHeader` node in
113
+ * `ed.state.doc`. Refuses the write when:
114
+ * - there is no documentHeader at index 0;
115
+ * - the header already has the requested text (cheap no-op);
116
+ * - the user's selection is inside the header (an external sync echo must
117
+ * never clobber in-flight typing);
118
+ * - `text` is empty AND the existing header is non-empty AND `force`
119
+ * wasn't passed (the no-destroy invariant).
120
+ *
121
+ * Returns `true` if a transaction was dispatched, `false` otherwise. Used
122
+ * by tests to assert the no-destroy invariant.
123
+ */
124
+ export declare function setHeaderText(ed: {
125
+ state: any;
126
+ view: {
127
+ dispatch: (tr: any) => void;
128
+ hasFocus?: () => boolean;
129
+ };
130
+ }, text: string, opts?: SetHeaderTextOptions): boolean;
@@ -0,0 +1,53 @@
1
+ import { Fragment } from "@tiptap/pm/model";
2
+ export const UNTITLED = "Untitled";
3
+ export function isEmptyTreeLabel(label) {
4
+ return !label || label === UNTITLED;
5
+ }
6
+ export function decideTitleSync(input) {
7
+ const { headerText, treeLabel, isRemoteUpdate, initialSyncDone } = input;
8
+ const treeEmpty = isEmptyTreeLabel(treeLabel);
9
+ const headerEmpty = isEmptyTreeLabel(headerText);
10
+ if (treeEmpty && headerEmpty) return { kind: "noop" };
11
+ if (!headerEmpty && !treeEmpty && headerText === treeLabel) {
12
+ return { kind: "noop" };
13
+ }
14
+ if (!headerEmpty && treeEmpty) {
15
+ return { kind: "tree-from-header", label: headerText };
16
+ }
17
+ if (headerEmpty && !treeEmpty) {
18
+ if (!initialSyncDone) {
19
+ return { kind: "header-from-tree", text: treeLabel };
20
+ }
21
+ if (isRemoteUpdate) {
22
+ return { kind: "header-from-tree", text: treeLabel };
23
+ }
24
+ return { kind: "noop" };
25
+ }
26
+ if (!initialSyncDone) {
27
+ return { kind: "tree-from-header", label: headerText };
28
+ }
29
+ if (!isRemoteUpdate) {
30
+ return { kind: "tree-from-header", label: headerText };
31
+ }
32
+ return { kind: "noop" };
33
+ }
34
+ export function setHeaderText(ed, text, opts = {}) {
35
+ const first = ed.state.doc.firstChild;
36
+ if (!first || first.type.name !== "documentHeader") return false;
37
+ if (first.textContent === text) return false;
38
+ const hasFocus = typeof ed.view.hasFocus === "function" ? ed.view.hasFocus() : false;
39
+ if (hasFocus) {
40
+ const { $head } = ed.state.selection;
41
+ if ($head?.parent?.type?.name === "documentHeader") return false;
42
+ }
43
+ if (!text && first.textContent && !opts.force) return false;
44
+ const { tr, schema } = ed.state;
45
+ const to = 1 + first.content.size;
46
+ if (text) {
47
+ tr.replaceWith(1, to, schema.text(text));
48
+ } else {
49
+ tr.replaceWith(1, to, Fragment.empty);
50
+ }
51
+ ed.view.dispatch(tr);
52
+ return true;
53
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abraca/nuxt",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "First-class Nuxt module for the Abracadabra CRDT collaboration platform",
5
5
  "repository": "abracadabra/abracadabra-nuxt",
6
6
  "license": "MIT",
@@ -70,6 +70,8 @@
70
70
  "@tiptap/extension-text-style": "^3.0.0",
71
71
  "@tiptap/starter-kit": "^3.0.0",
72
72
  "@tiptap/vue-3": "^3.0.0",
73
+ "@unovis/ts": "^1.6.5",
74
+ "@unovis/vue": "^1.6.5",
73
75
  "d3-force": "^3.0.0",
74
76
  "jszip": "^3.0.0",
75
77
  "lowlight": "^3.0.0",
@@ -131,6 +133,12 @@
131
133
  },
132
134
  "@tiptap/extension-emoji": {
133
135
  "optional": true
136
+ },
137
+ "@unovis/vue": {
138
+ "optional": true
139
+ },
140
+ "@unovis/ts": {
141
+ "optional": true
134
142
  }
135
143
  },
136
144
  "devDependencies": {
@@ -163,6 +171,8 @@
163
171
  "@types/d3-force": "^3.0.10",
164
172
  "@types/node": "latest",
165
173
  "@types/ws": "^8.18.1",
174
+ "@unovis/ts": "^1.6.5",
175
+ "@unovis/vue": "^1.6.5",
166
176
  "@vue/test-utils": "^2.4.10",
167
177
  "changelogen": "^0.6.2",
168
178
  "d3-force": "^3.0.0",