agentation-vue 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +27 -0
  2. package/dist/AgentationVue.d.vue.ts +27 -0
  3. package/dist/AgentationVue.vue +839 -0
  4. package/dist/AgentationVue.vue.d.ts +27 -0
  5. package/dist/components/AgentationToolbar.d.vue.ts +36 -0
  6. package/dist/components/AgentationToolbar.vue +233 -0
  7. package/dist/components/AgentationToolbar.vue.d.ts +36 -0
  8. package/dist/components/AnnotationInput.d.vue.ts +21 -0
  9. package/dist/components/AnnotationInput.vue +105 -0
  10. package/dist/components/AnnotationInput.vue.d.ts +21 -0
  11. package/dist/components/AnnotationMarker.d.vue.ts +15 -0
  12. package/dist/components/AnnotationMarker.vue +46 -0
  13. package/dist/components/AnnotationMarker.vue.d.ts +15 -0
  14. package/dist/components/ComponentChain.d.vue.ts +10 -0
  15. package/dist/components/ComponentChain.vue +91 -0
  16. package/dist/components/ComponentChain.vue.d.ts +10 -0
  17. package/dist/components/ElementHighlight.d.vue.ts +9 -0
  18. package/dist/components/ElementHighlight.vue +33 -0
  19. package/dist/components/ElementHighlight.vue.d.ts +9 -0
  20. package/dist/components/SettingsPanel.d.vue.ts +10 -0
  21. package/dist/components/SettingsPanel.vue +143 -0
  22. package/dist/components/SettingsPanel.vue.d.ts +10 -0
  23. package/dist/components/SettingsPopover.d.vue.ts +14 -0
  24. package/dist/components/SettingsPopover.vue +235 -0
  25. package/dist/components/SettingsPopover.vue.d.ts +14 -0
  26. package/dist/components/VaButton.d.vue.ts +23 -0
  27. package/dist/components/VaButton.vue +19 -0
  28. package/dist/components/VaButton.vue.d.ts +23 -0
  29. package/dist/components/VaIcon.d.vue.ts +6 -0
  30. package/dist/components/VaIcon.vue +18 -0
  31. package/dist/components/VaIcon.vue.d.ts +6 -0
  32. package/dist/components/VaIconButton.d.vue.ts +25 -0
  33. package/dist/components/VaIconButton.vue +43 -0
  34. package/dist/components/VaIconButton.vue.d.ts +25 -0
  35. package/dist/components/VaToggle.d.vue.ts +10 -0
  36. package/dist/components/VaToggle.vue +23 -0
  37. package/dist/components/VaToggle.vue.d.ts +10 -0
  38. package/dist/composables/useAnimationPause.d.ts +7 -0
  39. package/dist/composables/useAnimationPause.js +52 -0
  40. package/dist/composables/useAnimationPause.mjs +43 -0
  41. package/dist/composables/useAnnotations.d.ts +105 -0
  42. package/dist/composables/useAnnotations.js +106 -0
  43. package/dist/composables/useAnnotations.mjs +108 -0
  44. package/dist/composables/useAreaSelect.d.ts +21 -0
  45. package/dist/composables/useAreaSelect.js +62 -0
  46. package/dist/composables/useAreaSelect.mjs +41 -0
  47. package/dist/composables/useElementDetection.d.ts +22 -0
  48. package/dist/composables/useElementDetection.js +85 -0
  49. package/dist/composables/useElementDetection.mjs +82 -0
  50. package/dist/composables/useInteractionMode.d.ts +5 -0
  51. package/dist/composables/useInteractionMode.js +29 -0
  52. package/dist/composables/useInteractionMode.mjs +20 -0
  53. package/dist/composables/useKeyboardShortcuts.d.ts +43 -0
  54. package/dist/composables/useKeyboardShortcuts.js +202 -0
  55. package/dist/composables/useKeyboardShortcuts.mjs +223 -0
  56. package/dist/composables/useMarkerPositions.d.ts +5 -0
  57. package/dist/composables/useMarkerPositions.js +45 -0
  58. package/dist/composables/useMarkerPositions.mjs +36 -0
  59. package/dist/composables/useMultiSelect.d.ts +20 -0
  60. package/dist/composables/useMultiSelect.js +108 -0
  61. package/dist/composables/useMultiSelect.mjs +85 -0
  62. package/dist/composables/useOutputFormatter.d.ts +5 -0
  63. package/dist/composables/useOutputFormatter.js +100 -0
  64. package/dist/composables/useOutputFormatter.mjs +91 -0
  65. package/dist/composables/useSettings.d.ts +14 -0
  66. package/dist/composables/useSettings.js +48 -0
  67. package/dist/composables/useSettings.mjs +38 -0
  68. package/dist/composables/useTextSelection.d.ts +11 -0
  69. package/dist/composables/useTextSelection.js +33 -0
  70. package/dist/composables/useTextSelection.mjs +22 -0
  71. package/dist/composables/useToolbarAutoHide.d.ts +19 -0
  72. package/dist/composables/useToolbarAutoHide.js +270 -0
  73. package/dist/composables/useToolbarAutoHide.mjs +208 -0
  74. package/dist/composables/useToolbarDragSnap.d.ts +30 -0
  75. package/dist/composables/useToolbarDragSnap.js +296 -0
  76. package/dist/composables/useToolbarDragSnap.mjs +245 -0
  77. package/dist/constants.d.ts +2 -0
  78. package/dist/constants.js +8 -0
  79. package/dist/constants.mjs +2 -0
  80. package/dist/directives/vaTooltip.d.ts +22 -0
  81. package/dist/directives/vaTooltip.js +241 -0
  82. package/dist/directives/vaTooltip.mjs +257 -0
  83. package/dist/icons.d.ts +16 -0
  84. package/dist/icons.js +21 -0
  85. package/dist/icons.mjs +15 -0
  86. package/dist/index.d.ts +31 -0
  87. package/dist/index.js +168 -0
  88. package/dist/index.mjs +30 -0
  89. package/dist/styles/agentation.css +1 -0
  90. package/dist/types.d.ts +70 -0
  91. package/dist/types.js +1 -0
  92. package/dist/types.mjs +0 -0
  93. package/dist/utils/clipboard.d.ts +1 -0
  94. package/dist/utils/clipboard.js +22 -0
  95. package/dist/utils/clipboard.mjs +16 -0
  96. package/dist/utils/dom-inspector.d.ts +7 -0
  97. package/dist/utils/dom-inspector.js +168 -0
  98. package/dist/utils/dom-inspector.mjs +242 -0
  99. package/dist/utils/math.d.ts +1 -0
  100. package/dist/utils/math.js +9 -0
  101. package/dist/utils/math.mjs +3 -0
  102. package/dist/utils/portal.d.ts +2 -0
  103. package/dist/utils/portal.js +18 -0
  104. package/dist/utils/portal.mjs +11 -0
  105. package/dist/utils/selectors.d.ts +3 -0
  106. package/dist/utils/selectors.js +103 -0
  107. package/dist/utils/selectors.mjs +105 -0
  108. package/dist/utils/style.d.ts +2 -0
  109. package/dist/utils/style.js +14 -0
  110. package/dist/utils/style.mjs +8 -0
  111. package/package.json +49 -0
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useElementDetection = useElementDetection;
7
+ var _vueDemi = require("vue-demi");
8
+ var _constants = require("../constants");
9
+ var _domInspector = require("../utils/dom-inspector");
10
+ var _selectors = require("../utils/selectors");
11
+ function useElementDetection(overlayRef, showComponentTree) {
12
+ const hoveredElement = (0, _vueDemi.ref)(null);
13
+ const hoveredRect = (0, _vueDemi.ref)(null);
14
+ const hoveredName = (0, _vueDemi.ref)("");
15
+ const hoveredComponentChain = (0, _vueDemi.ref)();
16
+ let lastElement = null;
17
+ let rafId = null;
18
+ function getElementUnderOverlay(e) {
19
+ const overlay = overlayRef.value;
20
+ if (!overlay) return document.elementFromPoint(e.clientX, e.clientY);
21
+ const previousPointerEvents = overlay.style.pointerEvents;
22
+ overlay.style.pointerEvents = "none";
23
+ const el = document.elementFromPoint(e.clientX, e.clientY);
24
+ overlay.style.pointerEvents = previousPointerEvents;
25
+ return el;
26
+ }
27
+ function clearHighlight() {
28
+ hoveredElement.value = null;
29
+ hoveredRect.value = null;
30
+ hoveredName.value = "";
31
+ hoveredComponentChain.value = void 0;
32
+ lastElement = null;
33
+ }
34
+ function updateHighlight(el) {
35
+ const rect = el.getBoundingClientRect();
36
+ hoveredElement.value = el;
37
+ hoveredRect.value = {
38
+ x: rect.left,
39
+ y: rect.top,
40
+ width: rect.width,
41
+ height: rect.height
42
+ };
43
+ hoveredName.value = (0, _selectors.getElementName)(el);
44
+ if (showComponentTree?.()) {
45
+ hoveredComponentChain.value = (0, _domInspector.detectVueComponents)(el);
46
+ } else {
47
+ hoveredComponentChain.value = void 0;
48
+ }
49
+ }
50
+ function onMouseMove(e) {
51
+ if (rafId !== null) return;
52
+ rafId = requestAnimationFrame(() => {
53
+ rafId = null;
54
+ const el = getElementUnderOverlay(e);
55
+ if (el === lastElement) return;
56
+ if (el?.closest(_constants.VA_DATA_ATTR_SELECTOR)) {
57
+ clearHighlight();
58
+ return;
59
+ }
60
+ lastElement = el;
61
+ if (el) {
62
+ updateHighlight(el);
63
+ } else {
64
+ clearHighlight();
65
+ }
66
+ });
67
+ }
68
+ function cleanup() {
69
+ if (rafId !== null) {
70
+ cancelAnimationFrame(rafId);
71
+ rafId = null;
72
+ }
73
+ clearHighlight();
74
+ }
75
+ return {
76
+ hoveredElement,
77
+ hoveredRect,
78
+ hoveredName,
79
+ hoveredComponentChain,
80
+ onMouseMove,
81
+ clearHighlight,
82
+ getElementUnderOverlay,
83
+ cleanup
84
+ };
85
+ }
@@ -0,0 +1,82 @@
1
+ import { ref } from "vue-demi";
2
+ import { VA_DATA_ATTR_SELECTOR } from "../constants.mjs";
3
+ import { detectVueComponents } from "../utils/dom-inspector.mjs";
4
+ import { getElementName } from "../utils/selectors.mjs";
5
+ export function useElementDetection(overlayRef, showComponentTree) {
6
+ const hoveredElement = ref(null);
7
+ const hoveredRect = ref(null);
8
+ const hoveredName = ref("");
9
+ const hoveredComponentChain = ref();
10
+ let lastElement = null;
11
+ let rafId = null;
12
+ function getElementUnderOverlay(e) {
13
+ const overlay = overlayRef.value;
14
+ if (!overlay)
15
+ return document.elementFromPoint(e.clientX, e.clientY);
16
+ const previousPointerEvents = overlay.style.pointerEvents;
17
+ overlay.style.pointerEvents = "none";
18
+ const el = document.elementFromPoint(e.clientX, e.clientY);
19
+ overlay.style.pointerEvents = previousPointerEvents;
20
+ return el;
21
+ }
22
+ function clearHighlight() {
23
+ hoveredElement.value = null;
24
+ hoveredRect.value = null;
25
+ hoveredName.value = "";
26
+ hoveredComponentChain.value = void 0;
27
+ lastElement = null;
28
+ }
29
+ function updateHighlight(el) {
30
+ const rect = el.getBoundingClientRect();
31
+ hoveredElement.value = el;
32
+ hoveredRect.value = {
33
+ x: rect.left,
34
+ y: rect.top,
35
+ width: rect.width,
36
+ height: rect.height
37
+ };
38
+ hoveredName.value = getElementName(el);
39
+ if (showComponentTree?.()) {
40
+ hoveredComponentChain.value = detectVueComponents(el);
41
+ } else {
42
+ hoveredComponentChain.value = void 0;
43
+ }
44
+ }
45
+ function onMouseMove(e) {
46
+ if (rafId !== null)
47
+ return;
48
+ rafId = requestAnimationFrame(() => {
49
+ rafId = null;
50
+ const el = getElementUnderOverlay(e);
51
+ if (el === lastElement)
52
+ return;
53
+ if (el?.closest(VA_DATA_ATTR_SELECTOR)) {
54
+ clearHighlight();
55
+ return;
56
+ }
57
+ lastElement = el;
58
+ if (el) {
59
+ updateHighlight(el);
60
+ } else {
61
+ clearHighlight();
62
+ }
63
+ });
64
+ }
65
+ function cleanup() {
66
+ if (rafId !== null) {
67
+ cancelAnimationFrame(rafId);
68
+ rafId = null;
69
+ }
70
+ clearHighlight();
71
+ }
72
+ return {
73
+ hoveredElement,
74
+ hoveredRect,
75
+ hoveredName,
76
+ hoveredComponentChain,
77
+ onMouseMove,
78
+ clearHighlight,
79
+ getElementUnderOverlay,
80
+ cleanup
81
+ };
82
+ }
@@ -0,0 +1,5 @@
1
+ import type { InteractionMode } from '../types';
2
+ export declare function useInteractionMode(): {
3
+ mode: import("vue-demi").Ref<InteractionMode, InteractionMode>;
4
+ transition: (to: InteractionMode) => boolean;
5
+ };
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useInteractionMode = useInteractionMode;
7
+ var _vueDemi = require("vue-demi");
8
+ function useInteractionMode() {
9
+ const mode = (0, _vueDemi.ref)("idle");
10
+ const allowedTransitions = {
11
+ "idle": ["inspect"],
12
+ "inspect": ["idle", "input-open", "multi-selecting", "area-selecting"],
13
+ "multi-selecting": ["input-open", "inspect"],
14
+ "area-selecting": ["input-open", "inspect"],
15
+ "input-open": ["inspect", "idle"]
16
+ };
17
+ function transition(to) {
18
+ if (allowedTransitions[mode.value]?.includes(to)) {
19
+ mode.value = to;
20
+ return true;
21
+ }
22
+ console.warn(`[agentation-vue] Invalid transition: ${mode.value} \u2192 ${to}`);
23
+ return false;
24
+ }
25
+ return {
26
+ mode,
27
+ transition
28
+ };
29
+ }
@@ -0,0 +1,20 @@
1
+ import { ref } from "vue-demi";
2
+ export function useInteractionMode() {
3
+ const mode = ref("idle");
4
+ const allowedTransitions = {
5
+ "idle": ["inspect"],
6
+ "inspect": ["idle", "input-open", "multi-selecting", "area-selecting"],
7
+ "multi-selecting": ["input-open", "inspect"],
8
+ "area-selecting": ["input-open", "inspect"],
9
+ "input-open": ["inspect", "idle"]
10
+ };
11
+ function transition(to) {
12
+ if (allowedTransitions[mode.value]?.includes(to)) {
13
+ mode.value = to;
14
+ return true;
15
+ }
16
+ console.warn(`[agentation-vue] Invalid transition: ${mode.value} \u2192 ${to}`);
17
+ return false;
18
+ }
19
+ return { mode, transition };
20
+ }
@@ -0,0 +1,43 @@
1
+ import type { ComputedRef, Ref } from 'vue-demi';
2
+ import type { InteractionMode } from '../types';
3
+ export type ShortcutAction = 'activate' | 'element-select' | 'area-select' | 'pause-animations' | 'copy' | 'clear' | 'settings' | 'minimize';
4
+ export interface DoubleTapConfig {
5
+ enabled: boolean;
6
+ key: string;
7
+ thresholdMs: number;
8
+ }
9
+ export interface KeyboardShortcutConfig {
10
+ enabledWhenClosed: boolean;
11
+ priorityWhenOpen: boolean;
12
+ doubleTap: DoubleTapConfig;
13
+ keymap: Partial<Record<ShortcutAction, string>>;
14
+ conflictPolicy: 'ignore-editables' | 'always-capture';
15
+ }
16
+ export interface ShortcutActionHandlers {
17
+ activate: () => void;
18
+ deactivate: () => void;
19
+ elementSelect: () => void;
20
+ areaSelect: () => void;
21
+ pauseAnimations: () => void;
22
+ copy: () => void;
23
+ clear: () => void;
24
+ openSettings: () => void;
25
+ inputCancel: () => void;
26
+ closeSettings: () => void;
27
+ }
28
+ export interface UseKeyboardShortcutsOptions {
29
+ mode: Ref<InteractionMode>;
30
+ settingsOpen: Ref<boolean>;
31
+ toolbarDragging: Ref<boolean>;
32
+ toolbarRef: Ref<{
33
+ expanded: boolean;
34
+ } | null>;
35
+ isInteractionLocked: () => boolean;
36
+ config: ComputedRef<KeyboardShortcutConfig>;
37
+ actions: ShortcutActionHandlers;
38
+ }
39
+ export interface KeyboardShortcutState {
40
+ cleanup: () => void;
41
+ }
42
+ export declare const DEFAULT_SHORTCUT_CONFIG: KeyboardShortcutConfig;
43
+ export declare function useKeyboardShortcuts(options: UseKeyboardShortcutsOptions): KeyboardShortcutState;
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.DEFAULT_SHORTCUT_CONFIG = void 0;
7
+ exports.useKeyboardShortcuts = useKeyboardShortcuts;
8
+ var _vueDemi = require("vue-demi");
9
+ var _constants = require("../constants");
10
+ const DEFAULT_KEYMAP = {
11
+ "activate": "",
12
+ "element-select": "v",
13
+ "area-select": "a",
14
+ "pause-animations": "p",
15
+ "copy": "c",
16
+ "clear": "Backspace",
17
+ "settings": "",
18
+ "minimize": "Escape"
19
+ };
20
+ const DEFAULT_SHORTCUT_CONFIG = exports.DEFAULT_SHORTCUT_CONFIG = {
21
+ enabledWhenClosed: true,
22
+ priorityWhenOpen: true,
23
+ doubleTap: {
24
+ enabled: true,
25
+ key: "Shift",
26
+ thresholdMs: 280
27
+ },
28
+ keymap: {},
29
+ conflictPolicy: "ignore-editables"
30
+ };
31
+ const BROWSER_BLACKLIST = /* @__PURE__ */new Set(["Meta+l", "Meta+t", "Meta+w", "Meta+r", "Meta+n", "Meta+q", "Meta+Shift+t", "Meta+Shift+n", "Control+l", "Control+t", "Control+w", "Control+r", "Control+n", "Control+q", "Control+Shift+t", "Control+Shift+n", "Meta+c", "Meta+v", "Meta+x", "Meta+a", "Meta+z", "Control+c", "Control+v", "Control+x", "Control+a", "Control+z"]);
32
+ function useKeyboardShortcuts(options) {
33
+ const {
34
+ mode,
35
+ settingsOpen,
36
+ toolbarRef,
37
+ isInteractionLocked,
38
+ actions
39
+ } = options;
40
+ let lastActivationKeyUpTime = 0;
41
+ let listenerAttached = false;
42
+ let mergedKeymap = {
43
+ ...DEFAULT_KEYMAP,
44
+ ...options.config.value.keymap
45
+ };
46
+ (0, _vueDemi.watch)(options.config, cfg2 => {
47
+ mergedKeymap = {
48
+ ...DEFAULT_KEYMAP,
49
+ ...cfg2.keymap
50
+ };
51
+ });
52
+ function cfg() {
53
+ return options.config.value;
54
+ }
55
+ function getCurrentScope() {
56
+ if (mode.value === "idle" && (!toolbarRef.value || !toolbarRef.value.expanded)) {
57
+ return "closed";
58
+ }
59
+ if (settingsOpen.value) {
60
+ return "settings";
61
+ }
62
+ if (mode.value === "input-open") {
63
+ return "input";
64
+ }
65
+ return "open";
66
+ }
67
+ function isForeignEditable() {
68
+ const active = document.activeElement;
69
+ if (!active) return false;
70
+ const tag = active.tagName.toLowerCase();
71
+ const isEditable = tag === "input" || tag === "textarea" || active.isContentEditable;
72
+ if (!isEditable) return false;
73
+ return !active.closest(_constants.VA_DATA_ATTR_SELECTOR);
74
+ }
75
+ function isBrowserCombo(e) {
76
+ if (!e.metaKey && !e.ctrlKey) return false;
77
+ const parts = [];
78
+ if (e.metaKey) parts.push("Meta");
79
+ if (e.ctrlKey) parts.push("Control");
80
+ if (e.shiftKey) parts.push("Shift");
81
+ parts.push(e.key);
82
+ return BROWSER_BLACKLIST.has(parts.join("+"));
83
+ }
84
+ function findActionForKey(key) {
85
+ const normalized = key.toLowerCase();
86
+ for (const [action, mappedKey] of Object.entries(mergedKeymap)) {
87
+ if (!mappedKey) continue;
88
+ if (mappedKey.toLowerCase() === normalized || mappedKey === key) {
89
+ return action;
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ function executeAction(action) {
95
+ switch (action) {
96
+ case "element-select":
97
+ actions.elementSelect();
98
+ break;
99
+ case "area-select":
100
+ actions.areaSelect();
101
+ break;
102
+ case "pause-animations":
103
+ actions.pauseAnimations();
104
+ break;
105
+ case "copy":
106
+ actions.copy();
107
+ break;
108
+ case "clear":
109
+ actions.clear();
110
+ break;
111
+ case "settings":
112
+ actions.openSettings();
113
+ break;
114
+ case "minimize":
115
+ actions.deactivate();
116
+ if (toolbarRef.value) toolbarRef.value.expanded = false;
117
+ break;
118
+ }
119
+ }
120
+ function consume(e) {
121
+ e.preventDefault();
122
+ e.stopPropagation();
123
+ }
124
+ function onKeyDown(e) {
125
+ if (e.repeat) return;
126
+ if (isBrowserCombo(e)) return;
127
+ const hasModifier = e.metaKey || e.ctrlKey || e.altKey;
128
+ const scope = getCurrentScope();
129
+ if (scope === "closed") {
130
+ return;
131
+ }
132
+ if (scope === "settings") {
133
+ if (e.key === "Escape") {
134
+ consume(e);
135
+ actions.closeSettings();
136
+ }
137
+ return;
138
+ }
139
+ if (scope === "input") {
140
+ if (e.key === "Escape") {
141
+ consume(e);
142
+ actions.inputCancel();
143
+ }
144
+ return;
145
+ }
146
+ if (cfg().conflictPolicy === "ignore-editables" && isForeignEditable()) return;
147
+ if (isInteractionLocked()) return;
148
+ if (hasModifier) return;
149
+ const action = findActionForKey(e.key);
150
+ if (!action) return;
151
+ if (cfg().priorityWhenOpen) {
152
+ consume(e);
153
+ }
154
+ executeAction(action);
155
+ }
156
+ function onKeyUp(e) {
157
+ const {
158
+ doubleTap
159
+ } = cfg();
160
+ if (!doubleTap.enabled) return;
161
+ if (e.key !== doubleTap.key) return;
162
+ if (e.repeat) return;
163
+ const now = Date.now();
164
+ const delta = now - lastActivationKeyUpTime;
165
+ lastActivationKeyUpTime = now;
166
+ if (delta < doubleTap.thresholdMs && delta > 50) {
167
+ lastActivationKeyUpTime = 0;
168
+ const scope = getCurrentScope();
169
+ if (scope === "closed") {
170
+ actions.activate();
171
+ if (toolbarRef.value) toolbarRef.value.expanded = true;
172
+ } else if (scope === "open") {
173
+ actions.deactivate();
174
+ if (toolbarRef.value) toolbarRef.value.expanded = false;
175
+ }
176
+ }
177
+ }
178
+ function onBlurOrVisibility() {
179
+ lastActivationKeyUpTime = 0;
180
+ }
181
+ function attach() {
182
+ if (listenerAttached) return;
183
+ listenerAttached = true;
184
+ document.addEventListener("keydown", onKeyDown, true);
185
+ document.addEventListener("keyup", onKeyUp, true);
186
+ window.addEventListener("blur", onBlurOrVisibility);
187
+ document.addEventListener("visibilitychange", onBlurOrVisibility);
188
+ }
189
+ function detach() {
190
+ if (!listenerAttached) return;
191
+ listenerAttached = false;
192
+ document.removeEventListener("keydown", onKeyDown, true);
193
+ document.removeEventListener("keyup", onKeyUp, true);
194
+ window.removeEventListener("blur", onBlurOrVisibility);
195
+ document.removeEventListener("visibilitychange", onBlurOrVisibility);
196
+ }
197
+ (0, _vueDemi.onMounted)(attach);
198
+ (0, _vueDemi.onBeforeUnmount)(detach);
199
+ return {
200
+ cleanup: detach
201
+ };
202
+ }
@@ -0,0 +1,223 @@
1
+ import { onBeforeUnmount, onMounted, watch } from "vue-demi";
2
+ import { VA_DATA_ATTR_SELECTOR } from "../constants.mjs";
3
+ const DEFAULT_KEYMAP = {
4
+ "activate": "",
5
+ "element-select": "v",
6
+ "area-select": "a",
7
+ "pause-animations": "p",
8
+ "copy": "c",
9
+ "clear": "Backspace",
10
+ "settings": "",
11
+ "minimize": "Escape"
12
+ };
13
+ export const DEFAULT_SHORTCUT_CONFIG = {
14
+ enabledWhenClosed: true,
15
+ priorityWhenOpen: true,
16
+ doubleTap: { enabled: true, key: "Shift", thresholdMs: 280 },
17
+ keymap: {},
18
+ conflictPolicy: "ignore-editables"
19
+ };
20
+ const BROWSER_BLACKLIST = /* @__PURE__ */ new Set([
21
+ "Meta+l",
22
+ "Meta+t",
23
+ "Meta+w",
24
+ "Meta+r",
25
+ "Meta+n",
26
+ "Meta+q",
27
+ "Meta+Shift+t",
28
+ "Meta+Shift+n",
29
+ "Control+l",
30
+ "Control+t",
31
+ "Control+w",
32
+ "Control+r",
33
+ "Control+n",
34
+ "Control+q",
35
+ "Control+Shift+t",
36
+ "Control+Shift+n",
37
+ "Meta+c",
38
+ "Meta+v",
39
+ "Meta+x",
40
+ "Meta+a",
41
+ "Meta+z",
42
+ "Control+c",
43
+ "Control+v",
44
+ "Control+x",
45
+ "Control+a",
46
+ "Control+z"
47
+ ]);
48
+ export function useKeyboardShortcuts(options) {
49
+ const { mode, settingsOpen, toolbarRef, isInteractionLocked, actions } = options;
50
+ let lastActivationKeyUpTime = 0;
51
+ let listenerAttached = false;
52
+ let mergedKeymap = { ...DEFAULT_KEYMAP, ...options.config.value.keymap };
53
+ watch(options.config, (cfg2) => {
54
+ mergedKeymap = { ...DEFAULT_KEYMAP, ...cfg2.keymap };
55
+ });
56
+ function cfg() {
57
+ return options.config.value;
58
+ }
59
+ function getCurrentScope() {
60
+ if (mode.value === "idle" && (!toolbarRef.value || !toolbarRef.value.expanded)) {
61
+ return "closed";
62
+ }
63
+ if (settingsOpen.value) {
64
+ return "settings";
65
+ }
66
+ if (mode.value === "input-open") {
67
+ return "input";
68
+ }
69
+ return "open";
70
+ }
71
+ function isForeignEditable() {
72
+ const active = document.activeElement;
73
+ if (!active)
74
+ return false;
75
+ const tag = active.tagName.toLowerCase();
76
+ const isEditable = tag === "input" || tag === "textarea" || active.isContentEditable;
77
+ if (!isEditable)
78
+ return false;
79
+ return !active.closest(VA_DATA_ATTR_SELECTOR);
80
+ }
81
+ function isBrowserCombo(e) {
82
+ if (!e.metaKey && !e.ctrlKey)
83
+ return false;
84
+ const parts = [];
85
+ if (e.metaKey)
86
+ parts.push("Meta");
87
+ if (e.ctrlKey)
88
+ parts.push("Control");
89
+ if (e.shiftKey)
90
+ parts.push("Shift");
91
+ parts.push(e.key);
92
+ return BROWSER_BLACKLIST.has(parts.join("+"));
93
+ }
94
+ function findActionForKey(key) {
95
+ const normalized = key.toLowerCase();
96
+ for (const [action, mappedKey] of Object.entries(mergedKeymap)) {
97
+ if (!mappedKey)
98
+ continue;
99
+ if (mappedKey.toLowerCase() === normalized || mappedKey === key) {
100
+ return action;
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+ function executeAction(action) {
106
+ switch (action) {
107
+ case "element-select":
108
+ actions.elementSelect();
109
+ break;
110
+ case "area-select":
111
+ actions.areaSelect();
112
+ break;
113
+ case "pause-animations":
114
+ actions.pauseAnimations();
115
+ break;
116
+ case "copy":
117
+ actions.copy();
118
+ break;
119
+ case "clear":
120
+ actions.clear();
121
+ break;
122
+ case "settings":
123
+ actions.openSettings();
124
+ break;
125
+ case "minimize":
126
+ actions.deactivate();
127
+ if (toolbarRef.value)
128
+ toolbarRef.value.expanded = false;
129
+ break;
130
+ }
131
+ }
132
+ function consume(e) {
133
+ e.preventDefault();
134
+ e.stopPropagation();
135
+ }
136
+ function onKeyDown(e) {
137
+ if (e.repeat)
138
+ return;
139
+ if (isBrowserCombo(e))
140
+ return;
141
+ const hasModifier = e.metaKey || e.ctrlKey || e.altKey;
142
+ const scope = getCurrentScope();
143
+ if (scope === "closed") {
144
+ return;
145
+ }
146
+ if (scope === "settings") {
147
+ if (e.key === "Escape") {
148
+ consume(e);
149
+ actions.closeSettings();
150
+ }
151
+ return;
152
+ }
153
+ if (scope === "input") {
154
+ if (e.key === "Escape") {
155
+ consume(e);
156
+ actions.inputCancel();
157
+ }
158
+ return;
159
+ }
160
+ if (cfg().conflictPolicy === "ignore-editables" && isForeignEditable())
161
+ return;
162
+ if (isInteractionLocked())
163
+ return;
164
+ if (hasModifier)
165
+ return;
166
+ const action = findActionForKey(e.key);
167
+ if (!action)
168
+ return;
169
+ if (cfg().priorityWhenOpen) {
170
+ consume(e);
171
+ }
172
+ executeAction(action);
173
+ }
174
+ function onKeyUp(e) {
175
+ const { doubleTap } = cfg();
176
+ if (!doubleTap.enabled)
177
+ return;
178
+ if (e.key !== doubleTap.key)
179
+ return;
180
+ if (e.repeat)
181
+ return;
182
+ const now = Date.now();
183
+ const delta = now - lastActivationKeyUpTime;
184
+ lastActivationKeyUpTime = now;
185
+ if (delta < doubleTap.thresholdMs && delta > 50) {
186
+ lastActivationKeyUpTime = 0;
187
+ const scope = getCurrentScope();
188
+ if (scope === "closed") {
189
+ actions.activate();
190
+ if (toolbarRef.value)
191
+ toolbarRef.value.expanded = true;
192
+ } else if (scope === "open") {
193
+ actions.deactivate();
194
+ if (toolbarRef.value)
195
+ toolbarRef.value.expanded = false;
196
+ }
197
+ }
198
+ }
199
+ function onBlurOrVisibility() {
200
+ lastActivationKeyUpTime = 0;
201
+ }
202
+ function attach() {
203
+ if (listenerAttached)
204
+ return;
205
+ listenerAttached = true;
206
+ document.addEventListener("keydown", onKeyDown, true);
207
+ document.addEventListener("keyup", onKeyUp, true);
208
+ window.addEventListener("blur", onBlurOrVisibility);
209
+ document.addEventListener("visibilitychange", onBlurOrVisibility);
210
+ }
211
+ function detach() {
212
+ if (!listenerAttached)
213
+ return;
214
+ listenerAttached = false;
215
+ document.removeEventListener("keydown", onKeyDown, true);
216
+ document.removeEventListener("keyup", onKeyUp, true);
217
+ window.removeEventListener("blur", onBlurOrVisibility);
218
+ document.removeEventListener("visibilitychange", onBlurOrVisibility);
219
+ }
220
+ onMounted(attach);
221
+ onBeforeUnmount(detach);
222
+ return { cleanup: detach };
223
+ }
@@ -0,0 +1,5 @@
1
+ import type { Ref } from 'vue-demi';
2
+ import type { Annotation } from '../types';
3
+ export declare function useMarkerPositions(annotations: Ref<Annotation[]>): {
4
+ recalculatePositions: () => void;
5
+ };