agentation-vue 0.2.6 → 0.2.12
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.
- package/README.md +94 -0
- package/dist/AgentationVue.vue +270 -60
- package/dist/components/AgentationToolbar.d.vue.ts +2 -0
- package/dist/components/AgentationToolbar.vue +12 -3
- package/dist/components/AgentationToolbar.vue.d.ts +2 -0
- package/dist/components/AnnotationInput.d.vue.ts +2 -0
- package/dist/components/AnnotationInput.vue +88 -16
- package/dist/components/AnnotationInput.vue.d.ts +2 -0
- package/dist/components/AnnotationMarker.d.vue.ts +1 -0
- package/dist/components/AnnotationMarker.vue +12 -3
- package/dist/components/AnnotationMarker.vue.d.ts +1 -0
- package/dist/components/MentionDropdown.d.vue.ts +16 -0
- package/dist/components/MentionDropdown.vue +41 -0
- package/dist/components/MentionDropdown.vue.d.ts +16 -0
- package/dist/components/SettingsPanel.vue +26 -3
- package/dist/components/SettingsPopover.vue +3 -5
- package/dist/composables/useAnnotations.d.ts +2 -0
- package/dist/composables/useAnnotations.mjs +6 -1
- package/dist/composables/useKeyboardShortcuts.mjs +22 -8
- package/dist/composables/useMentionDropdown.d.ts +21 -0
- package/dist/composables/useMentionDropdown.mjs +162 -0
- package/dist/composables/useOutputFormatter.mjs +2 -1
- package/dist/composables/usePeekMode.d.ts +14 -0
- package/dist/composables/usePeekMode.mjs +119 -0
- package/dist/composables/useSettings.d.ts +1 -0
- package/dist/composables/useSettings.mjs +2 -1
- package/dist/constants.d.ts +2 -0
- package/dist/constants.mjs +3 -0
- package/dist/styles/agentation.css +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/utils/mention.d.ts +13 -0
- package/dist/utils/mention.mjs +46 -0
- package/package.json +2 -2
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MentionCandidate } from '../utils/mention';
|
|
1
2
|
type __VLS_Props = {
|
|
2
3
|
position: {
|
|
3
4
|
x: number;
|
|
@@ -8,6 +9,7 @@ type __VLS_Props = {
|
|
|
8
9
|
computedStyles?: Record<string, string>;
|
|
9
10
|
initialComment?: string;
|
|
10
11
|
isEditing?: boolean;
|
|
12
|
+
mentionCandidates?: MentionCandidate[];
|
|
11
13
|
};
|
|
12
14
|
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
13
15
|
cancel: () => any;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed, onMounted, ref } from "vue-demi";
|
|
2
|
+
import { computed, onMounted, ref, toRef } from "vue-demi";
|
|
3
|
+
import { useMentionDropdown } from "../composables/useMentionDropdown.mjs";
|
|
4
|
+
import { hydrateMentions, serializeMentions } from "../utils/mention.mjs";
|
|
3
5
|
import ComponentChain from "./ComponentChain.vue";
|
|
6
|
+
import MentionDropdown from "./MentionDropdown.vue";
|
|
4
7
|
import VaButton from "./VaButton.vue";
|
|
5
8
|
import VaIcon from "./VaIcon.vue";
|
|
6
9
|
const props = defineProps({
|
|
@@ -9,12 +12,16 @@ const props = defineProps({
|
|
|
9
12
|
componentChain: { type: String, required: false },
|
|
10
13
|
computedStyles: { type: Object, required: false },
|
|
11
14
|
initialComment: { type: String, required: false },
|
|
12
|
-
isEditing: { type: Boolean, required: false }
|
|
15
|
+
isEditing: { type: Boolean, required: false },
|
|
16
|
+
mentionCandidates: { type: Array, required: false }
|
|
13
17
|
});
|
|
14
18
|
const emit = defineEmits(["add", "cancel", "delete"]);
|
|
15
|
-
const comment = ref(props.initialComment || "");
|
|
16
19
|
const inputEl = ref(null);
|
|
20
|
+
const commentText = ref(props.initialComment || "");
|
|
17
21
|
const computedStyleEntries = computed(() => Object.entries(props.computedStyles || {}));
|
|
22
|
+
const candidates = toRef(props, "mentionCandidates");
|
|
23
|
+
const safeCandidates = computed(() => candidates.value || []);
|
|
24
|
+
const mention = useMentionDropdown(inputEl, safeCandidates);
|
|
18
25
|
const inputStyle = computed(() => {
|
|
19
26
|
const x = Math.min(props.position.x, window.innerWidth - 380);
|
|
20
27
|
const y = Math.min(props.position.y + 20, window.innerHeight - 150);
|
|
@@ -23,14 +30,68 @@ const inputStyle = computed(() => {
|
|
|
23
30
|
top: `${Math.max(10, y)}px`
|
|
24
31
|
};
|
|
25
32
|
});
|
|
26
|
-
function
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
33
|
+
function autoResize() {
|
|
34
|
+
const el = inputEl.value;
|
|
35
|
+
if (!el)
|
|
36
|
+
return;
|
|
37
|
+
el.style.height = "auto";
|
|
38
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
39
|
+
}
|
|
40
|
+
function getComment() {
|
|
41
|
+
const el = inputEl.value;
|
|
42
|
+
if (!el)
|
|
43
|
+
return "";
|
|
44
|
+
return serializeMentions(el);
|
|
45
|
+
}
|
|
46
|
+
function onInput() {
|
|
47
|
+
commentText.value = getComment();
|
|
48
|
+
autoResize();
|
|
49
|
+
mention.checkForTrigger();
|
|
50
|
+
}
|
|
51
|
+
function onKeyDown(e) {
|
|
52
|
+
if (mention.onKeyDown(e))
|
|
29
53
|
return;
|
|
30
|
-
|
|
54
|
+
if (e.key === "Enter" && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
onAdd();
|
|
57
|
+
} else if (e.key === "Escape") {
|
|
58
|
+
if (mention.isOpen.value) {
|
|
59
|
+
e.preventDefault();
|
|
60
|
+
mention.close();
|
|
61
|
+
} else {
|
|
62
|
+
emit("cancel");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function onAdd() {
|
|
67
|
+
emit("add", getComment().trim());
|
|
68
|
+
}
|
|
69
|
+
function onPaste(e) {
|
|
70
|
+
e.preventDefault();
|
|
71
|
+
const text = e.clipboardData?.getData("text/plain") || "";
|
|
72
|
+
document.execCommand("insertText", false, text);
|
|
73
|
+
}
|
|
74
|
+
function onSelectCandidate(candidate) {
|
|
75
|
+
mention.selectCandidate(candidate);
|
|
31
76
|
}
|
|
32
77
|
onMounted(() => {
|
|
33
|
-
inputEl.value
|
|
78
|
+
const el = inputEl.value;
|
|
79
|
+
if (!el)
|
|
80
|
+
return;
|
|
81
|
+
if (props.initialComment) {
|
|
82
|
+
const html = hydrateMentions(props.initialComment, safeCandidates.value);
|
|
83
|
+
el.innerHTML = html;
|
|
84
|
+
}
|
|
85
|
+
el.focus();
|
|
86
|
+
const sel = window.getSelection();
|
|
87
|
+
if (sel && el.childNodes.length > 0) {
|
|
88
|
+
const range = document.createRange();
|
|
89
|
+
range.selectNodeContents(el);
|
|
90
|
+
range.collapse(false);
|
|
91
|
+
sel.removeAllRanges();
|
|
92
|
+
sel.addRange(range);
|
|
93
|
+
}
|
|
94
|
+
autoResize();
|
|
34
95
|
});
|
|
35
96
|
</script>
|
|
36
97
|
|
|
@@ -66,13 +127,24 @@ onMounted(() => {
|
|
|
66
127
|
<ComponentChain :chain="componentChain" variant="light" truncate="leaf" />
|
|
67
128
|
</div>
|
|
68
129
|
<span v-else class="__va-input-label">{{ elementName || "Annotation" }}</span>
|
|
69
|
-
<
|
|
130
|
+
<div
|
|
70
131
|
ref="inputEl"
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
132
|
+
class="__va-input-editable"
|
|
133
|
+
contenteditable="true"
|
|
134
|
+
role="textbox"
|
|
135
|
+
aria-multiline="true"
|
|
136
|
+
data-placeholder="Add a comment..."
|
|
137
|
+
@input="onInput"
|
|
138
|
+
@keydown="onKeyDown"
|
|
139
|
+
@paste="onPaste"
|
|
140
|
+
/>
|
|
141
|
+
<MentionDropdown
|
|
142
|
+
:open="mention.isOpen.value"
|
|
143
|
+
:candidates="mention.filteredCandidates.value"
|
|
144
|
+
:active-index="mention.activeIndex.value"
|
|
145
|
+
:position="mention.dropdownPosition.value"
|
|
146
|
+
@select="onSelectCandidate"
|
|
147
|
+
/>
|
|
76
148
|
<div class="__va-input-actions">
|
|
77
149
|
<button
|
|
78
150
|
v-if="isEditing"
|
|
@@ -86,8 +158,8 @@ onMounted(() => {
|
|
|
86
158
|
<VaButton variant="secondary" @click="$emit('cancel')">
|
|
87
159
|
Cancel
|
|
88
160
|
</VaButton>
|
|
89
|
-
<VaButton
|
|
90
|
-
{{ isEditing ? "Save" : "Add" }}
|
|
161
|
+
<VaButton @click="onAdd">
|
|
162
|
+
{{ isEditing ? "Save" : commentText.trim() ? "Add" : "Pin" }}
|
|
91
163
|
</VaButton>
|
|
92
164
|
</div>
|
|
93
165
|
</div>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { MentionCandidate } from '../utils/mention';
|
|
1
2
|
type __VLS_Props = {
|
|
2
3
|
position: {
|
|
3
4
|
x: number;
|
|
@@ -8,6 +9,7 @@ type __VLS_Props = {
|
|
|
8
9
|
computedStyles?: Record<string, string>;
|
|
9
10
|
initialComment?: string;
|
|
10
11
|
isEditing?: boolean;
|
|
12
|
+
mentionCandidates?: MentionCandidate[];
|
|
11
13
|
};
|
|
12
14
|
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
13
15
|
cancel: () => any;
|
|
@@ -6,6 +6,7 @@ type __VLS_Props = {
|
|
|
6
6
|
isStale?: boolean;
|
|
7
7
|
isPending?: boolean;
|
|
8
8
|
isSelection?: boolean;
|
|
9
|
+
hidden?: boolean;
|
|
9
10
|
};
|
|
10
11
|
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
11
12
|
click: () => any;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { computed } from "vue-demi";
|
|
2
|
+
import { computed, onMounted, ref } from "vue-demi";
|
|
3
3
|
import VaIcon from "./VaIcon.vue";
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
number: { type: Number, required: true },
|
|
@@ -8,9 +8,16 @@ const props = defineProps({
|
|
|
8
8
|
isFixed: { type: Boolean, required: false },
|
|
9
9
|
isStale: { type: Boolean, required: false },
|
|
10
10
|
isPending: { type: Boolean, required: false },
|
|
11
|
-
isSelection: { type: Boolean, required: false }
|
|
11
|
+
isSelection: { type: Boolean, required: false },
|
|
12
|
+
hidden: { type: Boolean, required: false }
|
|
12
13
|
});
|
|
13
14
|
defineEmits(["click"]);
|
|
15
|
+
const entering = ref(true);
|
|
16
|
+
onMounted(() => {
|
|
17
|
+
requestAnimationFrame(() => {
|
|
18
|
+
entering.value = false;
|
|
19
|
+
});
|
|
20
|
+
});
|
|
14
21
|
const markerStyle = computed(() => ({
|
|
15
22
|
left: `${props.x}%`,
|
|
16
23
|
top: `${props.y}px`
|
|
@@ -24,7 +31,9 @@ const markerStyle = computed(() => ({
|
|
|
24
31
|
'__va-marker--fixed': isFixed,
|
|
25
32
|
'__va-marker--stale': isStale,
|
|
26
33
|
'__va-marker--pending': isPending,
|
|
27
|
-
'__va-marker--selection': isSelection
|
|
34
|
+
'__va-marker--selection': isSelection,
|
|
35
|
+
'__va-marker--hidden': hidden,
|
|
36
|
+
'__va-marker--entering': entering
|
|
28
37
|
}"
|
|
29
38
|
:style="markerStyle"
|
|
30
39
|
data-agentation-vue
|
|
@@ -6,6 +6,7 @@ type __VLS_Props = {
|
|
|
6
6
|
isStale?: boolean;
|
|
7
7
|
isPending?: boolean;
|
|
8
8
|
isSelection?: boolean;
|
|
9
|
+
hidden?: boolean;
|
|
9
10
|
};
|
|
10
11
|
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
11
12
|
click: () => any;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MentionCandidate } from '../utils/mention';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
candidates: MentionCandidate[];
|
|
5
|
+
activeIndex: number;
|
|
6
|
+
position: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
12
|
+
select: (candidate: MentionCandidate) => any;
|
|
13
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
14
|
+
onSelect?: ((candidate: MentionCandidate) => any) | undefined;
|
|
15
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
export default _default;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from "vue-demi";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
open: { type: Boolean, required: true },
|
|
5
|
+
candidates: { type: Array, required: true },
|
|
6
|
+
activeIndex: { type: Number, required: true },
|
|
7
|
+
position: { type: Object, required: true }
|
|
8
|
+
});
|
|
9
|
+
defineEmits(["select"]);
|
|
10
|
+
const dropdownStyle = computed(() => {
|
|
11
|
+
if (!props.open)
|
|
12
|
+
return { display: "none" };
|
|
13
|
+
return {
|
|
14
|
+
left: `${props.position.x}px`,
|
|
15
|
+
top: `${props.position.y}px`
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<div
|
|
22
|
+
v-show="open && candidates.length > 0"
|
|
23
|
+
class="__va-mention-dropdown"
|
|
24
|
+
:style="dropdownStyle"
|
|
25
|
+
role="listbox"
|
|
26
|
+
data-agentation-vue
|
|
27
|
+
>
|
|
28
|
+
<div
|
|
29
|
+
v-for="(candidate, i) in candidates"
|
|
30
|
+
:key="candidate.id"
|
|
31
|
+
class="__va-mention-option"
|
|
32
|
+
:class="{ '__va-mention-option--active': i === activeIndex }"
|
|
33
|
+
role="option"
|
|
34
|
+
:aria-selected="i === activeIndex"
|
|
35
|
+
@mousedown.prevent="$emit('select', candidate)"
|
|
36
|
+
>
|
|
37
|
+
<span class="__va-mention-option-number">{{ candidate.displayNumber }}</span>
|
|
38
|
+
<span class="__va-mention-option-preview">{{ candidate.commentPreview }}</span>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MentionCandidate } from '../utils/mention';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
candidates: MentionCandidate[];
|
|
5
|
+
activeIndex: number;
|
|
6
|
+
position: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
12
|
+
select: (candidate: MentionCandidate) => any;
|
|
13
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
14
|
+
onSelect?: ((candidate: MentionCandidate) => any) | undefined;
|
|
15
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
export default _default;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed, toRef } from "vue-demi";
|
|
3
|
+
import { VA_VERSION } from "../constants.mjs";
|
|
3
4
|
import { vaTooltipDirective } from "../directives/vaTooltip.mjs";
|
|
4
5
|
import VaIcon from "./VaIcon.vue";
|
|
5
6
|
import VaToggle from "./VaToggle.vue";
|
|
@@ -36,6 +37,7 @@ function toggleTheme() {
|
|
|
36
37
|
<template>
|
|
37
38
|
<div class="__va-settings" data-agentation-vue @click.stop>
|
|
38
39
|
<div class="__va-settings-top">
|
|
40
|
+
<span class="__va-settings-title">Agentation vue <span class="__va-settings-version">v{{ VA_VERSION }}</span></span>
|
|
39
41
|
<button v-va-tooltip="'Toggle theme'" type="button" class="__va-theme-toggle" @click="toggleTheme">
|
|
40
42
|
<VaIcon :name="themeIcon" />
|
|
41
43
|
</button>
|
|
@@ -82,10 +84,10 @@ function toggleTheme() {
|
|
|
82
84
|
<div class="__va-settings-divider" />
|
|
83
85
|
|
|
84
86
|
<div class="__va-settings-row">
|
|
85
|
-
<span class="__va-settings-label">Clear
|
|
87
|
+
<span class="__va-settings-label">Clear After Copy</span>
|
|
86
88
|
<VaToggle
|
|
87
89
|
:model-value="settings.clearAfterCopy"
|
|
88
|
-
aria-label="Clear
|
|
90
|
+
aria-label="Clear After Copy"
|
|
89
91
|
@update:model-value="update('clearAfterCopy', $event)"
|
|
90
92
|
/>
|
|
91
93
|
</div>
|
|
@@ -123,7 +125,28 @@ function toggleTheme() {
|
|
|
123
125
|
{{ isMac ? "\u2325 Option" : "Alt" }}
|
|
124
126
|
</option>
|
|
125
127
|
<option value="Shift">
|
|
126
|
-
Shift
|
|
128
|
+
⇧ Shift
|
|
129
|
+
</option>
|
|
130
|
+
</select>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div class="__va-settings-row">
|
|
134
|
+
<span class="__va-settings-label">Peek inspect (hold key)</span>
|
|
135
|
+
<select :value="settings.peekKey" @change="onSelectChange('peekKey', $event)">
|
|
136
|
+
<option value="none">
|
|
137
|
+
Off
|
|
138
|
+
</option>
|
|
139
|
+
<option value="Meta">
|
|
140
|
+
{{ isMac ? "\u2318 Cmd" : "Ctrl" }}
|
|
141
|
+
</option>
|
|
142
|
+
<option value="Alt">
|
|
143
|
+
{{ isMac ? "\u2325 Option" : "Alt" }}
|
|
144
|
+
</option>
|
|
145
|
+
<option value="Shift">
|
|
146
|
+
⇧ Shift
|
|
147
|
+
</option>
|
|
148
|
+
<option value="Control">
|
|
149
|
+
{{ isMac ? "\u2303 Control" : "Ctrl" }}
|
|
127
150
|
</option>
|
|
128
151
|
</select>
|
|
129
152
|
</div>
|
|
@@ -138,12 +138,10 @@ function schedulePositionUpdate() {
|
|
|
138
138
|
function onDocumentPointerDown(e) {
|
|
139
139
|
if (!props.open)
|
|
140
140
|
return;
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
141
|
+
const path = e.composedPath();
|
|
142
|
+
if (panelEl.value && path.includes(panelEl.value))
|
|
143
143
|
return;
|
|
144
|
-
if (
|
|
145
|
-
return;
|
|
146
|
-
if (props.anchorEl?.contains(target))
|
|
144
|
+
if (props.anchorEl && path.includes(props.anchorEl))
|
|
147
145
|
return;
|
|
148
146
|
emit("close");
|
|
149
147
|
}
|
|
@@ -4,6 +4,7 @@ declare function addAnnotation(annotation: Omit<Annotation, 'id' | 'timestamp'>)
|
|
|
4
4
|
declare function removeAnnotation(id: string): Annotation | undefined;
|
|
5
5
|
declare function updateAnnotation(id: string, updates: Partial<Annotation>): Annotation | undefined;
|
|
6
6
|
declare function clearAnnotations(): Annotation[];
|
|
7
|
+
declare function restoreAnnotations(items: Annotation[]): void;
|
|
7
8
|
export declare function setAnnotationStorage(adapter: StorageAdapter): void;
|
|
8
9
|
export declare function resetAnnotationStorage(): void;
|
|
9
10
|
export declare function useAnnotations(initialUrl?: string): {
|
|
@@ -102,6 +103,7 @@ export declare function useAnnotations(initialUrl?: string): {
|
|
|
102
103
|
removeAnnotation: typeof removeAnnotation;
|
|
103
104
|
updateAnnotation: typeof updateAnnotation;
|
|
104
105
|
clearAnnotations: typeof clearAnnotations;
|
|
106
|
+
restoreAnnotations: typeof restoreAnnotations;
|
|
105
107
|
setScopeUrl: typeof setScopeUrl;
|
|
106
108
|
};
|
|
107
109
|
export {};
|
|
@@ -110,6 +110,11 @@ function clearAnnotations() {
|
|
|
110
110
|
save();
|
|
111
111
|
return cleared;
|
|
112
112
|
}
|
|
113
|
+
function restoreAnnotations(items) {
|
|
114
|
+
annotations.value.push(...items);
|
|
115
|
+
counter = getCounterSeed(annotations.value);
|
|
116
|
+
save();
|
|
117
|
+
}
|
|
113
118
|
setScopeUrl(scopedUrl);
|
|
114
119
|
export function setAnnotationStorage(adapter) {
|
|
115
120
|
annotationStorage = adapter;
|
|
@@ -121,5 +126,5 @@ export function resetAnnotationStorage() {
|
|
|
121
126
|
}
|
|
122
127
|
export function useAnnotations(initialUrl = getCurrentUrl()) {
|
|
123
128
|
setScopeUrl(initialUrl);
|
|
124
|
-
return { annotations, addAnnotation, removeAnnotation, updateAnnotation, clearAnnotations, setScopeUrl };
|
|
129
|
+
return { annotations, addAnnotation, removeAnnotation, updateAnnotation, clearAnnotations, restoreAnnotations, setScopeUrl };
|
|
125
130
|
}
|
|
@@ -50,6 +50,7 @@ export function useKeyboardShortcuts(options) {
|
|
|
50
50
|
let lastActivationKeyUpTime = 0;
|
|
51
51
|
let listenerAttached = false;
|
|
52
52
|
let mergedKeymap = { ...DEFAULT_KEYMAP, ...options.config.value.keymap };
|
|
53
|
+
const suppressedKeyUps = /* @__PURE__ */ new Set();
|
|
53
54
|
watch(options.config, (cfg2) => {
|
|
54
55
|
mergedKeymap = { ...DEFAULT_KEYMAP, ...cfg2.keymap };
|
|
55
56
|
});
|
|
@@ -129,9 +130,15 @@ export function useKeyboardShortcuts(options) {
|
|
|
129
130
|
break;
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
|
-
function
|
|
133
|
+
function normalizeKey(key) {
|
|
134
|
+
return key.length === 1 ? key.toLowerCase() : key;
|
|
135
|
+
}
|
|
136
|
+
function consume(e, suppressKeyUp = false) {
|
|
133
137
|
e.preventDefault();
|
|
138
|
+
e.stopImmediatePropagation();
|
|
134
139
|
e.stopPropagation();
|
|
140
|
+
if (suppressKeyUp)
|
|
141
|
+
suppressedKeyUps.add(normalizeKey(e.key));
|
|
135
142
|
}
|
|
136
143
|
function onKeyDown(e) {
|
|
137
144
|
if (e.repeat)
|
|
@@ -145,14 +152,14 @@ export function useKeyboardShortcuts(options) {
|
|
|
145
152
|
}
|
|
146
153
|
if (scope === "settings") {
|
|
147
154
|
if (e.key === "Escape") {
|
|
148
|
-
consume(e);
|
|
155
|
+
consume(e, true);
|
|
149
156
|
actions.closeSettings();
|
|
150
157
|
}
|
|
151
158
|
return;
|
|
152
159
|
}
|
|
153
160
|
if (scope === "input") {
|
|
154
161
|
if (e.key === "Escape") {
|
|
155
|
-
consume(e);
|
|
162
|
+
consume(e, true);
|
|
156
163
|
actions.inputCancel();
|
|
157
164
|
}
|
|
158
165
|
return;
|
|
@@ -167,11 +174,17 @@ export function useKeyboardShortcuts(options) {
|
|
|
167
174
|
if (!action)
|
|
168
175
|
return;
|
|
169
176
|
if (cfg().priorityWhenOpen) {
|
|
170
|
-
consume(e);
|
|
177
|
+
consume(e, true);
|
|
171
178
|
}
|
|
172
179
|
executeAction(action);
|
|
173
180
|
}
|
|
174
181
|
function onKeyUp(e) {
|
|
182
|
+
const normalizedKey = normalizeKey(e.key);
|
|
183
|
+
if (suppressedKeyUps.has(normalizedKey)) {
|
|
184
|
+
suppressedKeyUps.delete(normalizedKey);
|
|
185
|
+
consume(e);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
175
188
|
const { doubleTap } = cfg();
|
|
176
189
|
if (!doubleTap.enabled)
|
|
177
190
|
return;
|
|
@@ -198,13 +211,14 @@ export function useKeyboardShortcuts(options) {
|
|
|
198
211
|
}
|
|
199
212
|
function onBlurOrVisibility() {
|
|
200
213
|
lastActivationKeyUpTime = 0;
|
|
214
|
+
suppressedKeyUps.clear();
|
|
201
215
|
}
|
|
202
216
|
function attach() {
|
|
203
217
|
if (listenerAttached)
|
|
204
218
|
return;
|
|
205
219
|
listenerAttached = true;
|
|
206
|
-
|
|
207
|
-
|
|
220
|
+
window.addEventListener("keydown", onKeyDown, true);
|
|
221
|
+
window.addEventListener("keyup", onKeyUp, true);
|
|
208
222
|
window.addEventListener("blur", onBlurOrVisibility);
|
|
209
223
|
document.addEventListener("visibilitychange", onBlurOrVisibility);
|
|
210
224
|
}
|
|
@@ -212,8 +226,8 @@ export function useKeyboardShortcuts(options) {
|
|
|
212
226
|
if (!listenerAttached)
|
|
213
227
|
return;
|
|
214
228
|
listenerAttached = false;
|
|
215
|
-
|
|
216
|
-
|
|
229
|
+
window.removeEventListener("keydown", onKeyDown, true);
|
|
230
|
+
window.removeEventListener("keyup", onKeyUp, true);
|
|
217
231
|
window.removeEventListener("blur", onBlurOrVisibility);
|
|
218
232
|
document.removeEventListener("visibilitychange", onBlurOrVisibility);
|
|
219
233
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Ref } from 'vue-demi';
|
|
2
|
+
import type { MentionCandidate } from '../utils/mention';
|
|
3
|
+
export declare function useMentionDropdown(inputEl: Ref<HTMLElement | null>, candidates: Ref<MentionCandidate[]>): {
|
|
4
|
+
isOpen: Ref<boolean, boolean>;
|
|
5
|
+
filteredCandidates: import("vue-demi").ComputedRef<MentionCandidate[]>;
|
|
6
|
+
activeIndex: Ref<number, number>;
|
|
7
|
+
dropdownPosition: Ref<{
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
}, {
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
} | {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
}>;
|
|
17
|
+
checkForTrigger: () => void;
|
|
18
|
+
selectCandidate: (candidate: MentionCandidate) => void;
|
|
19
|
+
onKeyDown: (e: KeyboardEvent) => boolean;
|
|
20
|
+
close: () => void;
|
|
21
|
+
};
|