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.
- package/LICENSE +27 -0
- package/dist/AgentationVue.d.vue.ts +27 -0
- package/dist/AgentationVue.vue +839 -0
- package/dist/AgentationVue.vue.d.ts +27 -0
- package/dist/components/AgentationToolbar.d.vue.ts +36 -0
- package/dist/components/AgentationToolbar.vue +233 -0
- package/dist/components/AgentationToolbar.vue.d.ts +36 -0
- package/dist/components/AnnotationInput.d.vue.ts +21 -0
- package/dist/components/AnnotationInput.vue +105 -0
- package/dist/components/AnnotationInput.vue.d.ts +21 -0
- package/dist/components/AnnotationMarker.d.vue.ts +15 -0
- package/dist/components/AnnotationMarker.vue +46 -0
- package/dist/components/AnnotationMarker.vue.d.ts +15 -0
- package/dist/components/ComponentChain.d.vue.ts +10 -0
- package/dist/components/ComponentChain.vue +91 -0
- package/dist/components/ComponentChain.vue.d.ts +10 -0
- package/dist/components/ElementHighlight.d.vue.ts +9 -0
- package/dist/components/ElementHighlight.vue +33 -0
- package/dist/components/ElementHighlight.vue.d.ts +9 -0
- package/dist/components/SettingsPanel.d.vue.ts +10 -0
- package/dist/components/SettingsPanel.vue +143 -0
- package/dist/components/SettingsPanel.vue.d.ts +10 -0
- package/dist/components/SettingsPopover.d.vue.ts +14 -0
- package/dist/components/SettingsPopover.vue +235 -0
- package/dist/components/SettingsPopover.vue.d.ts +14 -0
- package/dist/components/VaButton.d.vue.ts +23 -0
- package/dist/components/VaButton.vue +19 -0
- package/dist/components/VaButton.vue.d.ts +23 -0
- package/dist/components/VaIcon.d.vue.ts +6 -0
- package/dist/components/VaIcon.vue +18 -0
- package/dist/components/VaIcon.vue.d.ts +6 -0
- package/dist/components/VaIconButton.d.vue.ts +25 -0
- package/dist/components/VaIconButton.vue +43 -0
- package/dist/components/VaIconButton.vue.d.ts +25 -0
- package/dist/components/VaToggle.d.vue.ts +10 -0
- package/dist/components/VaToggle.vue +23 -0
- package/dist/components/VaToggle.vue.d.ts +10 -0
- package/dist/composables/useAnimationPause.d.ts +7 -0
- package/dist/composables/useAnimationPause.js +52 -0
- package/dist/composables/useAnimationPause.mjs +43 -0
- package/dist/composables/useAnnotations.d.ts +105 -0
- package/dist/composables/useAnnotations.js +106 -0
- package/dist/composables/useAnnotations.mjs +108 -0
- package/dist/composables/useAreaSelect.d.ts +21 -0
- package/dist/composables/useAreaSelect.js +62 -0
- package/dist/composables/useAreaSelect.mjs +41 -0
- package/dist/composables/useElementDetection.d.ts +22 -0
- package/dist/composables/useElementDetection.js +85 -0
- package/dist/composables/useElementDetection.mjs +82 -0
- package/dist/composables/useInteractionMode.d.ts +5 -0
- package/dist/composables/useInteractionMode.js +29 -0
- package/dist/composables/useInteractionMode.mjs +20 -0
- package/dist/composables/useKeyboardShortcuts.d.ts +43 -0
- package/dist/composables/useKeyboardShortcuts.js +202 -0
- package/dist/composables/useKeyboardShortcuts.mjs +223 -0
- package/dist/composables/useMarkerPositions.d.ts +5 -0
- package/dist/composables/useMarkerPositions.js +45 -0
- package/dist/composables/useMarkerPositions.mjs +36 -0
- package/dist/composables/useMultiSelect.d.ts +20 -0
- package/dist/composables/useMultiSelect.js +108 -0
- package/dist/composables/useMultiSelect.mjs +85 -0
- package/dist/composables/useOutputFormatter.d.ts +5 -0
- package/dist/composables/useOutputFormatter.js +100 -0
- package/dist/composables/useOutputFormatter.mjs +91 -0
- package/dist/composables/useSettings.d.ts +14 -0
- package/dist/composables/useSettings.js +48 -0
- package/dist/composables/useSettings.mjs +38 -0
- package/dist/composables/useTextSelection.d.ts +11 -0
- package/dist/composables/useTextSelection.js +33 -0
- package/dist/composables/useTextSelection.mjs +22 -0
- package/dist/composables/useToolbarAutoHide.d.ts +19 -0
- package/dist/composables/useToolbarAutoHide.js +270 -0
- package/dist/composables/useToolbarAutoHide.mjs +208 -0
- package/dist/composables/useToolbarDragSnap.d.ts +30 -0
- package/dist/composables/useToolbarDragSnap.js +296 -0
- package/dist/composables/useToolbarDragSnap.mjs +245 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +8 -0
- package/dist/constants.mjs +2 -0
- package/dist/directives/vaTooltip.d.ts +22 -0
- package/dist/directives/vaTooltip.js +241 -0
- package/dist/directives/vaTooltip.mjs +257 -0
- package/dist/icons.d.ts +16 -0
- package/dist/icons.js +21 -0
- package/dist/icons.mjs +15 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +168 -0
- package/dist/index.mjs +30 -0
- package/dist/styles/agentation.css +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.js +1 -0
- package/dist/types.mjs +0 -0
- package/dist/utils/clipboard.d.ts +1 -0
- package/dist/utils/clipboard.js +22 -0
- package/dist/utils/clipboard.mjs +16 -0
- package/dist/utils/dom-inspector.d.ts +7 -0
- package/dist/utils/dom-inspector.js +168 -0
- package/dist/utils/dom-inspector.mjs +242 -0
- package/dist/utils/math.d.ts +1 -0
- package/dist/utils/math.js +9 -0
- package/dist/utils/math.mjs +3 -0
- package/dist/utils/portal.d.ts +2 -0
- package/dist/utils/portal.js +18 -0
- package/dist/utils/portal.mjs +11 -0
- package/dist/utils/selectors.d.ts +3 -0
- package/dist/utils/selectors.js +103 -0
- package/dist/utils/selectors.mjs +105 -0
- package/dist/utils/style.d.ts +2 -0
- package/dist/utils/style.js +14 -0
- package/dist/utils/style.mjs +8 -0
- package/package.json +49 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BoundingBox } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
rect: BoundingBox | null;
|
|
4
|
+
elementName: string;
|
|
5
|
+
visible: boolean;
|
|
6
|
+
componentChain?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BoundingBox } from '../types'
|
|
3
|
+
import { computed } from 'vue-demi'
|
|
4
|
+
import { boundingBoxToStyle } from '../utils/style'
|
|
5
|
+
import ComponentChain from './ComponentChain.vue'
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
rect: BoundingBox | null
|
|
9
|
+
elementName: string
|
|
10
|
+
visible: boolean
|
|
11
|
+
componentChain?: string
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
const highlightStyle = computed(() => {
|
|
15
|
+
if (!props.rect)
|
|
16
|
+
return {}
|
|
17
|
+
return boundingBoxToStyle(props.rect)
|
|
18
|
+
})
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<div
|
|
23
|
+
v-if="visible && rect"
|
|
24
|
+
class="__va-highlight"
|
|
25
|
+
:style="highlightStyle"
|
|
26
|
+
data-agentation-vue
|
|
27
|
+
>
|
|
28
|
+
<div v-if="componentChain" class="__va-highlight-label __va-highlight-label--chain">
|
|
29
|
+
<ComponentChain :chain="componentChain" variant="dark" truncate="auto" />
|
|
30
|
+
</div>
|
|
31
|
+
<span v-else class="__va-highlight-label">{{ elementName }}</span>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BoundingBox } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
rect: BoundingBox | null;
|
|
4
|
+
elementName: string;
|
|
5
|
+
visible: boolean;
|
|
6
|
+
componentChain?: string;
|
|
7
|
+
};
|
|
8
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Settings } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
settings: Settings;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
6
|
+
update: (settings: Partial<Settings>) => any;
|
|
7
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
8
|
+
onUpdate?: ((settings: Partial<Settings>) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { Settings } from '../types'
|
|
3
|
+
import { computed, toRef } from 'vue-demi'
|
|
4
|
+
import { vaTooltipDirective } from '../directives/vaTooltip'
|
|
5
|
+
import VaIcon from './VaIcon.vue'
|
|
6
|
+
import VaToggle from './VaToggle.vue'
|
|
7
|
+
|
|
8
|
+
const props = defineProps<{
|
|
9
|
+
settings: Settings
|
|
10
|
+
}>()
|
|
11
|
+
const emit = defineEmits<{
|
|
12
|
+
update: [settings: Partial<Settings>]
|
|
13
|
+
}>()
|
|
14
|
+
const settings = toRef(props, 'settings')
|
|
15
|
+
|
|
16
|
+
const presetColors = ['#8B5CF6', '#3B82F6', '#06B6D4', '#10B981', '#EAB308', '#FF5C00', '#EF4444']
|
|
17
|
+
const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.userAgent)
|
|
18
|
+
|
|
19
|
+
function update(key: keyof Settings, value: any) {
|
|
20
|
+
emit('update', { [key]: value })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function onSelectChange(key: keyof Settings, event: Event) {
|
|
24
|
+
const target = event.currentTarget as HTMLSelectElement | null
|
|
25
|
+
if (!target)
|
|
26
|
+
return
|
|
27
|
+
update(key, target.value)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const isDarkTheme = computed(() => {
|
|
31
|
+
if (settings.value.theme === 'dark')
|
|
32
|
+
return true
|
|
33
|
+
if (settings.value.theme === 'light')
|
|
34
|
+
return false
|
|
35
|
+
return typeof window !== 'undefined'
|
|
36
|
+
&& typeof window.matchMedia === 'function'
|
|
37
|
+
&& window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const themeIcon = computed(() => (isDarkTheme.value ? 'sun' : 'moon'))
|
|
41
|
+
const vVaTooltip = vaTooltipDirective
|
|
42
|
+
|
|
43
|
+
function toggleTheme() {
|
|
44
|
+
update('theme', isDarkTheme.value ? 'light' : 'dark')
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<template>
|
|
49
|
+
<div class="__va-settings" data-agentation-vue @click.stop>
|
|
50
|
+
<div class="__va-settings-top">
|
|
51
|
+
<button v-va-tooltip="'Toggle theme'" type="button" class="__va-theme-toggle" @click="toggleTheme">
|
|
52
|
+
<VaIcon :name="themeIcon" />
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="__va-settings-row">
|
|
57
|
+
<span class="__va-settings-label">Output Detail</span>
|
|
58
|
+
<select :value="settings.outputDetail" @change="onSelectChange('outputDetail', $event)">
|
|
59
|
+
<option value="standard">
|
|
60
|
+
Standard
|
|
61
|
+
</option>
|
|
62
|
+
<option value="forensic">
|
|
63
|
+
Forensic
|
|
64
|
+
</option>
|
|
65
|
+
</select>
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div class="__va-settings-row">
|
|
69
|
+
<span class="__va-settings-label">Vue component tree</span>
|
|
70
|
+
<VaToggle
|
|
71
|
+
:model-value="settings.showComponentTree"
|
|
72
|
+
aria-label="Vue component tree"
|
|
73
|
+
@update:model-value="update('showComponentTree', $event)"
|
|
74
|
+
/>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div class="__va-settings-divider" />
|
|
78
|
+
|
|
79
|
+
<div class="__va-settings-row __va-settings-row--stack">
|
|
80
|
+
<span class="__va-settings-label">Marker Color</span>
|
|
81
|
+
<div class="__va-color-swatches">
|
|
82
|
+
<button
|
|
83
|
+
v-for="color in presetColors"
|
|
84
|
+
:key="color"
|
|
85
|
+
type="button"
|
|
86
|
+
class="__va-color-swatch"
|
|
87
|
+
:class="{ '__va-color-swatch--active': settings.markerColor === color }"
|
|
88
|
+
:style="{ background: color }"
|
|
89
|
+
@click="update('markerColor', color)"
|
|
90
|
+
/>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div class="__va-settings-divider" />
|
|
95
|
+
|
|
96
|
+
<div class="__va-settings-row">
|
|
97
|
+
<span class="__va-settings-label">Clear on copy/send</span>
|
|
98
|
+
<VaToggle
|
|
99
|
+
:model-value="settings.clearAfterCopy"
|
|
100
|
+
aria-label="Clear on copy/send"
|
|
101
|
+
@update:model-value="update('clearAfterCopy', $event)"
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div class="__va-settings-row">
|
|
106
|
+
<span class="__va-settings-label">Block page interactions</span>
|
|
107
|
+
<VaToggle
|
|
108
|
+
:model-value="settings.blockPageInteractions"
|
|
109
|
+
aria-label="Block page interactions"
|
|
110
|
+
@update:model-value="update('blockPageInteractions', $event)"
|
|
111
|
+
/>
|
|
112
|
+
</div>
|
|
113
|
+
|
|
114
|
+
<div class="__va-settings-row">
|
|
115
|
+
<span class="__va-settings-label">Auto-hide floating button</span>
|
|
116
|
+
<VaToggle
|
|
117
|
+
:model-value="settings.autoHideToolbar"
|
|
118
|
+
aria-label="Auto-hide floating button"
|
|
119
|
+
@update:model-value="update('autoHideToolbar', $event)"
|
|
120
|
+
/>
|
|
121
|
+
</div>
|
|
122
|
+
|
|
123
|
+
<div class="__va-settings-divider" />
|
|
124
|
+
|
|
125
|
+
<div class="__va-settings-row">
|
|
126
|
+
<span class="__va-settings-label">Activate with double tap</span>
|
|
127
|
+
<select :value="settings.activationKey" @change="onSelectChange('activationKey', $event)">
|
|
128
|
+
<option value="none">
|
|
129
|
+
Off
|
|
130
|
+
</option>
|
|
131
|
+
<option value="Meta">
|
|
132
|
+
{{ isMac ? '⌘ Cmd' : 'Ctrl' }}
|
|
133
|
+
</option>
|
|
134
|
+
<option value="Alt">
|
|
135
|
+
{{ isMac ? '⌥ Option' : 'Alt' }}
|
|
136
|
+
</option>
|
|
137
|
+
<option value="Shift">
|
|
138
|
+
Shift
|
|
139
|
+
</option>
|
|
140
|
+
</select>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</template>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Settings } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
settings: Settings;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
6
|
+
update: (settings: Partial<Settings>) => any;
|
|
7
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
8
|
+
onUpdate?: ((settings: Partial<Settings>) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Settings } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
settings: Settings;
|
|
5
|
+
anchorEl: HTMLElement | null;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
8
|
+
close: () => any;
|
|
9
|
+
update: (settings: Partial<Settings>) => any;
|
|
10
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onClose?: (() => any) | undefined;
|
|
12
|
+
onUpdate?: ((settings: Partial<Settings>) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { BoundingBox, Settings } from '../types'
|
|
3
|
+
import { nextTick, onBeforeUnmount, ref, watch } from 'vue-demi'
|
|
4
|
+
import { clamp } from '../utils/math'
|
|
5
|
+
import SettingsPanel from './SettingsPanel.vue'
|
|
6
|
+
|
|
7
|
+
type Placement = 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end' | 'right-start' | 'right-end'
|
|
8
|
+
|
|
9
|
+
const props = defineProps<{
|
|
10
|
+
open: boolean
|
|
11
|
+
settings: Settings
|
|
12
|
+
anchorEl: HTMLElement | null
|
|
13
|
+
}>()
|
|
14
|
+
|
|
15
|
+
const emit = defineEmits<{
|
|
16
|
+
close: []
|
|
17
|
+
update: [settings: Partial<Settings>]
|
|
18
|
+
}>()
|
|
19
|
+
|
|
20
|
+
const panelEl = ref<HTMLElement | null>(null)
|
|
21
|
+
const placement = ref<Placement>('bottom-start')
|
|
22
|
+
const style = ref<Record<string, string>>({
|
|
23
|
+
left: '-9999px',
|
|
24
|
+
top: '-9999px',
|
|
25
|
+
visibility: 'hidden',
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const GAP = 8
|
|
29
|
+
const VIEWPORT_PADDING = 8
|
|
30
|
+
let rafId: number | null = null
|
|
31
|
+
|
|
32
|
+
function getPlacementCandidates(anchorRect: DOMRect): Placement[] {
|
|
33
|
+
const isOnBottomHalf = anchorRect.top > window.innerHeight / 2
|
|
34
|
+
const isOnRightHalf = anchorRect.left > window.innerWidth / 2
|
|
35
|
+
const preferredVertical = isOnBottomHalf ? 'top' : 'bottom'
|
|
36
|
+
const secondaryVertical = isOnBottomHalf ? 'bottom' : 'top'
|
|
37
|
+
const preferredAlign = isOnRightHalf ? 'end' : 'start'
|
|
38
|
+
const secondaryAlign = isOnRightHalf ? 'start' : 'end'
|
|
39
|
+
const preferredHorizontal = isOnRightHalf ? 'left' : 'right'
|
|
40
|
+
const secondaryHorizontal = isOnRightHalf ? 'right' : 'left'
|
|
41
|
+
|
|
42
|
+
return [
|
|
43
|
+
`${preferredVertical}-${preferredAlign}` as Placement,
|
|
44
|
+
`${preferredVertical}-${secondaryAlign}` as Placement,
|
|
45
|
+
`${secondaryVertical}-${preferredAlign}` as Placement,
|
|
46
|
+
`${secondaryVertical}-${secondaryAlign}` as Placement,
|
|
47
|
+
`${preferredHorizontal}-start` as Placement,
|
|
48
|
+
`${preferredHorizontal}-end` as Placement,
|
|
49
|
+
`${secondaryHorizontal}-start` as Placement,
|
|
50
|
+
`${secondaryHorizontal}-end` as Placement,
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getCoordinates(anchorRect: DOMRect, panelRect: BoundingBox, value: Placement): { x: number, y: number } {
|
|
55
|
+
switch (value) {
|
|
56
|
+
case 'top-start':
|
|
57
|
+
return { x: anchorRect.left, y: anchorRect.top - GAP - panelRect.height }
|
|
58
|
+
case 'top-end':
|
|
59
|
+
return { x: anchorRect.right - panelRect.width, y: anchorRect.top - GAP - panelRect.height }
|
|
60
|
+
case 'bottom-start':
|
|
61
|
+
return { x: anchorRect.left, y: anchorRect.bottom + GAP }
|
|
62
|
+
case 'bottom-end':
|
|
63
|
+
return { x: anchorRect.right - panelRect.width, y: anchorRect.bottom + GAP }
|
|
64
|
+
case 'left-start':
|
|
65
|
+
return { x: anchorRect.left - GAP - panelRect.width, y: anchorRect.top }
|
|
66
|
+
case 'left-end':
|
|
67
|
+
return { x: anchorRect.left - GAP - panelRect.width, y: anchorRect.bottom - panelRect.height }
|
|
68
|
+
case 'right-start':
|
|
69
|
+
return { x: anchorRect.right + GAP, y: anchorRect.top }
|
|
70
|
+
case 'right-end':
|
|
71
|
+
return { x: anchorRect.right + GAP, y: anchorRect.bottom - panelRect.height }
|
|
72
|
+
default:
|
|
73
|
+
return { x: anchorRect.left, y: anchorRect.bottom + GAP }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getOverflow(x: number, y: number, panelRect: BoundingBox) {
|
|
78
|
+
const rightLimit = window.innerWidth - VIEWPORT_PADDING
|
|
79
|
+
const bottomLimit = window.innerHeight - VIEWPORT_PADDING
|
|
80
|
+
return {
|
|
81
|
+
left: Math.max(0, VIEWPORT_PADDING - x),
|
|
82
|
+
right: Math.max(0, x + panelRect.width - rightLimit),
|
|
83
|
+
top: Math.max(0, VIEWPORT_PADDING - y),
|
|
84
|
+
bottom: Math.max(0, y + panelRect.height - bottomLimit),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getOverflowScore(overflow: ReturnType<typeof getOverflow>) {
|
|
89
|
+
return overflow.left + overflow.right + overflow.top + overflow.bottom
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function applyPosition() {
|
|
93
|
+
if (!props.open)
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
const anchorEl = props.anchorEl
|
|
97
|
+
const panel = panelEl.value
|
|
98
|
+
if (!anchorEl || !panel) {
|
|
99
|
+
style.value = { left: '-9999px', top: '-9999px', visibility: 'hidden' }
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!anchorEl.isConnected) {
|
|
104
|
+
emit('close')
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const anchorRect = anchorEl.getBoundingClientRect()
|
|
109
|
+
const panelRect: BoundingBox = {
|
|
110
|
+
x: 0,
|
|
111
|
+
y: 0,
|
|
112
|
+
width: panel.offsetWidth,
|
|
113
|
+
height: panel.offsetHeight,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const candidates = getPlacementCandidates(anchorRect)
|
|
117
|
+
let best = candidates[0]
|
|
118
|
+
let bestCoords = getCoordinates(anchorRect, panelRect, best)
|
|
119
|
+
let bestOverflow = getOverflow(bestCoords.x, bestCoords.y, panelRect)
|
|
120
|
+
let bestScore = getOverflowScore(bestOverflow)
|
|
121
|
+
|
|
122
|
+
for (let i = 1; i < candidates.length; i++) {
|
|
123
|
+
const candidate = candidates[i]
|
|
124
|
+
const coords = getCoordinates(anchorRect, panelRect, candidate)
|
|
125
|
+
const overflow = getOverflow(coords.x, coords.y, panelRect)
|
|
126
|
+
const score = getOverflowScore(overflow)
|
|
127
|
+
if (score < bestScore) {
|
|
128
|
+
best = candidate
|
|
129
|
+
bestCoords = coords
|
|
130
|
+
bestOverflow = overflow
|
|
131
|
+
bestScore = score
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const x = clamp(
|
|
136
|
+
bestCoords.x,
|
|
137
|
+
VIEWPORT_PADDING,
|
|
138
|
+
Math.max(VIEWPORT_PADDING, window.innerWidth - VIEWPORT_PADDING - panelRect.width),
|
|
139
|
+
)
|
|
140
|
+
const y = clamp(
|
|
141
|
+
bestCoords.y,
|
|
142
|
+
VIEWPORT_PADDING,
|
|
143
|
+
Math.max(VIEWPORT_PADDING, window.innerHeight - VIEWPORT_PADDING - panelRect.height),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
placement.value = best
|
|
147
|
+
style.value = {
|
|
148
|
+
left: `${Math.round(x)}px`,
|
|
149
|
+
top: `${Math.round(y)}px`,
|
|
150
|
+
visibility: 'visible',
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function schedulePositionUpdate() {
|
|
155
|
+
if (rafId != null)
|
|
156
|
+
return
|
|
157
|
+
rafId = window.requestAnimationFrame(() => {
|
|
158
|
+
rafId = null
|
|
159
|
+
applyPosition()
|
|
160
|
+
})
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function onDocumentPointerDown(e: PointerEvent) {
|
|
164
|
+
if (!props.open)
|
|
165
|
+
return
|
|
166
|
+
const target = e.target as Node | null
|
|
167
|
+
if (!target)
|
|
168
|
+
return
|
|
169
|
+
if (panelEl.value?.contains(target))
|
|
170
|
+
return
|
|
171
|
+
if (props.anchorEl?.contains(target))
|
|
172
|
+
return
|
|
173
|
+
emit('close')
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function addGlobalListeners() {
|
|
177
|
+
window.addEventListener('resize', schedulePositionUpdate)
|
|
178
|
+
window.addEventListener('scroll', schedulePositionUpdate, true)
|
|
179
|
+
document.addEventListener('pointerdown', onDocumentPointerDown, true)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function removeGlobalListeners() {
|
|
183
|
+
window.removeEventListener('resize', schedulePositionUpdate)
|
|
184
|
+
window.removeEventListener('scroll', schedulePositionUpdate, true)
|
|
185
|
+
document.removeEventListener('pointerdown', onDocumentPointerDown, true)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
watch(
|
|
189
|
+
() => props.open,
|
|
190
|
+
async (isOpen) => {
|
|
191
|
+
if (isOpen) {
|
|
192
|
+
await nextTick()
|
|
193
|
+
applyPosition()
|
|
194
|
+
addGlobalListeners()
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
removeGlobalListeners()
|
|
198
|
+
style.value = { left: '-9999px', top: '-9999px', visibility: 'hidden' }
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
{ immediate: true },
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
watch(
|
|
205
|
+
() => props.anchorEl,
|
|
206
|
+
async () => {
|
|
207
|
+
if (!props.open)
|
|
208
|
+
return
|
|
209
|
+
await nextTick()
|
|
210
|
+
applyPosition()
|
|
211
|
+
},
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
onBeforeUnmount(() => {
|
|
215
|
+
removeGlobalListeners()
|
|
216
|
+
if (rafId != null) {
|
|
217
|
+
window.cancelAnimationFrame(rafId)
|
|
218
|
+
rafId = null
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
</script>
|
|
222
|
+
|
|
223
|
+
<template>
|
|
224
|
+
<div
|
|
225
|
+
v-if="open"
|
|
226
|
+
ref="panelEl"
|
|
227
|
+
class="__va-settings-popover"
|
|
228
|
+
:data-placement="placement"
|
|
229
|
+
:style="style"
|
|
230
|
+
data-agentation-vue
|
|
231
|
+
@click.stop
|
|
232
|
+
>
|
|
233
|
+
<SettingsPanel :settings="settings" @update="$emit('update', $event)" />
|
|
234
|
+
</div>
|
|
235
|
+
</template>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Settings } from '../types';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
open: boolean;
|
|
4
|
+
settings: Settings;
|
|
5
|
+
anchorEl: HTMLElement | null;
|
|
6
|
+
};
|
|
7
|
+
declare const _default: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
8
|
+
close: () => any;
|
|
9
|
+
update: (settings: Partial<Settings>) => any;
|
|
10
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
11
|
+
onClose?: (() => any) | undefined;
|
|
12
|
+
onUpdate?: ((settings: Partial<Settings>) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
variant?: 'primary' | 'secondary';
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_1: {};
|
|
6
|
+
type __VLS_Slots = {} & {
|
|
7
|
+
default?: (props: typeof __VLS_1) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
click: (event: MouseEvent) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
13
|
+
}>, {
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
variant: "primary" | "secondary";
|
|
16
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
20
|
+
new (): {
|
|
21
|
+
$slots: S;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
withDefaults(defineProps<{
|
|
3
|
+
variant?: 'primary' | 'secondary'
|
|
4
|
+
disabled?: boolean
|
|
5
|
+
}>(), {
|
|
6
|
+
variant: 'primary',
|
|
7
|
+
disabled: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
defineEmits<{
|
|
11
|
+
click: [event: MouseEvent]
|
|
12
|
+
}>()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<template>
|
|
16
|
+
<button type="button" class="__va-btn" :class="`__va-btn--${variant}`" :disabled="disabled" @click="$emit('click', $event)">
|
|
17
|
+
<slot />
|
|
18
|
+
</button>
|
|
19
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
variant?: 'primary' | 'secondary';
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
};
|
|
5
|
+
declare var __VLS_1: {};
|
|
6
|
+
type __VLS_Slots = {} & {
|
|
7
|
+
default?: (props: typeof __VLS_1) => any;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_component: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
click: (event: MouseEvent) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
13
|
+
}>, {
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
variant: "primary" | "secondary";
|
|
16
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
17
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
20
|
+
new (): {
|
|
21
|
+
$slots: S;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IconName } from '../icons';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
name: IconName;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { IconName } from '../icons'
|
|
3
|
+
import { icons } from '../icons'
|
|
4
|
+
|
|
5
|
+
defineProps<{ name: IconName }>()
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<svg
|
|
10
|
+
viewBox="0 0 24 24"
|
|
11
|
+
fill="none"
|
|
12
|
+
stroke="currentColor"
|
|
13
|
+
stroke-width="2"
|
|
14
|
+
stroke-linecap="round"
|
|
15
|
+
stroke-linejoin="round"
|
|
16
|
+
v-html="icons[name]"
|
|
17
|
+
/>
|
|
18
|
+
</template>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IconName } from '../icons';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
name: IconName;
|
|
4
|
+
};
|
|
5
|
+
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
active?: boolean;
|
|
3
|
+
disabled?: boolean;
|
|
4
|
+
title?: string;
|
|
5
|
+
shortcut?: string;
|
|
6
|
+
};
|
|
7
|
+
declare var __VLS_1: {};
|
|
8
|
+
type __VLS_Slots = {} & {
|
|
9
|
+
default?: (props: typeof __VLS_1) => any;
|
|
10
|
+
};
|
|
11
|
+
declare const __VLS_component: import("vue-demi").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue-demi").ComponentOptionsMixin, import("vue-demi").ComponentOptionsMixin, {
|
|
12
|
+
click: (event: MouseEvent) => any;
|
|
13
|
+
}, string, import("vue-demi").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
14
|
+
onClick?: ((event: MouseEvent) => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
active: boolean;
|
|
18
|
+
}, {}, {}, {}, string, import("vue-demi").ComponentProvideOptions, false, {}, any>;
|
|
19
|
+
declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
|
|
20
|
+
export default _default;
|
|
21
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
22
|
+
new (): {
|
|
23
|
+
$slots: S;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue-demi'
|
|
3
|
+
import { vaTooltipDirective } from '../directives/vaTooltip'
|
|
4
|
+
|
|
5
|
+
const props = withDefaults(defineProps<{
|
|
6
|
+
active?: boolean
|
|
7
|
+
disabled?: boolean
|
|
8
|
+
title?: string
|
|
9
|
+
shortcut?: string
|
|
10
|
+
}>(), {
|
|
11
|
+
active: false,
|
|
12
|
+
disabled: false,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
defineEmits<{
|
|
16
|
+
click: [event: MouseEvent]
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const vVaTooltip = vaTooltipDirective
|
|
20
|
+
const tooltipValue = computed(() => {
|
|
21
|
+
if (!props.title)
|
|
22
|
+
return null
|
|
23
|
+
return {
|
|
24
|
+
text: props.title,
|
|
25
|
+
shortcut: props.shortcut,
|
|
26
|
+
disabled: props.disabled,
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<button
|
|
33
|
+
v-va-tooltip="tooltipValue"
|
|
34
|
+
type="button"
|
|
35
|
+
class="__va-icon-btn"
|
|
36
|
+
:class="{ '__va-icon-btn--active': active }"
|
|
37
|
+
:aria-label="title"
|
|
38
|
+
:disabled="disabled"
|
|
39
|
+
@click="$emit('click', $event)"
|
|
40
|
+
>
|
|
41
|
+
<slot />
|
|
42
|
+
</button>
|
|
43
|
+
</template>
|