@abraca/nuxt 2.0.11 → 2.3.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 (130) hide show
  1. package/dist/module.d.mts +68 -0
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +99 -4
  4. package/dist/runtime/components/ACodeEditor.d.vue.ts +26 -0
  5. package/dist/runtime/components/ACodeEditor.vue +268 -0
  6. package/dist/runtime/components/ACodeEditor.vue.d.ts +26 -0
  7. package/dist/runtime/components/ADocumentTree.vue +52 -20
  8. package/dist/runtime/components/AEditor.d.vue.ts +20 -13
  9. package/dist/runtime/components/AEditor.vue +55 -2
  10. package/dist/runtime/components/AEditor.vue.d.ts +20 -13
  11. package/dist/runtime/components/ANodePanel.vue +64 -60
  12. package/dist/runtime/components/ANotificationBell.d.vue.ts +1 -1
  13. package/dist/runtime/components/ANotificationBell.vue.d.ts +1 -1
  14. package/dist/runtime/components/ASpaceFormModal.d.vue.ts +2 -2
  15. package/dist/runtime/components/ASpaceFormModal.vue.d.ts +2 -2
  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/aware/APresenceBlobs.d.vue.ts +29 -1
  19. package/dist/runtime/components/aware/APresenceBlobs.vue +54 -8
  20. package/dist/runtime/components/aware/APresenceBlobs.vue.d.ts +29 -1
  21. package/dist/runtime/components/aware/APresenceCursors.d.vue.ts +11 -0
  22. package/dist/runtime/components/aware/APresenceCursors.vue +74 -9
  23. package/dist/runtime/components/aware/APresenceCursors.vue.d.ts +11 -0
  24. package/dist/runtime/components/aware/AToggleGroup.d.vue.ts +28 -13
  25. package/dist/runtime/components/aware/AToggleGroup.vue +56 -20
  26. package/dist/runtime/components/aware/AToggleGroup.vue.d.ts +28 -13
  27. package/dist/runtime/components/docs/ADocsNavigation.d.vue.ts +1 -1
  28. package/dist/runtime/components/docs/ADocsNavigation.vue.d.ts +1 -1
  29. package/dist/runtime/components/docs/ADocsSearch.d.vue.ts +1 -1
  30. package/dist/runtime/components/docs/ADocsSearch.vue.d.ts +1 -1
  31. package/dist/runtime/components/docs/ADocsSearchButton.d.vue.ts +1 -1
  32. package/dist/runtime/components/docs/ADocsSearchButton.vue.d.ts +1 -1
  33. package/dist/runtime/components/docs/ADocsToc.d.vue.ts +2 -2
  34. package/dist/runtime/components/docs/ADocsToc.vue.d.ts +2 -2
  35. package/dist/runtime/components/editor/AEditorRedoButton.d.vue.ts +1 -1
  36. package/dist/runtime/components/editor/AEditorRedoButton.vue.d.ts +1 -1
  37. package/dist/runtime/components/editor/AEditorUndoButton.d.vue.ts +1 -1
  38. package/dist/runtime/components/editor/AEditorUndoButton.vue.d.ts +1 -1
  39. package/dist/runtime/components/editor/ANodeInlineLabel.d.vue.ts +1 -1
  40. package/dist/runtime/components/editor/ANodeInlineLabel.vue.d.ts +1 -1
  41. package/dist/runtime/components/registry/APluginBrowser.d.vue.ts +23 -0
  42. package/dist/runtime/components/registry/APluginBrowser.vue +155 -0
  43. package/dist/runtime/components/registry/APluginBrowser.vue.d.ts +23 -0
  44. package/dist/runtime/components/registry/APluginCapabilityDialog.d.vue.ts +17 -0
  45. package/dist/runtime/components/registry/APluginCapabilityDialog.vue +159 -0
  46. package/dist/runtime/components/registry/APluginCapabilityDialog.vue.d.ts +17 -0
  47. package/dist/runtime/components/registry/APluginCard.d.vue.ts +20 -0
  48. package/dist/runtime/components/registry/APluginCard.vue +91 -0
  49. package/dist/runtime/components/registry/APluginCard.vue.d.ts +20 -0
  50. package/dist/runtime/components/registry/APluginDetail.d.vue.ts +18 -0
  51. package/dist/runtime/components/registry/APluginDetail.vue +252 -0
  52. package/dist/runtime/components/registry/APluginDetail.vue.d.ts +18 -0
  53. package/dist/runtime/components/renderers/ACodeRenderer.d.vue.ts +15 -0
  54. package/dist/runtime/components/renderers/ACodeRenderer.vue +68 -0
  55. package/dist/runtime/components/renderers/ACodeRenderer.vue.d.ts +15 -0
  56. package/dist/runtime/components/renderers/AGraphRenderer.vue +416 -120
  57. package/dist/runtime/components/renderers/AProseRenderer.d.vue.ts +2 -2
  58. package/dist/runtime/components/renderers/AProseRenderer.vue.d.ts +2 -2
  59. package/dist/runtime/components/shell/ABreadcrumbForDoc.d.vue.ts +11 -0
  60. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue +16 -0
  61. package/dist/runtime/components/shell/ABreadcrumbForDoc.vue.d.ts +11 -0
  62. package/dist/runtime/components/shell/ASettingsSection.d.vue.ts +35 -0
  63. package/dist/runtime/components/shell/ASettingsSection.vue +26 -0
  64. package/dist/runtime/components/shell/ASettingsSection.vue.d.ts +35 -0
  65. package/dist/runtime/components/shell/ASidebar.d.vue.ts +1 -1
  66. package/dist/runtime/components/shell/ASidebar.vue.d.ts +1 -1
  67. package/dist/runtime/components/shell/AUserMenu.d.vue.ts +5 -2
  68. package/dist/runtime/components/shell/AUserMenu.vue +4 -0
  69. package/dist/runtime/components/shell/AUserMenu.vue.d.ts +5 -2
  70. package/dist/runtime/composables/useAbracadabraSchema.d.ts +83 -0
  71. package/dist/runtime/composables/useAbracadabraSchema.js +52 -0
  72. package/dist/runtime/composables/useAggregatedPresence.d.ts +1 -6
  73. package/dist/runtime/composables/useCalendarView.d.ts +1 -1
  74. package/dist/runtime/composables/useChat.js +1 -0
  75. package/dist/runtime/composables/useDocBreadcrumb.d.ts +21 -0
  76. package/dist/runtime/composables/useDocBreadcrumb.js +33 -0
  77. package/dist/runtime/composables/useDocEntryTyped.d.ts +60 -0
  78. package/dist/runtime/composables/useDocEntryTyped.js +70 -0
  79. package/dist/runtime/composables/useEditorDragHandle.js +18 -0
  80. package/dist/runtime/composables/useEditorSuggestions.js +2 -1
  81. package/dist/runtime/composables/useInstalledPlugins.d.ts +3 -21
  82. package/dist/runtime/composables/useInstalledPlugins.js +2 -12
  83. package/dist/runtime/composables/useMetaMenuItems.d.ts +21 -0
  84. package/dist/runtime/composables/useMetaMenuItems.js +115 -0
  85. package/dist/runtime/composables/useMetaValidator.d.ts +27 -0
  86. package/dist/runtime/composables/useMetaValidator.js +10 -0
  87. package/dist/runtime/composables/usePluginCatalog.d.ts +161 -0
  88. package/dist/runtime/composables/usePluginCatalog.js +234 -0
  89. package/dist/runtime/composables/useQuery.d.ts +79 -0
  90. package/dist/runtime/composables/useQuery.js +97 -0
  91. package/dist/runtime/composables/useSpaces.js +4 -5
  92. package/dist/runtime/composables/useTableView.d.ts +3 -3
  93. package/dist/runtime/composables/useTypedDoc.d.ts +97 -0
  94. package/dist/runtime/composables/useTypedDoc.js +114 -0
  95. package/dist/runtime/composables/useWebRTC.js +44 -5
  96. package/dist/runtime/extensions/document-meta.js +5 -0
  97. package/dist/runtime/extensions/timeline.d.ts +11 -0
  98. package/dist/runtime/extensions/timeline.js +52 -0
  99. package/dist/runtime/extensions/views/DocumentMetaView.d.vue.ts +4 -0
  100. package/dist/runtime/extensions/views/DocumentMetaView.vue +63 -0
  101. package/dist/runtime/extensions/views/DocumentMetaView.vue.d.ts +4 -0
  102. package/dist/runtime/extensions/views/TimelineItemView.d.vue.ts +4 -0
  103. package/dist/runtime/extensions/views/TimelineItemView.vue +131 -0
  104. package/dist/runtime/extensions/views/TimelineItemView.vue.d.ts +4 -0
  105. package/dist/runtime/extensions/views/TimelineView.d.vue.ts +9 -0
  106. package/dist/runtime/extensions/views/TimelineView.vue +29 -0
  107. package/dist/runtime/extensions/views/TimelineView.vue.d.ts +9 -0
  108. package/dist/runtime/locale.d.ts +2 -0
  109. package/dist/runtime/locale.js +2 -0
  110. package/dist/runtime/plugin-abracadabra.client.js +107 -6
  111. package/dist/runtime/plugin-registry.d.ts +11 -30
  112. package/dist/runtime/plugin-registry.js +2 -82
  113. package/dist/runtime/plugins/core.plugin.js +10 -4
  114. package/dist/runtime/server/api/_abracadabra/spaces.get.d.ts +1 -1
  115. package/dist/runtime/server/plugins/abracadabra-service.js +28 -0
  116. package/dist/runtime/server/utils/docCache.js +24 -3
  117. package/dist/runtime/server/utils/schemaServerSupport.d.ts +52 -0
  118. package/dist/runtime/server/utils/schemaServerSupport.js +51 -0
  119. package/dist/runtime/types.d.ts +63 -46
  120. package/dist/runtime/utils/docTypes.d.ts +15 -0
  121. package/dist/runtime/utils/docTypes.js +20 -0
  122. package/dist/runtime/utils/loadCodeMirror.d.ts +32 -0
  123. package/dist/runtime/utils/loadCodeMirror.js +65 -0
  124. package/dist/runtime/utils/markdownToYjs.d.ts +1 -23
  125. package/dist/runtime/utils/markdownToYjs.js +5 -440
  126. package/dist/runtime/utils/schemaSupport.d.ts +60 -0
  127. package/dist/runtime/utils/schemaSupport.js +40 -0
  128. package/dist/runtime/utils/yjsConvert.d.ts +1 -14
  129. package/dist/runtime/utils/yjsConvert.js +5 -331
  130. package/package.json +84 -23
