@abraca/nuxt 2.0.1 → 2.0.4

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 (120) hide show
  1. package/dist/module.d.mts +18 -7
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +21 -5
  4. package/dist/runtime/assets/aware-tokens.css +1 -0
  5. package/dist/runtime/components/AAccountSwitcherModal.d.vue.ts +16 -1
  6. package/dist/runtime/components/AAccountSwitcherModal.vue +33 -4
  7. package/dist/runtime/components/AAccountSwitcherModal.vue.d.ts +16 -1
  8. package/dist/runtime/components/AAuthLinkLanding.d.vue.ts +3 -0
  9. package/dist/runtime/components/AAuthLinkLanding.vue +85 -0
  10. package/dist/runtime/components/AAuthLinkLanding.vue.d.ts +3 -0
  11. package/dist/runtime/components/AClaimAccountModal.d.vue.ts +7 -1
  12. package/dist/runtime/components/AClaimAccountModal.vue +28 -13
  13. package/dist/runtime/components/AClaimAccountModal.vue.d.ts +7 -1
  14. package/dist/runtime/components/AEmailVerifyConfirmModal.d.vue.ts +30 -0
  15. package/dist/runtime/components/AEmailVerifyConfirmModal.vue +100 -0
  16. package/dist/runtime/components/AEmailVerifyConfirmModal.vue.d.ts +30 -0
  17. package/dist/runtime/components/AEmailVerifyRequestCard.d.vue.ts +22 -0
  18. package/dist/runtime/components/AEmailVerifyRequestCard.vue +65 -0
  19. package/dist/runtime/components/AEmailVerifyRequestCard.vue.d.ts +22 -0
  20. package/dist/runtime/components/AMnemonicLoginModal.d.vue.ts +1 -1
  21. package/dist/runtime/components/AMnemonicLoginModal.vue.d.ts +1 -1
  22. package/dist/runtime/components/ANodePanel.vue +2 -0
  23. package/dist/runtime/components/ANotificationBell.d.vue.ts +2 -2
  24. package/dist/runtime/components/ANotificationBell.vue.d.ts +2 -2
  25. package/dist/runtime/components/APasswordChangeModal.d.vue.ts +28 -0
  26. package/dist/runtime/components/APasswordChangeModal.vue +178 -0
  27. package/dist/runtime/components/APasswordChangeModal.vue.d.ts +28 -0
  28. package/dist/runtime/components/APasswordLoginModal.d.vue.ts +42 -0
  29. package/dist/runtime/components/APasswordLoginModal.vue +177 -0
  30. package/dist/runtime/components/APasswordLoginModal.vue.d.ts +42 -0
  31. package/dist/runtime/components/APasswordRegisterModal.d.vue.ts +49 -0
  32. package/dist/runtime/components/APasswordRegisterModal.vue +262 -0
  33. package/dist/runtime/components/APasswordRegisterModal.vue.d.ts +49 -0
  34. package/dist/runtime/components/APasswordResetConfirmModal.d.vue.ts +31 -0
  35. package/dist/runtime/components/APasswordResetConfirmModal.vue +154 -0
  36. package/dist/runtime/components/APasswordResetConfirmModal.vue.d.ts +31 -0
  37. package/dist/runtime/components/APasswordResetRequestModal.d.vue.ts +35 -0
  38. package/dist/runtime/components/APasswordResetRequestModal.vue +113 -0
  39. package/dist/runtime/components/APasswordResetRequestModal.vue.d.ts +35 -0
  40. package/dist/runtime/components/ASetPasswordCard.d.vue.ts +26 -0
  41. package/dist/runtime/components/ASetPasswordCard.vue +139 -0
  42. package/dist/runtime/components/ASetPasswordCard.vue.d.ts +26 -0
  43. package/dist/runtime/components/aware/AAccordion.d.vue.ts +2 -0
  44. package/dist/runtime/components/aware/AAccordion.vue +11 -1
  45. package/dist/runtime/components/aware/AAccordion.vue.d.ts +2 -0
  46. package/dist/runtime/components/aware/AButton.vue +3 -3
  47. package/dist/runtime/components/aware/ACollapsible.d.vue.ts +2 -0
  48. package/dist/runtime/components/aware/ACollapsible.vue +9 -1
  49. package/dist/runtime/components/aware/ACollapsible.vue.d.ts +2 -0
  50. package/dist/runtime/components/aware/AGlobalFocusLayer.vue +1 -1
  51. package/dist/runtime/components/aware/AHoverItem.vue +28 -3
  52. package/dist/runtime/components/aware/AMedia.d.vue.ts +1 -1
  53. package/dist/runtime/components/aware/AMedia.vue.d.ts +1 -1
  54. package/dist/runtime/components/aware/AModal.d.vue.ts +2 -0
  55. package/dist/runtime/components/aware/AModal.vue +9 -1
  56. package/dist/runtime/components/aware/AModal.vue.d.ts +2 -0
  57. package/dist/runtime/components/aware/APresenceBlobs.vue +1 -1
  58. package/dist/runtime/components/aware/APresenceCursors.vue +1 -1
  59. package/dist/runtime/components/aware/AScroll.d.vue.ts +2 -0
  60. package/dist/runtime/components/aware/AScroll.vue +13 -3
  61. package/dist/runtime/components/aware/AScroll.vue.d.ts +2 -0
  62. package/dist/runtime/components/aware/ASlideover.d.vue.ts +2 -0
  63. package/dist/runtime/components/aware/ASlideover.vue +9 -1
  64. package/dist/runtime/components/aware/ASlideover.vue.d.ts +2 -0
  65. package/dist/runtime/components/aware/ASlider.vue +1 -0
  66. package/dist/runtime/components/aware/ATabs.d.vue.ts +2 -0
  67. package/dist/runtime/components/aware/ATabs.vue +9 -1
  68. package/dist/runtime/components/aware/ATabs.vue.d.ts +2 -0
  69. package/dist/runtime/components/chat/ANodeChatPanel.vue +1 -0
  70. package/dist/runtime/components/editor/AEditorRedoButton.d.vue.ts +2 -2
  71. package/dist/runtime/components/editor/AEditorRedoButton.vue.d.ts +2 -2
  72. package/dist/runtime/components/editor/AEditorUndoButton.d.vue.ts +2 -2
  73. package/dist/runtime/components/editor/AEditorUndoButton.vue.d.ts +2 -2
  74. package/dist/runtime/components/shell/AUserMenu.d.vue.ts +2 -2
  75. package/dist/runtime/components/shell/AUserMenu.vue.d.ts +2 -2
  76. package/dist/runtime/components/shell/AUserProfilePopover.d.vue.ts +1 -1
  77. package/dist/runtime/components/shell/AUserProfilePopover.vue.d.ts +1 -1
  78. package/dist/runtime/composables/useAAField.js +7 -4
  79. package/dist/runtime/composables/useAAFocus.js +10 -5
  80. package/dist/runtime/composables/useAAFollowAnchor.js +68 -34
  81. package/dist/runtime/composables/useAAFollowPeer.d.ts +7 -4
  82. package/dist/runtime/composables/useAAFollowPeer.js +60 -11
  83. package/dist/runtime/composables/useAAViewport.d.ts +1 -1
  84. package/dist/runtime/composables/useAbracadabraAuth.d.ts +2 -0
  85. package/dist/runtime/composables/useAbracadabraAuth.js +2 -0
  86. package/dist/runtime/composables/useEmailVerification.d.ts +40 -26
  87. package/dist/runtime/composables/useEmailVerification.js +95 -43
  88. package/dist/runtime/composables/usePasswordAuth.d.ts +64 -0
  89. package/dist/runtime/composables/usePasswordAuth.js +126 -0
  90. package/dist/runtime/composables/useTiptapHistory.d.ts +2 -2
  91. package/dist/runtime/composables/useTiptapHistory.js +5 -5
  92. package/dist/runtime/extensions/views/MetaFieldView.vue +23 -6
  93. package/dist/runtime/plugin-abracadabra.client.js +57 -8
  94. package/dist/runtime/plugin-abracadabra.server.js +2 -0
  95. package/dist/runtime/server/plugins/abracadabra-service.js +20 -9
  96. package/dist/runtime/types.d.ts +11 -0
  97. package/dist/runtime/utils/awareRingStyle.js +1 -1
  98. package/package.json +7 -7
  99. package/dist/runtime/components/renderers/ASpatialRenderer.d.vue.ts +0 -19
  100. package/dist/runtime/components/renderers/ASpatialRenderer.vue +0 -459
  101. package/dist/runtime/components/renderers/ASpatialRenderer.vue.d.ts +0 -19
  102. package/dist/runtime/components/renderers/spatial/SpatialGround.d.vue.ts +0 -20
  103. package/dist/runtime/components/renderers/spatial/SpatialGround.vue +0 -26
  104. package/dist/runtime/components/renderers/spatial/SpatialGround.vue.d.ts +0 -20
  105. package/dist/runtime/components/renderers/spatial/SpatialObject.d.vue.ts +0 -17
  106. package/dist/runtime/components/renderers/spatial/SpatialObject.vue +0 -257
  107. package/dist/runtime/components/renderers/spatial/SpatialObject.vue.d.ts +0 -17
  108. package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.d.vue.ts +0 -15
  109. package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.vue +0 -18
  110. package/dist/runtime/components/renderers/spatial/SpatialSceneBridge.vue.d.ts +0 -15
  111. package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.d.vue.ts +0 -16
  112. package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.vue +0 -66
  113. package/dist/runtime/components/renderers/spatial/SpatialTransformInputs.vue.d.ts +0 -16
  114. package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.d.vue.ts +0 -8
  115. package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.vue +0 -53
  116. package/dist/runtime/components/renderers/spatial/SpatialUserAvatar.vue.d.ts +0 -8
  117. package/dist/runtime/composables/useSpatialCamera.d.ts +0 -16
  118. package/dist/runtime/composables/useSpatialCamera.js +0 -175
  119. package/dist/runtime/composables/useSpatialDrag.d.ts +0 -14
  120. package/dist/runtime/composables/useSpatialDrag.js +0 -137
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  total?: boolean;
6
7
  };
