@m3ui-vue/m3ui-vue 0.1.2 → 0.1.3
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/package.json
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, nextTick } from
|
|
3
|
-
import MIcon from
|
|
4
|
-
import MContextMenuPanel from
|
|
5
|
-
import type { ContextMenuItem } from
|
|
2
|
+
import { ref, onMounted, nextTick } from "vue";
|
|
3
|
+
import MIcon from "./MIcon.vue";
|
|
4
|
+
import MContextMenuPanel from "./_MContextMenuPanel.vue";
|
|
5
|
+
import type { ContextMenuItem } from "./MContextMenu.vue";
|
|
6
6
|
|
|
7
7
|
const props = defineProps<{
|
|
8
|
-
items: ContextMenuItem[]
|
|
9
|
-
x: number
|
|
10
|
-
y: number
|
|
11
|
-
}>()
|
|
8
|
+
items: ContextMenuItem[];
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
}>();
|
|
12
12
|
|
|
13
|
-
const emit = defineEmits<{ close: [] }>()
|
|
13
|
+
const emit = defineEmits<{ close: [] }>();
|
|
14
14
|
|
|
15
|
-
const panel = ref<HTMLElement | null>(null)
|
|
16
|
-
const panelX = ref(props.x)
|
|
17
|
-
const panelY = ref(props.y)
|
|
18
|
-
const activeIndex = ref<number | null>(null)
|
|
19
|
-
const subPos = ref({ x: 0, y: 0 })
|
|
15
|
+
const panel = ref<HTMLElement | null>(null);
|
|
16
|
+
const panelX = ref(props.x);
|
|
17
|
+
const panelY = ref(props.y);
|
|
18
|
+
const activeIndex = ref<number | null>(null);
|
|
19
|
+
const subPos = ref({ x: 0, y: 0 });
|
|
20
20
|
|
|
21
21
|
onMounted(async () => {
|
|
22
|
-
await nextTick()
|
|
23
|
-
if (!panel.value) return
|
|
24
|
-
const el = panel.value
|
|
25
|
-
panelX.value = Math.min(props.x, window.innerWidth - el.offsetWidth - 8)
|
|
26
|
-
panelY.value = Math.min(props.y, window.innerHeight - el.offsetHeight - 8)
|
|
27
|
-
})
|
|
22
|
+
await nextTick();
|
|
23
|
+
if (!panel.value) return;
|
|
24
|
+
const el = panel.value;
|
|
25
|
+
panelX.value = Math.min(props.x, window.innerWidth - el.offsetWidth - 8);
|
|
26
|
+
panelY.value = Math.min(props.y, window.innerHeight - el.offsetHeight - 8);
|
|
27
|
+
});
|
|
28
28
|
|
|
29
29
|
function onItemMouseEnter(index: number, item: ContextMenuItem, e: MouseEvent) {
|
|
30
30
|
if (item.divider || item.disabled) {
|
|
31
|
-
activeIndex.value = null
|
|
32
|
-
return
|
|
31
|
+
activeIndex.value = null;
|
|
32
|
+
return;
|
|
33
33
|
}
|
|
34
34
|
if (!item.children?.length) {
|
|
35
|
-
activeIndex.value = null
|
|
36
|
-
return
|
|
35
|
+
activeIndex.value = null;
|
|
36
|
+
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
activeIndex.value = index
|
|
40
|
-
const itemEl = e.currentTarget as HTMLElement
|
|
41
|
-
const itemRect = itemEl.getBoundingClientRect()
|
|
42
|
-
const panelRect = panel.value!.getBoundingClientRect()
|
|
39
|
+
activeIndex.value = index;
|
|
40
|
+
const itemEl = e.currentTarget as HTMLElement;
|
|
41
|
+
const itemRect = itemEl.getBoundingClientRect();
|
|
42
|
+
const panelRect = panel.value!.getBoundingClientRect();
|
|
43
43
|
|
|
44
|
-
let x = panelRect.right
|
|
45
|
-
let y = itemRect.top
|
|
46
|
-
if (x + 220 > window.innerWidth) x = panelRect.left - 220
|
|
47
|
-
if (y + 300 > window.innerHeight) y = Math.max(8, window.innerHeight - 300)
|
|
44
|
+
let x = panelRect.right;
|
|
45
|
+
let y = itemRect.top;
|
|
46
|
+
if (x + 220 > window.innerWidth) x = panelRect.left - 220;
|
|
47
|
+
if (y + 300 > window.innerHeight) y = Math.max(8, window.innerHeight - 300);
|
|
48
48
|
|
|
49
|
-
subPos.value = { x, y }
|
|
49
|
+
subPos.value = { x, y };
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
function onItemClick(item: ContextMenuItem) {
|
|
53
|
-
if (item.disabled || item.divider || item.children?.length) return
|
|
54
|
-
item.onClick?.()
|
|
55
|
-
emit(
|
|
53
|
+
if (item.disabled || item.divider || item.children?.length) return;
|
|
54
|
+
item.onClick?.();
|
|
55
|
+
emit("close");
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function onPanelMouseLeave(e: MouseEvent) {
|
|
59
59
|
// Don't close if the mouse moved to another context menu panel (sibling sub-panel)
|
|
60
|
-
const related = e.relatedTarget as Element | null
|
|
61
|
-
if (related?.closest(
|
|
62
|
-
activeIndex.value = null
|
|
60
|
+
const related = e.relatedTarget as Element | null;
|
|
61
|
+
if (related?.closest(".m3-ctx-panel")) return;
|
|
62
|
+
activeIndex.value = null;
|
|
63
63
|
}
|
|
64
64
|
</script>
|
|
65
65
|
|
|
@@ -84,7 +84,9 @@ function onPanelMouseLeave(e: MouseEvent) {
|
|
|
84
84
|
? 'cursor-pointer text-error hover:bg-error/8'
|
|
85
85
|
: 'cursor-pointer text-on-surface hover:bg-on-surface/8',
|
|
86
86
|
activeIndex === i && !item.disabled
|
|
87
|
-
?
|
|
87
|
+
? item.danger
|
|
88
|
+
? 'bg-error/8'
|
|
89
|
+
: 'bg-on-surface/8'
|
|
88
90
|
: '',
|
|
89
91
|
]"
|
|
90
92
|
@mouseenter="onItemMouseEnter(i, item, $event)"
|
|
@@ -101,7 +103,10 @@ function onPanelMouseLeave(e: MouseEvent) {
|
|
|
101
103
|
|
|
102
104
|
<span class="flex-1">{{ item.label }}</span>
|
|
103
105
|
|
|
104
|
-
<span
|
|
106
|
+
<span
|
|
107
|
+
v-if="item.shortcut"
|
|
108
|
+
class="text-label-small text-on-surface-variant"
|
|
109
|
+
>
|
|
105
110
|
{{ item.shortcut }}
|
|
106
111
|
</span>
|
|
107
112
|
|
|
@@ -121,6 +126,7 @@ function onPanelMouseLeave(e: MouseEvent) {
|
|
|
121
126
|
animated by Vue's Transition (produces a console warning). -->
|
|
122
127
|
<MContextMenuPanel
|
|
123
128
|
v-if="activeIndex !== null && items[activeIndex]?.children?.length"
|
|
129
|
+
:key="activeIndex"
|
|
124
130
|
:items="items[activeIndex]!.children!"
|
|
125
131
|
:x="subPos.x"
|
|
126
132
|
:y="subPos.y"
|