@@ -1,16 +1,30 @@
1
1
  <script setup>
2
2
  import { computed, onBeforeUnmount, onMounted, ref } from "vue";
3
- import { useRoute } from "#imports";
3
+ import { useRoute, useNuxtApp } from "#imports";
4
4
  import { useAAEphemeral } from "../../composables/useAAEphemeral";
5
+ import { useAwarenessOf } from "../../composables/useYDoc";
5
6
  import { elementFromPath } from "../../utils/domPath";
6
- const { peers } = useAAEphemeral("aa:focus");
7
+ const props = defineProps({
8
+ coords: { type: String, required: false, default: "viewport" },
9
+ worldChannel: { type: String, required: false, default: "cursor-pos" },
10
+ toScreen: { type: Function, required: false }
11
+ });
12
+ const { peers: focusPeers } = useAAEphemeral("aa:focus");
7
13
  const route = useRoute();
14
+ const { provider } = useNuxtApp().$abracadabra;
15
+ const { states: worldStates } = useAwarenessOf(provider);
8
16
  const tick = ref(0);
9
17
  const blobs = computed(() => {
10
18
  tick.value;
11
19
  if (typeof window === "undefined") return [];
20
+ if (props.coords === "world") {
21
+ return computeWorldBlobs();
22
+ }
23
+ return computeViewportBlobs();
24
+ });
25
+ function computeViewportBlobs() {
12
26
  const out = [];
13
- for (const p of peers.value) {
27
+ for (const p of focusPeers.value) {
14
28
  const v = p.value;
15
29
  if (!v) continue;
16
30
  if (v.route && v.route !== route.path) continue;
@@ -20,13 +34,42 @@ const blobs = computed(() => {
20
34
  const r = el.getBoundingClientRect();
21
35
  const x = r.left + v.pointer.dx;
22
36
  const y = r.top + v.pointer.dy;
23
- const vw = window.innerWidth || document.documentElement.clientWidth;
24
- const vh = window.innerHeight || document.documentElement.clientHeight;
25
- if (x < -180 || y < -180 || x > vw + 180 || y > vh + 180) continue;
37
+ if (isOffscreen(x, y)) continue;
26
38
  out.push({ clientId: p.clientId, user: p.user, x, y });
27
39
  }
28
40
  return out;
29
- });
41
+ }
42
+ function computeWorldBlobs() {
43
+ const toScreen = props.toScreen;
44
+ if (!toScreen) return [];
45
+ const localId = provider.value?.awareness?.clientID;
46
+ const out = [];
47
+ for (const peer of worldStates.value) {
48
+ if (peer.clientId === localId) continue;
49
+ const raw = peer[props.worldChannel];
50
+ if (!raw || typeof raw !== "object") continue;
51
+ const wx = raw.x;
52
+ const wy = raw.y;
53
+ if (typeof wx !== "number" || typeof wy !== "number") continue;
54
+ const projected = toScreen(wx, wy);
55
+ if (!projected) continue;
56
+ if (isOffscreen(projected.x, projected.y)) continue;
57
+ out.push({
58
+ clientId: peer.clientId,
59
+ // useAwarenessOf flattens awareness state onto the peer object, so
60
+ // `user` is at the top level — same shape useAAEphemeral returns.
61
+ user: peer.user,
62
+ x: projected.x,
63
+ y: projected.y
64
+ });
65
+ }
66
+ return out;
67
+ }
68
+ function isOffscreen(x, y) {
69
+ const vw = window.innerWidth || document.documentElement.clientWidth;
70
+ const vh = window.innerHeight || document.documentElement.clientHeight;
71
+ return x < -180 || y < -180 || x > vw + 180 || y > vh + 180;
72
+ }
30
73
  let raf = 0;
31
74
  function bump() {
32
75
  tick.value++;
@@ -39,11 +82,14 @@ function onResize() {
39
82
  tick.value++;
40
83
  }
41
84
  onMounted(() => {
85
+ if (props.coords === "world") {
86
+ raf = requestAnimationFrame(bump);
87
+ }
42
88
  document.addEventListener("scroll", onScroll, { passive: true, capture: true });
43
89
  window.addEventListener("resize", onResize, { passive: true });
44
90
  });
45
91
  onBeforeUnmount(() => {
46
- cancelAnimationFrame(raf);
92
+ if (raf) cancelAnimationFrame(raf);
47
93
  document.removeEventListener("scroll", onScroll, { capture: true });
48
94
  window.removeEventListener("resize", onResize);
49
95
  });
@@ -1,3 +1,31 @@
1
- declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
1
+ type __VLS_Props = {
2
+ /**
3
+ * Coordinate space the blob positions live in.
4
+ * - `viewport` (default): element-anchored peer pointer from `aa:focus`.
5
+ * - `world`: absolute world coords from `state[worldChannel]`, projected
6
+ * into the local viewport via `toScreen`.
7
+ */
8
+ coords?: 'viewport' | 'world';
9
+ /**
10
+ * Awareness state field carrying world coords `{x, y}` per peer. Only used
11
+ * in `coords="world"` mode. Defaults to `'cursor-pos'` to match the
12
+ * playground's map page broadcast.
13
+ */
14
+ worldChannel?: string;
15
+ /**
16
+ * Project a peer's world coordinates into local viewport CSS pixels.
17
+ * Required when `coords="world"`. Return `null` to drop a peer (e.g.
18
+ * because the point falls outside the visible region or the local
19
+ * camera isn't ready yet).
20
+ */
21
+ toScreen?: (worldX: number, worldY: number) => {
22
+ x: number;
23
+ y: number;
24
+ } | null;
25
+ };
26
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
27
+ coords: "viewport" | "world";
28
+ worldChannel: string;
29
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
2
30
  declare const _default: typeof __VLS_export;
3
31
  export default _default;
@@ -2,6 +2,15 @@ type __VLS_Props = {
2
2
  scope: string;
3
3
  /** Max simultaneous peer cursors to render. */
4
4
  max?: number;
5
+ /** Coordinate mode — see component docs. */
6
+ coords?: 'viewport' | 'world';
7
+ /** Awareness field carrying world coords `{x, y}` per peer. World mode only. */
8
+ worldChannel?: string;
9
+ /** Project world → viewport CSS pixels, or `null` to drop the peer. World mode only. */
10
+ toScreen?: (worldX: number, worldY: number) => {
11
+ x: number;
12
+ y: number;
13
+ } | null;
5
14
  };
6
15
  declare var __VLS_1: {};
7
16
  type __VLS_Slots = {} & {
@@ -9,6 +18,8 @@ type __VLS_Slots = {} & {
9
18
  };
10
19
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
11
20
  max: number;
21
+ coords: "viewport" | "world";
22
+ worldChannel: string;
12
23
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
24
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
14
25
  declare const _default: typeof __VLS_export;
@@ -1,21 +1,90 @@
1
1
  <script setup>
2
- import { computed, ref } from "vue";
2
+ import { computed, onBeforeUnmount, onMounted, ref } from "vue";
3
+ import { useNuxtApp } from "#imports";
3
4
  import { useAAPointer } from "../../composables/useAAPointer";
5
+ import { useAwarenessOf } from "../../composables/useYDoc";
4
6
  defineOptions({ inheritAttrs: false });
5
7
  const props = defineProps({
6
8
  scope: { type: String, required: true },
7
- max: { type: Number, required: false, default: 8 }
9
+ max: { type: Number, required: false, default: 8 },
10
+ coords: { type: String, required: false, default: "viewport" },
11
+ worldChannel: { type: String, required: false, default: "cursor-pos" },
12
+ toScreen: { type: Function, required: false }
8
13
  });
9
14
  const hostRef = ref(null);
10
15
  const { pointers } = useAAPointer(() => props.scope, hostRef);
11
- const visible = computed(() => pointers.value.slice(0, props.max));
12
- const overflow = computed(() => Math.max(0, pointers.value.length - visible.value.length));
16
+ const { provider } = useNuxtApp().$abracadabra;
17
+ const { states: worldStates } = useAwarenessOf(provider);
18
+ const tick = ref(0);
19
+ let raf = 0;
20
+ function bump() {
21
+ tick.value++;
22
+ raf = requestAnimationFrame(bump);
23
+ }
24
+ const rendered = computed(() => {
25
+ if (props.coords === "world") {
26
+ tick.value;
27
+ return computeWorldCursors();
28
+ }
29
+ return pointers.value.map((p) => ({
30
+ clientId: p.clientId,
31
+ // Multiply normalised coords by host size at render time so the host
32
+ // can resize without us re-broadcasting; CSS handles it via `%`.
33
+ x: p.x * 100,
34
+ y: p.y * 100,
35
+ user: p.user
36
+ }));
37
+ });
38
+ function computeWorldCursors() {
39
+ const toScreen = props.toScreen;
40
+ const host = hostRef.value;
41
+ if (!toScreen || !host) return [];
42
+ const rect = host.getBoundingClientRect();
43
+ if (rect.width === 0 || rect.height === 0) return [];
44
+ const localId = provider.value?.awareness?.clientID;
45
+ const out = [];
46
+ for (const peer of worldStates.value) {
47
+ if (peer.clientId === localId) continue;
48
+ const raw = peer[props.worldChannel];
49
+ if (!raw || typeof raw !== "object") continue;
50
+ const wx = raw.x;
51
+ const wy = raw.y;
52
+ if (typeof wx !== "number" || typeof wy !== "number") continue;
53
+ const projected = toScreen(wx, wy);
54
+ if (!projected) continue;
55
+ const lx = projected.x - rect.left;
56
+ const ly = projected.y - rect.top;
57
+ out.push({
58
+ clientId: peer.clientId,
59
+ x: lx,
60
+ y: ly,
61
+ user: peer.user
62
+ });
63
+ }
64
+ return out;
65
+ }
66
+ const visible = computed(() => rendered.value.slice(0, props.max));
67
+ const overflow = computed(() => Math.max(0, rendered.value.length - visible.value.length));
13
68
  function colorFor(p) {
14
69
  return p.user?.color || "var(--ui-text-muted)";
15
70
  }
16
71
  function nameFor(p) {
17
72
  return p.user?.name || "Anonymous";
18
73
  }
74
+ function posStyle(c) {
75
+ if (props.coords === "world") {
76
+ return { left: c.x + "px", top: c.y + "px" };
77
+ }
78
+ return { left: c.x + "%", top: c.y + "%" };
79
+ }
80
+ onMounted(() => {
81
+ if (props.coords === "world") {
82
+ raf = requestAnimationFrame(bump);
83
+ }
84
+ });
85
+ onBeforeUnmount(() => {
86
+ if (raf) cancelAnimationFrame(raf);
87
+ });
19
88
  </script>
20
89
 
21
90
  <template>
@@ -26,11 +95,7 @@ function nameFor(p) {
26
95
  v-for="p in visible"
27
96
  :key="p.clientId"
28
97
  class="aa-cursor"
29
- :style="{
30
- left: p.x * 100 + '%',
31
- top: p.y * 100 + '%',
32
- color: colorFor(p)
33
- }"
98
+ :style="{ ...posStyle(p), color: colorFor(p) }"
34
99
  >
35
100
  <svg width="18" height="20" viewBox="0 0 12 16" xmlns="http://www.w3.org/2000/svg">
36
101
  <path d="M0 0 L0 12 L3.5 8.5 L5.5 13.5 L7 13 L5 8 L9 8 Z" fill="currentColor" stroke="white" stroke-width="0.6" stroke-linejoin="round" />
@@ -2,6 +2,15 @@ type __VLS_Props = {
2
2
  scope: string;
3
3
  /** Max simultaneous peer cursors to render. */
4
4
  max?: number;
5
+ /** Coordinate mode — see component docs. */
6
+ coords?: 'viewport' | 'world';
7
+ /** Awareness field carrying world coords `{x, y}` per peer. World mode only. */
8
+ worldChannel?: string;
9
+ /** Project world → viewport CSS pixels, or `null` to drop the peer. World mode only. */
10
+ toScreen?: (worldX: number, worldY: number) => {
11
+ x: number;
12
+ y: number;
13
+ } | null;
5
14
  };
6
15
  declare var __VLS_1: {};
7
16
  type __VLS_Slots = {} & {
@@ -9,6 +18,8 @@ type __VLS_Slots = {} & {
9
18
  };
10
19
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
11
20
  max: number;
21
+ coords: "viewport" | "world";
22
+ worldChannel: string;
12
23
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
13
24
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
14
25
  declare const _default: typeof __VLS_export;
@@ -1,27 +1,42 @@
1
+ interface ToggleItem {
2
+ value: string;
3
+ label?: string;
4
+ icon?: string;
5
+ disabled?: boolean;
6
+ }
1
7
  type __VLS_Props = {
2
8
  fieldKey: string;
9
+ items: ToggleItem[];
10
+ type?: 'single' | 'multiple';
3
11
  awareness?: boolean;
4
12
  sync?: boolean;
5
13
  total?: boolean;
6
14
  max?: number;
15
+ /** Forwarded to each UButton. */
16
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
17
+ /** Variant used for unselected items. Selected items always use `solid`. */
18
+ variant?: 'solid' | 'soft' | 'outline' | 'ghost' | 'subtle' | 'link';
19
+ /** Color used for selected items. */
20
+ color?: 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'neutral';
21
+ /** External v-model — takes precedence over `sync`. */
22
+ modelValue?: string | string[];
23
+ /** Allow deselecting in `single` mode by clicking the active item again. Default: true. */
24
+ allowDeselect?: boolean;
7
25
  };
8
- declare var __VLS_9: string, __VLS_10: any, __VLS_20: string, __VLS_21: any;
9
- type __VLS_Slots = {} & {
10
- [K in NonNullable<typeof __VLS_9>]?: (props: typeof __VLS_10) => any;
11
- } & {
12
- [K in NonNullable<typeof __VLS_20>]?: (props: typeof __VLS_21) => any;
13
- };
14
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
26
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
27
+ "update:modelValue": (value: string | string[]) => any;
28
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
29
+ "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
30
+ }>, {
31
+ color: "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral";
15
32
  sync: boolean;
33
+ type: "single" | "multiple";
16
34
  awareness: boolean;
35
+ size: "xs" | "sm" | "md" | "lg" | "xl";
17
36
  max: number;
37
+ variant: "solid" | "soft" | "outline" | "ghost" | "subtle" | "link";
18
38
  total: boolean;
39
+ allowDeselect: boolean;
19
40
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
- declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
21
41
  declare const _default: typeof __VLS_export;
22
42
  export default _default;
23
- type __VLS_WithSlots<T, S> = T & {
24
- new (): {
25
- $slots: S;
26
- };
27
- };
@@ -6,17 +6,55 @@ import { awareRingStyle } from "../../utils/awareRingStyle";
6
6
  defineOptions({ inheritAttrs: false });
7
7
  const props = defineProps({
8
8
  fieldKey: { type: String, required: true },
9
+ items: { type: Array, required: true },
10
+ type: { type: String, required: false, default: "single" },
9
11
  awareness: { type: Boolean, required: false, default: true },
10
12
  sync: { type: Boolean, required: false, default: false },
11
13
  total: { type: Boolean, required: false, default: false },
12
- max: { type: Number, required: false, default: 3 }
14
+ max: { type: Number, required: false, default: 3 },
15
+ size: { type: String, required: false, default: "sm" },
16
+ variant: { type: String, required: false, default: "soft" },
17
+ color: { type: String, required: false, default: "primary" },
18
+ modelValue: { type: [String, Array], required: false },
19
+ allowDeselect: { type: Boolean, required: false, default: true }
13
20
  });
21
+ const emit = defineEmits(["update:modelValue"]);
14
22
  const enableAwareness = computed(() => props.awareness || props.total);
15
23
  const enableSync = computed(() => props.sync || props.total);
16
24
  const attrs = useAttrs();
17
25
  const { hoverers, focusers, pressers, isPressed, handlers } = useAAField(() => props.fieldKey);
18
26
  const synced = useAAFieldValue(() => props.fieldKey);
19
- const hasExternalModel = computed(() => "modelValue" in attrs || "onUpdate:modelValue" in attrs);
27
+ const hasExternalModel = computed(() => "modelValue" in attrs || props.modelValue !== void 0);
28
+ const driveFromSync = computed(() => enableSync.value && !hasExternalModel.value);
29
+ const current = computed({
30
+ get() {
31
+ if (driveFromSync.value) return synced.value;
32
+ return props.modelValue;
33
+ },
34
+ set(value) {
35
+ if (driveFromSync.value) {
36
+ synced.value = value;
37
+ }
38
+ emit("update:modelValue", value);
39
+ }
40
+ });
41
+ function isActive(value) {
42
+ const v = current.value;
43
+ if (props.type === "multiple") return Array.isArray(v) && v.includes(value);
44
+ return v === value;
45
+ }
46
+ function toggle(value) {
47
+ if (props.type === "multiple") {
48
+ const cur = Array.isArray(current.value) ? current.value : [];
49
+ current.value = cur.includes(value) ? cur.filter((x) => x !== value) : [...cur, value];
50
+ return;
51
+ }
52
+ if (current.value === value) {
53
+ if (props.allowDeselect) current.value = "";
54
+ return;
55
+ }
56
+ current.value = value;
57
+ }
20
58
  const ringStyle = computed(
21
59
  () => enableAwareness.value ? awareRingStyle({
22
60
  hover: hoverers.value[0]?.user?.color,
@@ -48,23 +86,21 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
48
86
  :style="ringStyle"
49
87
  v-on="eventHandlers"
50
88
  >
51
- <UToggleGroup
52
- v-if="enableSync && !hasExternalModel"
53
- v-model="synced"
54
- v-bind="attrs"
55
- >
56
- <template v-for="(_, name) in $slots" #[name]="slotData">
57
- <slot :name="name" v-bind="slotData ?? {}" />
58
- </template>
59
- </UToggleGroup>
60
- <UToggleGroup
61
- v-else
62
- v-bind="attrs"
63
- >
64
- <template v-for="(_, name) in $slots" #[name]="slotData">
65
- <slot :name="name" v-bind="slotData ?? {}" />
66
- </template>
67
- </UToggleGroup>
89
+ <div class="aa-toggle-group" role="group">
90
+ <UButton
91
+ v-for="item in items"
92
+ :key="item.value"
93
+ :icon="item.icon"
94
+ :label="item.label"
95
+ :size="size"
96
+ :variant="isActive(item.value) ? 'solid' : variant"
97
+ :color="isActive(item.value) ? color : 'neutral'"
98
+ :disabled="item.disabled"
99
+ :aria-pressed="isActive(item.value)"
100
+ class="aa-toggle-group__btn"
101
+ @click="toggle(item.value)"
102
+ />
103
+ </div>
68
104
 
69
105
  <Transition name="aa-peer">
70
106
  <span v-if="overlayPeers.length" class="aa-overlay">
@@ -75,5 +111,5 @@ const eventHandlers = computed(() => enableAwareness.value ? handlers : {});
75
111
  </template>
76
112
 
77
113
  <style scoped>
78
- .aa-host{border-radius:var(--ui-radius,.375rem);position:relative;transition:filter .12s ease}.aa-host--inline{display:inline-flex}.aa-host--pressed{filter:brightness(.9)}.aa-overlay{display:flex;pointer-events:none;position:absolute;right:0;top:-.625rem;z-index:10}.aa-overlay>*+*{margin-left:-.25rem}.aa-peer-enter-active,.aa-peer-leave-active{transition:opacity .15s ease}.aa-peer-enter-from,.aa-peer-leave-to{opacity:0}
114
+ .aa-host{border-radius:var(--ui-radius,.375rem);position:relative;transition:filter .12s ease}.aa-host--inline{display:inline-flex}.aa-host--pressed{filter:brightness(.9)}.aa-overlay{display:flex;pointer-events:none;position:absolute;right:0;top:-.625rem;z-index:10}.aa-overlay>*+*{margin-left:-.25rem}.aa-peer-enter-active,.aa-peer-leave-active{transition:opacity .15s ease}.aa-peer-enter-from,.aa-peer-leave-to{opacity:0}.aa-toggle-group{display:inline-flex;isolation:isolate}.aa-toggle-group__btn{border-radius:0;position:relative}.aa-toggle-group__btn:focus-visible,.aa-toggle-group__btn:hover{z-index:1}.aa-toggle-group__btn:first-child{border-bottom-left-radius:var(--ui-radius,.375rem);border-top-left-radius:var(--ui-radius,.375rem)}.aa-toggle-group__btn:last-child{border-bottom-right-radius:var(--ui-radius,.375rem);border-top-right-radius:var(--ui-radius,.375rem)}.aa-toggle-group__btn+.aa-toggle-group__btn{margin-left:-1px}
79
115
  </style>
@@ -1,27 +1,42 @@
1
+ interface ToggleItem {
2
+ value: string;
3
+ label?: string;
4
+ icon?: string;
5
+ disabled?: boolean;
6
+ }
1
7
  type __VLS_Props = {
2
8
  fieldKey: string;
9
+ items: ToggleItem[];
10
+ type?: 'single' | 'multiple';
3
11
  awareness?: boolean;
4
12
  sync?: boolean;
5
13
  total?: boolean;
6
14
  max?: number;
15
+ /** Forwarded to each UButton. */
16
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
17
+ /** Variant used for unselected items. Selected items always use `solid`. */
18
+ variant?: 'solid' | 'soft' | 'outline' | 'ghost' | 'subtle' | 'link';
19
+ /** Color used for selected items. */
20
+ color?: 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'error' | 'neutral';
21
+ /** External v-model — takes precedence over `sync`. */
22
+ modelValue?: string | string[];
23
+ /** Allow deselecting in `single` mode by clicking the active item again. Default: true. */
24
+ allowDeselect?: boolean;
7
25
  };
8
- declare var __VLS_9: string, __VLS_10: any, __VLS_20: string, __VLS_21: any;
9
- type __VLS_Slots = {} & {
10
- [K in NonNullable<typeof __VLS_9>]?: (props: typeof __VLS_10) => any;
11
- } & {
12
- [K in NonNullable<typeof __VLS_20>]?: (props: typeof __VLS_21) => any;
13
- };
14
- declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
26
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
27
+ "update:modelValue": (value: string | string[]) => any;
28
+ }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
29
+ "onUpdate:modelValue"?: ((value: string | string[]) => any) | undefined;
30
+ }>, {
31
+ color: "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral";
15
32
  sync: boolean;
33
+ type: "single" | "multiple";
16
34
  awareness: boolean;
35
+ size: "xs" | "sm" | "md" | "lg" | "xl";
17
36
  max: number;
37
+ variant: "solid" | "soft" | "outline" | "ghost" | "subtle" | "link";
18
38
  total: boolean;
39
+ allowDeselect: boolean;
19
40
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
- declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
21
41
  declare const _default: typeof __VLS_export;
22
42
  export default _default;
23
- type __VLS_WithSlots<T, S> = T & {
24
- new (): {
25
- $slots: S;
26
- };
27
- };
@@ -143,8 +143,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
143
143
  }>, {
144
144
  type: string;
145
145
  disabled: boolean;
146
- level: number;
147
146
  as: any;
147
+ level: number;
148
148
  collapsible: boolean;
149
149
  highlight: boolean;
150
150
  defaultOpen: boolean;
@@ -143,8 +143,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
143
143
  }>, {
144
144
  type: string;
145
145
  disabled: boolean;
146
- level: number;
147
146
  as: any;
147
+ level: number;
148
148
  collapsible: boolean;
149
149
  highlight: boolean;
150
150
  defaultOpen: boolean;
@@ -238,8 +238,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
238
238
  transition: boolean;
239
239
  autofocus: boolean;
240
240
  loading: boolean;
241
- overlay: boolean;
242
241
  colorMode: boolean;
242
+ overlay: boolean;
243
243
  dismissible: boolean;
244
244
  fullscreen: boolean;
245
245
  modal: boolean;
@@ -238,8 +238,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
238
238
  transition: boolean;
239
239
  autofocus: boolean;
240
240
  loading: boolean;
241
- overlay: boolean;
242
241
  colorMode: boolean;
242
+ overlay: boolean;
243
243
  dismissible: boolean;
244
244
  fullscreen: boolean;
245
245
  modal: boolean;
@@ -240,8 +240,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
240
240
  square: boolean;
241
241
  viewTransition: boolean;
242
242
  block: boolean;
243
- collapsed: boolean;
244
243
  loading: boolean;
244
+ collapsed: boolean;
245
245
  tooltip: boolean | Record<string, any>;
246
246
  leading: boolean;
247
247
  trailing: boolean;
@@ -240,8 +240,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
240
240
  square: boolean;
241
241
  viewTransition: boolean;
242
242
  block: boolean;
243
- collapsed: boolean;
244
243
  loading: boolean;
244
+ collapsed: boolean;
245
245
  tooltip: boolean | Record<string, any>;
246
246
  leading: boolean;
247
247
  trailing: boolean;
@@ -51,8 +51,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
51
51
  required: false;
52
52
  };
53
53
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
54
- move: (...args: any[]) => void;
55
54
  "update:open": (...args: any[]) => void;
55
+ move: (...args: any[]) => void;
56
56
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
57
57
  as: {
58
58
  type: null;
@@ -104,8 +104,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
104
104
  required: false;
105
105
  };
106
106
  }>> & Readonly<{
107
- onMove?: ((...args: any[]) => any) | undefined;
108
107
  "onUpdate:open"?: ((...args: any[]) => any) | undefined;
108
+ onMove?: ((...args: any[]) => any) | undefined;
109
109
  }>, {
110
110
  as: any;
111
111
  open: boolean;
@@ -51,8 +51,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
51
51
  required: false;
52
52
  };
53
53
  }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
54
- move: (...args: any[]) => void;
55
54
  "update:open": (...args: any[]) => void;
55
+ move: (...args: any[]) => void;
56
56
  }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
57
57
  as: {
58
58
  type: null;
@@ -104,8 +104,8 @@ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<import
104
104
  required: false;
105
105
  };
106
106
  }>> & Readonly<{
107
- onMove?: ((...args: any[]) => any) | undefined;
108
107
  "onUpdate:open"?: ((...args: any[]) => any) | undefined;
108
+ onMove?: ((...args: any[]) => any) | undefined;
109
109
  }>, {
110
110
  as: any;
111
111
  open: boolean;
@@ -16,8 +16,8 @@ type __VLS_Props = {
16
16
  tooltip?: string | false;
17
17
  };
18
18
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
19
- color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
19
  icon: string;
20
+ color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
21
21
  size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
@@ -16,8 +16,8 @@ type __VLS_Props = {
16
16
  tooltip?: string | false;
17
17
  };
18
18
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
19
- color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
19
  icon: string;
20
+ color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
21
21
  size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
@@ -16,8 +16,8 @@ type __VLS_Props = {
16
16
  tooltip?: string | false;
17
17
  };
18
18
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
19
- color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
19
  icon: string;
20
+ color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
21
21
  size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;