7
8
  declare var __VLS_8: {}, __VLS_11: {}, __VLS_14: {}, __VLS_17: {}, __VLS_20: {}, __VLS_31: string, __VLS_32: any;
@@ -21,6 +22,7 @@ type __VLS_Slots = {} & {
21
22
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
22
23
  awareness: boolean;
23
24
  live: boolean;
25
+ followOnly: boolean;
24
26
  total: boolean;
25
27
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -65,5 +65,5 @@ onBeforeUnmount(() => {
65
65
  </template>
66
66
 
67
67
  <style scoped>
68
- .aa-presence-blobs{inset:0;isolation:isolate;mix-blend-mode:screen;pointer-events:none;position:fixed;z-index:0}.aa-presence-blobs__blob{border-radius:999px;filter:blur(60px);height:360px;opacity:.35;pointer-events:none;position:fixed;transform:translate(-50%,-50%);transition:left .2s ease-out,top .2s ease-out;width:360px}@media (prefers-color-scheme:light){.aa-presence-blobs{mix-blend-mode:multiply}.aa-presence-blobs__blob{opacity:.22}}
68
+ .aa-presence-blobs{inset:0;isolation:isolate;mix-blend-mode:screen;pointer-events:none;position:fixed;z-index:0}.aa-presence-blobs__blob{border-radius:999px;filter:blur(60px);height:360px;opacity:.35;pointer-events:none;position:fixed;transform:translate(-50%,-50%);transition:left var(--aa-track-blob-duration) var(--aa-track-blob-easing),top var(--aa-track-blob-duration) var(--aa-track-blob-easing);width:360px}@media (prefers-color-scheme:light){.aa-presence-blobs{mix-blend-mode:multiply}.aa-presence-blobs__blob{opacity:.22}}
69
69
  </style>
@@ -43,5 +43,5 @@ function nameFor(p) {
43
43
  </template>
44
44
 
45
45
  <style scoped>
46
- .aa-cursors-host{height:100%;position:relative;width:100%}.aa-cursors-layer{inset:0;overflow:hidden;pointer-events:none;position:absolute;z-index:50}.aa-cursor{align-items:flex-start;display:flex;gap:.15rem;position:absolute;transform:translate(-2px,-2px);transition:top 60ms linear,left 60ms linear}.aa-cursor__label{border-radius:.25rem .25rem .25rem 0;box-shadow:0 1px 2px rgba(0,0,0,.18);color:#fff;font-size:.6875rem;font-weight:500;line-height:1;margin-left:-2px;margin-top:11px;padding:.2rem .4rem;white-space:nowrap}.aa-cursors-overflow{background:var(--ui-bg-elevated);border:1px solid var(--ui-border);border-radius:999px;bottom:.5rem;color:var(--ui-text-muted);font-size:.6875rem;padding:.15rem .45rem;position:absolute;right:.5rem}
46
+ .aa-cursors-host{height:100%;position:relative;width:100%}.aa-cursors-layer{inset:0;overflow:hidden;pointer-events:none;position:absolute;z-index:50}.aa-cursor{align-items:flex-start;display:flex;gap:.15rem;position:absolute;transform:translate(-2px,-2px);transition:top var(--aa-track-cursor-duration) var(--aa-track-cursor-easing),left var(--aa-track-cursor-duration) var(--aa-track-cursor-easing)}.aa-cursor__label{border-radius:.25rem .25rem .25rem 0;box-shadow:0 1px 2px rgba(0,0,0,.18);color:#fff;font-size:.6875rem;font-weight:500;line-height:1;margin-left:-2px;margin-top:11px;padding:.2rem .4rem;white-space:nowrap}.aa-cursors-overflow{background:var(--ui-bg-elevated);border:1px solid var(--ui-border);border-radius:999px;bottom:.5rem;color:var(--ui-text-muted);font-size:.6875rem;padding:.15rem .45rem;position:absolute;right:.5rem}
47
47
  </style>
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  peers?: boolean;
6
7
  total?: boolean;
7
8
  };
@@ -13,6 +14,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
13
14
  peers: boolean;
14
15
  awareness: boolean;
15
16
  live: boolean;
17
+ followOnly: boolean;
16
18
  total: boolean;
17
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
20
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -3,17 +3,20 @@ import { computed, onBeforeUnmount, onMounted, ref, useAttrs, watch } from "vue"
3
3
  import { useAAField } from "../../composables/useAAField";
4
4
  import { useAAUIState } from "../../composables/useAAUIState";
5
5
  import { useAAEphemeral } from "../../composables/useAAEphemeral";
6
+ import { useAAFollowPeer } from "../../composables/useAAFollowPeer";
6
7
  import { awareRingStyle } from "../../utils/awareRingStyle";
7
8
  defineOptions({ inheritAttrs: false });
8
9
  const props = defineProps({
9
10
  fieldKey: { type: String, required: true },
10
11
  awareness: { type: Boolean, required: false, default: true },
11
12
  live: { type: Boolean, required: false, default: false },
13
+ followOnly: { type: Boolean, required: false, default: false },
12
14
  peers: { type: Boolean, required: false, default: false },
13
15
  total: { type: Boolean, required: false, default: false }
14
16
  });
17
+ const { isFollowing } = useAAFollowPeer();
15
18
  const enableAwareness = computed(() => props.awareness || props.total);
16
- const enableLive = computed(() => props.live || props.total);
19
+ const enableLive = computed(() => props.live || props.total || props.followOnly && isFollowing.value);
17
20
  const enablePeers = computed(() => props.peers || props.total);
18
21
  const { hoverers, focusers, pressers, isPressed, hoverHandlers } = useAAField(() => props.fieldKey);
19
22
  const ringStyle = computed(
@@ -40,8 +43,7 @@ function flush() {
40
43
  function onScroll() {
41
44
  if (!raf) raf = requestAnimationFrame(flush);
42
45
  }
43
- watch(liveScroll, (val) => {
44
- if (!enableLive.value) return;
46
+ function applyLiveScroll(val) {
45
47
  const el = elRef.value;
46
48
  if (!el || !val) return;
47
49
  if (Math.abs(el.scrollTop - val.y) < 2 && Math.abs(el.scrollLeft - val.x) < 2) return;
@@ -50,6 +52,14 @@ watch(liveScroll, (val) => {
50
52
  queueMicrotask(() => {
51
53
  suppress = false;
52
54
  });
55
+ }
56
+ watch(liveScroll, (val) => {
57
+ if (!enableLive.value) return;
58
+ applyLiveScroll(val);
59
+ });
60
+ watch(enableLive, (now, prev) => {
61
+ if (!now || prev) return;
62
+ applyLiveScroll(liveScroll.value);
53
63
  });
54
64
  onMounted(() => {
55
65
  elRef.value?.addEventListener("scroll", onScroll, { passive: true });
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  peers?: boolean;
6
7
  total?: boolean;
7
8
  };
@@ -13,6 +14,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
13
14
  peers: boolean;
14
15
  awareness: boolean;
15
16
  live: boolean;
17
+ followOnly: boolean;
16
18
  total: boolean;
17
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
18
20
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  total?: boolean;
6
7
  };
7
8
  declare var __VLS_8: {}, __VLS_11: {}, __VLS_14: {}, __VLS_17: {}, __VLS_20: {}, __VLS_31: string, __VLS_32: any;
@@ -21,6 +22,7 @@ type __VLS_Slots = {} & {
21
22
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
22
23
  awareness: boolean;
23
24
  live: boolean;
25
+ followOnly: boolean;
24
26
  total: boolean;
25
27
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -1,15 +1,18 @@
1
1
  <script setup>
2
2
  import { computed, ref, useAttrs, watch } from "vue";
3
3
  import { useAAUIState, useAAUIStateAuthor } from "../../composables/useAAUIState";
4
+ import { useAAFollowPeer } from "../../composables/useAAFollowPeer";
4
5
  import { useAwareness } from "../../composables/useAwareness";
5
6
  defineOptions({ inheritAttrs: false });
6
7
  const props = defineProps({
7
8
  fieldKey: { type: String, required: true },
8
9
  awareness: { type: Boolean, required: false, default: true },
9
10
  live: { type: Boolean, required: false, default: false },
11
+ followOnly: { type: Boolean, required: false, default: false },
10
12
  total: { type: Boolean, required: false, default: false }
11
13
  });
12
- const enableLive = computed(() => props.live || props.total);
14
+ const { isFollowing } = useAAFollowPeer();
15
+ const enableLive = computed(() => props.live || props.total || props.followOnly && isFollowing.value);
13
16
  const attrs = useAttrs();
14
17
  const liveOpen = useAAUIState(() => `${props.fieldKey}:open`, { defaultValue: false });
15
18
  const author = useAAUIStateAuthor(() => `${props.fieldKey}:open`);
@@ -25,6 +28,11 @@ watch(local, (val) => {
25
28
  if (!enableLive.value) return;
26
29
  if (!!liveOpen.value !== val) liveOpen.value = val;
27
30
  });
31
+ watch(enableLive, (now, prev) => {
32
+ if (!now || prev) return;
33
+ const incoming = !!liveOpen.value;
34
+ if (local.value !== incoming) local.value = incoming;
35
+ });
28
36
  const openedByUser = computed(() => {
29
37
  if (!enableLive.value || !local.value || author.value == null) return null;
30
38
  const state = states.value.get(author.value);
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  total?: boolean;
6
7
  };
7
8
  declare var __VLS_8: {}, __VLS_11: {}, __VLS_14: {}, __VLS_17: {}, __VLS_20: {}, __VLS_31: string, __VLS_32: any;
@@ -21,6 +22,7 @@ type __VLS_Slots = {} & {
21
22
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
22
23
  awareness: boolean;
23
24
  live: boolean;
25
+ followOnly: boolean;
24
26
  total: boolean;
25
27
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
26
28
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -26,6 +26,7 @@ const range = computed(() => Math.max(1e-4, props.max - props.min));
26
26
  function publishThumb(val) {
27
27
  if (!enablePeers.value || val == null) return;
28
28
  const single = Array.isArray(val) ? val[0] : val;
29
+ if (single == null) return;
29
30
  const norm = (single - props.min) / range.value;
30
31
  setThumb(Math.max(0, Math.min(1, norm)));
31
32
  }
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  peers?: boolean;
6
7
  total?: boolean;
7
8
  };
@@ -15,6 +16,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
15
16
  peers: boolean;
16
17
  awareness: boolean;
17
18
  live: boolean;
19
+ followOnly: boolean;
18
20
  total: boolean;
19
21
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
22
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -3,6 +3,7 @@ import { computed, ref, useAttrs, watch } from "vue";
3
3
  import { useAAField } from "../../composables/useAAField";
4
4
  import { useAAUIState } from "../../composables/useAAUIState";
5
5
  import { useAAEphemeral } from "../../composables/useAAEphemeral";
6
+ import { useAAFollowPeer } from "../../composables/useAAFollowPeer";
6
7
  import AHoverItem from "./AHoverItem.vue";
7
8
  function tabId(item) {
8
9
  if (item == null) return "";
@@ -19,11 +20,13 @@ const props = defineProps({
19
20
  fieldKey: { type: String, required: true },
20
21
  awareness: { type: Boolean, required: false, default: true },
21
22
  live: { type: Boolean, required: false, default: false },
23
+ followOnly: { type: Boolean, required: false, default: false },
22
24
  peers: { type: Boolean, required: false, default: false },
23
25
  total: { type: Boolean, required: false, default: false }
24
26
  });
27
+ const { isFollowing } = useAAFollowPeer();
25
28
  const enableAwareness = computed(() => props.awareness || props.total);
26
- const enableLive = computed(() => props.live || props.total);
29
+ const enableLive = computed(() => props.live || props.total || props.followOnly && isFollowing.value);
27
30
  const enablePeers = computed(() => props.peers || props.total);
28
31
  const attrs = useAttrs();
29
32
  const { hoverers, focusers, hoverHandlers } = useAAField(() => props.fieldKey);
@@ -42,6 +45,11 @@ watch(local, (val) => {
42
45
  if (enableLive.value && (liveActive.value || "") !== val) liveActive.value = val;
43
46
  if (enablePeers.value) setLocal(val || null);
44
47
  });
48
+ watch(enableLive, (now, prev) => {
49
+ if (!now || prev) return;
50
+ const incoming = liveActive.value || "";
51
+ if (incoming && local.value !== incoming) local.value = incoming;
52
+ });
45
53
  const ringStyle = computed(() => {
46
54
  if (!enableAwareness.value) return void 0;
47
55
  const focusColor = focusers.value[0]?.user?.color;
@@ -2,6 +2,7 @@ type __VLS_Props = {
2
2
  fieldKey: string;
3
3
  awareness?: boolean;
4
4
  live?: boolean;
5
+ followOnly?: boolean;
5
6
  peers?: boolean;
6
7
  total?: boolean;
7
8
  };
@@ -15,6 +16,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
15
16
  peers: boolean;
16
17
  awareness: boolean;
17
18
  live: boolean;
19
+ followOnly: boolean;
18
20
  total: boolean;
19
21
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
22
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -20,6 +20,7 @@ const typingUsersAdapted = computed(
20
20
  () => (typingUsers.value || []).map((id) => ({
21
21
  userId: String(id),
22
22
  userName: String(id),
23
+ name: String(id),
23
24
  color: "#888"
24
25
  }))
25
26
  );
@@ -9,7 +9,7 @@
9
9
  import type { Editor } from '@tiptap/vue-3';
10
10
  type __VLS_Props = {
11
11
  editor: Editor | null | undefined;
12
- size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg';
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
13
  variant?: 'ghost' | 'soft' | 'outline' | 'solid' | 'subtle' | 'link';
14
14
  color?: 'neutral' | 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info';
15
15
  icon?: string;
@@ -18,7 +18,7 @@ type __VLS_Props = {
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
19
  color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
20
  icon: string;
21
- size: "2xs" | "xs" | "sm" | "md" | "lg";
21
+ size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -9,7 +9,7 @@
9
9
  import type { Editor } from '@tiptap/vue-3';
10
10
  type __VLS_Props = {
11
11
  editor: Editor | null | undefined;
12
- size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg';
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
13
  variant?: 'ghost' | 'soft' | 'outline' | 'solid' | 'subtle' | 'link';
14
14
  color?: 'neutral' | 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info';
15
15
  icon?: string;
@@ -18,7 +18,7 @@ type __VLS_Props = {
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
19
  color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
20
  icon: string;
21
- size: "2xs" | "xs" | "sm" | "md" | "lg";
21
+ size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -9,7 +9,7 @@
9
9
  import type { Editor } from '@tiptap/vue-3';
10
10
  type __VLS_Props = {
11
11
  editor: Editor | null | undefined;
12
- size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg';
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
13
  variant?: 'ghost' | 'soft' | 'outline' | 'solid' | 'subtle' | 'link';
14
14
  color?: 'neutral' | 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info';
15
15
  icon?: string;
@@ -18,7 +18,7 @@ type __VLS_Props = {
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
19
  color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
20
  icon: string;
21
- size: "2xs" | "xs" | "sm" | "md" | "lg";
21
+ size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -9,7 +9,7 @@
9
9
  import type { Editor } from '@tiptap/vue-3';
10
10
  type __VLS_Props = {
11
11
  editor: Editor | null | undefined;
12
- size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg';
12
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
13
13
  variant?: 'ghost' | 'soft' | 'outline' | 'solid' | 'subtle' | 'link';
14
14
  color?: 'neutral' | 'primary' | 'secondary' | 'error' | 'warning' | 'success' | 'info';
15
15
  icon?: string;
@@ -18,7 +18,7 @@ type __VLS_Props = {
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
19
  color: "neutral" | "primary" | "secondary" | "error" | "warning" | "success" | "info";
20
20
  icon: string;
21
- size: "2xs" | "xs" | "sm" | "md" | "lg";
21
+ size: "xs" | "sm" | "md" | "lg" | "xl";
22
22
  variant: "ghost" | "soft" | "outline" | "solid" | "subtle" | "link";
23
23
  tooltip: string | false;
24
24
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -12,13 +12,13 @@ type __VLS_Props = {
12
12
  extraItems?: DropdownMenuItem[][];
13
13
  };
14
14
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ logout: () => any;
15
16
  "open-settings": () => any;
16
17
  "open-account": () => any;
17
- logout: () => any;
18
18
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
19
+ onLogout?: (() => any) | undefined;
19
20
  "onOpen-settings"?: (() => any) | undefined;
20
21
  "onOpen-account"?: (() => any) | undefined;
21
- onLogout?: (() => any) | undefined;
22
22
  }>, {
23
23
  color: string;
24
24
  collapsed: boolean;
@@ -12,13 +12,13 @@ type __VLS_Props = {
12
12
  extraItems?: DropdownMenuItem[][];
13
13
  };
14
14
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
15
+ logout: () => any;
15
16
  "open-settings": () => any;
16
17
  "open-account": () => any;
17
- logout: () => any;
18
18
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
19
+ onLogout?: (() => any) | undefined;
19
20
  "onOpen-settings"?: (() => any) | undefined;
20
21
  "onOpen-account"?: (() => any) | undefined;
21
- onLogout?: (() => any) | undefined;
22
22
  }>, {
23
23
  color: string;
24
24
  collapsed: boolean;
@@ -39,8 +39,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
39
39
  currentDocId: string | null;
40
40
  avatarStyle: string;
41
41
  isSelf: boolean;
42
- showFollow: boolean;
43
42
  isFollowing: boolean;
43
+ showFollow: boolean;
44
44
  currentDocLabel: string | null;
45
45
  currentDocIcon: string;
46
46
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -39,8 +39,8 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
39
39
  currentDocId: string | null;
40
40
  avatarStyle: string;
41
41
  isSelf: boolean;
42
- showFollow: boolean;
43
42
  isFollowing: boolean;
43
+ showFollow: boolean;
44
44
  currentDocLabel: string | null;
45
45
  currentDocIcon: string;
46
46
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
@@ -2,7 +2,7 @@ import { computed, isRef, onScopeDispose, ref } from "vue";
2
2
  import { useAwareness } from "./useAwareness.js";
3
3
  import { useAwarenessPeers } from "./useAwarenessPeers.js";
4
4
  export function useAAField(key) {
5
- const { setField } = useAwareness();
5
+ const { setField, localState } = useAwareness();
6
6
  const { peers } = useAwarenessPeers();
7
7
  const fieldKey = computed(
8
8
  () => typeof key === "function" ? key() : isRef(key) ? key.value : key
@@ -38,7 +38,8 @@ export function useAAField(key) {
38
38
  setField("hover", fieldKey.value);
39
39
  }
40
40
  function onMouseleave() {
41
- setField("hover", null);
41
+ const current = localState.value?.hover;
42
+ if (current === fieldKey.value) setField("hover", null);
42
43
  }
43
44
  function onMousedown() {
44
45
  localPress.value = true;
@@ -46,13 +47,15 @@ export function useAAField(key) {
46
47
  }
47
48
  function onMouseup() {
48
49
  localPress.value = false;
49
- setField("press", null);
50
+ const current = localState.value?.press;
51
+ if (current === fieldKey.value) setField("press", null);
50
52
  }
51
53
  function onFocus() {
52
54
  setField("focus", fieldKey.value);
53
55
  }
54
56
  function onBlur() {
55
- setField("focus", null);
57
+ const current = localState.value?.focus;
58
+ if (current === fieldKey.value) setField("focus", null);
56
59
  }
57
60
  const isPressed = computed(() => localPress.value || pressers.value.length > 0);
58
61
  const handlers = {
@@ -97,12 +97,17 @@ export function useAAFocus() {
97
97
  const candidates = document.elementsFromPoint(clientX, clientY);
98
98
  for (const el of candidates) {
99
99
  if (!isAnchorable(el)) continue;
100
- const path = pathFromElement(el);
101
- if (!path) continue;
102
- const r = el.getBoundingClientRect();
103
- return { elementPath: path, dx: clientX - r.left, dy: clientY - r.top };
100
+ const path2 = pathFromElement(el);
101
+ if (!path2) continue;
102
+ const r2 = el.getBoundingClientRect();
103
+ return { elementPath: path2, dx: clientX - r2.left, dy: clientY - r2.top };
104
104
  }
105
- return null;
105
+ const picked = pickAnchorElement();
106
+ if (!picked) return null;
107
+ const path = pathFromElement(picked.el);
108
+ if (!path) return null;
109
+ const r = picked.el.getBoundingClientRect();
110
+ return { elementPath: path, dx: clientX - r.left, dy: clientY - r.top };
106
111
  }
107
112
  function snapshot() {
108
113
  cancelAnimationFrame(raf);
@@ -1,4 +1,4 @@
1
- import { computed, watch } from "vue";
1
+ import { computed, onScopeDispose, watch } from "vue";
2
2
  import { useRoute, useRouter } from "#imports";
3
3
  import { useAAEphemeral } from "./useAAEphemeral.js";
4
4
  import { useAwarenessPeers } from "./useAwarenessPeers.js";
@@ -8,8 +8,11 @@ export function useAAFollowAnchor(leaderId) {
8
8
  const { peers: allPeers } = useAwarenessPeers();
9
9
  const route = useRoute();
10
10
  const router = useRouter();
11
+ const scrollState = /* @__PURE__ */ new Map();
11
12
  let scrollRaf = 0;
12
- let lastTargetKey = "";
13
+ const LERP = 0.18;
14
+ const SETTLE_PX = 0.5;
15
+ const MIN_DELTA_PX = 4;
13
16
  const leaderPayload = computed(() => {
14
17
  const id = leaderId.value;
15
18
  if (id == null) return null;
@@ -23,43 +26,74 @@ export function useAAFollowAnchor(leaderId) {
23
26
  });
24
27
  }
25
28
  }, { immediate: true });
26
- function scrollToLeader() {
27
- cancelAnimationFrame(scrollRaf);
28
- scrollRaf = requestAnimationFrame(() => {
29
- const payload = leaderPayload.value;
30
- if (!payload) return;
31
- if (payload.route !== route.path) return;
32
- const instructions = [];
33
- if (payload.scrollers && payload.scrollers.length) {
34
- for (const s of payload.scrollers) {
35
- instructions.push({ container: s.containerPath, element: s.elementPath, ratio: s.ratio });
29
+ function ensureRaf() {
30
+ if (scrollRaf) return;
31
+ const tick = () => {
32
+ let stillMoving = false;
33
+ for (const [scroller, s] of scrollState) {
34
+ const delta = s.target - s.current;
35
+ if (Math.abs(delta) < SETTLE_PX) {
36
+ if (scroller === window) window.scrollTo({ top: s.target, behavior: "auto" });
37
+ else scroller.scrollTo({ top: s.target, behavior: "auto" });
38
+ scrollState.delete(scroller);
39
+ continue;
36
40
  }
37
- } else if (payload.kind === "anchor" && payload.anchor) {
38
- instructions.push({ element: payload.anchor.elementPath, ratio: payload.anchorRatio ?? 0.05 });
39
- } else if (payload.kind === "selection" && payload.start) {
40
- instructions.push({ element: payload.start.elementPath, ratio: 0.2 });
41
+ stillMoving = true;
42
+ s.current += delta * LERP;
43
+ if (scroller === window) window.scrollTo({ top: s.current, behavior: "auto" });
44
+ else scroller.scrollTo({ top: s.current, behavior: "auto" });
41
45
  }
42
- const fingerprint = [];
43
- for (const ins of instructions) {
44
- const target = elementFromPath(ins.element);
45
- if (!target || !target.isConnected) continue;
46
- const scroller = ins.container ? elementFromPath(ins.container) ?? window : window;
47
- const isWindow = scroller === window;
48
- const scrollerRect = isWindow ? { top: 0, height: window.innerHeight || document.documentElement.clientHeight } : scroller.getBoundingClientRect();
49
- const desiredTop = scrollerRect.top + scrollerRect.height * Math.max(0, Math.min(0.9, ins.ratio));
50
- const rect = target.getBoundingClientRect();
51
- const delta = rect.top - desiredTop;
52
- fingerprint.push(`${isWindow ? "w" : ins.container?.join(",")}-${Math.round(rect.top)}-${ins.ratio.toFixed(3)}`);
53
- if (Math.abs(delta) < 8) continue;
54
- if (isWindow) window.scrollBy({ top: delta, behavior: "smooth" });
55
- else scroller.scrollBy({ top: delta, behavior: "smooth" });
46
+ scrollRaf = stillMoving ? requestAnimationFrame(tick) : 0;
47
+ };
48
+ scrollRaf = requestAnimationFrame(tick);
49
+ }
50
+ function scrollToLeader() {
51
+ const payload = leaderPayload.value;
52
+ if (!payload) return;
53
+ if (payload.route !== route.path) return;
54
+ const instructions = [];
55
+ if (payload.scrollers && payload.scrollers.length) {
56
+ for (const s of payload.scrollers) {
57
+ instructions.push({ container: s.containerPath, element: s.elementPath, ratio: s.ratio });
56
58
  }
57
- const key = fingerprint.join("|");
58
- if (key === lastTargetKey) return;
59
- lastTargetKey = key;
60
- });
59
+ } else if (payload.kind === "anchor" && payload.anchor) {
60
+ instructions.push({ element: payload.anchor.elementPath, ratio: payload.anchorRatio ?? 0.05 });
61
+ } else if (payload.kind === "selection" && payload.start) {
62
+ instructions.push({ element: payload.start.elementPath, ratio: 0.2 });
63
+ }
64
+ let targetsChanged = false;
65
+ for (const ins of instructions) {
66
+ const target = elementFromPath(ins.element);
67
+ if (!target || !target.isConnected) continue;
68
+ const scroller = ins.container ? elementFromPath(ins.container) ?? window : window;
69
+ const isWindow = scroller === window;
70
+ const scrollerRect = isWindow ? { top: 0, height: window.innerHeight || document.documentElement.clientHeight } : scroller.getBoundingClientRect();
71
+ const desiredTop = scrollerRect.top + scrollerRect.height * Math.max(0, Math.min(0.9, ins.ratio));
72
+ const rect = target.getBoundingClientRect();
73
+ const delta = rect.top - desiredTop;
74
+ if (Math.abs(delta) < MIN_DELTA_PX) continue;
75
+ const currentScroll = isWindow ? window.scrollY : scroller.scrollTop;
76
+ const targetScroll = currentScroll + delta;
77
+ const existing = scrollState.get(scroller);
78
+ if (existing) {
79
+ existing.current = currentScroll;
80
+ if (Math.abs(existing.target - targetScroll) >= 0.5) {
81
+ existing.target = targetScroll;
82
+ targetsChanged = true;
83
+ }
84
+ } else {
85
+ scrollState.set(scroller, { current: currentScroll, target: targetScroll });
86
+ targetsChanged = true;
87
+ }
88
+ }
89
+ if (targetsChanged) ensureRaf();
61
90
  }
62
91
  watch(leaderPayload, scrollToLeader, { deep: true, flush: "post" });
92
+ onScopeDispose(() => {
93
+ if (scrollRaf) cancelAnimationFrame(scrollRaf);
94
+ scrollRaf = 0;
95
+ scrollState.clear();
96
+ });
63
97
  const leader = computed(() => {
64
98
  const id = leaderId.value;
65
99
  if (id == null) return null;
@@ -19,11 +19,14 @@ export interface UseAAFollowPeerOptions {
19
19
  onBreak?: () => void;
20
20
  }
21
21
  export declare function useAAFollowPeer(options?: UseAAFollowPeerOptions): {
22
- follow: (clientId: number) => void;
22
+ follow: (clientIdOrPublicKey: number | string) => void;
23
23
  unfollow: () => void;
24
- followingClientId: import("vue").Ref<number | null, number | null>;
24
+ followingClientId: import("vue").ComputedRef<number | null>;
25
+ followingPublicKey: import("vue").ComputedRef<string | null>;
25
26
  followingUser: import("vue").ComputedRef<{
26
- name?: string;
27
- color?: string;
27
+ name?: string | undefined;
28
+ color?: string | undefined;
29
+ publicKey?: string | undefined;
28
30
  } | null>;
31
+ isFollowing: import("vue").ComputedRef<boolean>;
29
32
  };