summaryrefslogtreecommitdiff
path: root/packages/client/src/components/ui/context-menu.vue
diff options
context:
space:
mode:
Diffstat (limited to 'packages/client/src/components/ui/context-menu.vue')
-rw-r--r--packages/client/src/components/ui/context-menu.vue97
1 files changed, 97 insertions, 0 deletions
diff --git a/packages/client/src/components/ui/context-menu.vue b/packages/client/src/components/ui/context-menu.vue
new file mode 100644
index 0000000000..561099cbe0
--- /dev/null
+++ b/packages/client/src/components/ui/context-menu.vue
@@ -0,0 +1,97 @@
+<template>
+<transition :name="$store.state.animation ? 'fade' : ''" appear>
+ <div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
+ <MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
+ </div>
+</transition>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import contains from '@/scripts/contains';
+import MkMenu from './menu.vue';
+
+export default defineComponent({
+ components: {
+ MkMenu,
+ },
+ props: {
+ items: {
+ type: Array,
+ required: true
+ },
+ ev: {
+ required: true
+ },
+ viaKeyboard: {
+ type: Boolean,
+ required: false
+ },
+ },
+ emits: ['closed'],
+ computed: {
+ keymap(): any {
+ return {
+ 'esc': () => this.$emit('closed'),
+ };
+ },
+ },
+ mounted() {
+ let left = this.ev.pageX + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
+ let top = this.ev.pageY + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
+
+ const width = this.$el.offsetWidth;
+ const height = this.$el.offsetHeight;
+
+ if (left + width - window.pageXOffset > window.innerWidth) {
+ left = window.innerWidth - width + window.pageXOffset;
+ }
+
+ if (top + height - window.pageYOffset > window.innerHeight) {
+ top = window.innerHeight - height + window.pageYOffset;
+ }
+
+ if (top < 0) {
+ top = 0;
+ }
+
+ if (left < 0) {
+ left = 0;
+ }
+
+ this.$el.style.top = top + 'px';
+ this.$el.style.left = left + 'px';
+
+ for (const el of Array.from(document.querySelectorAll('body *'))) {
+ el.addEventListener('mousedown', this.onMousedown);
+ }
+ },
+ beforeUnmount() {
+ for (const el of Array.from(document.querySelectorAll('body *'))) {
+ el.removeEventListener('mousedown', this.onMousedown);
+ }
+ },
+ methods: {
+ onMousedown(e) {
+ if (!contains(this.$el, e.target) && (this.$el != e.target)) this.$emit('closed');
+ },
+ }
+});
+</script>
+
+<style lang="scss" scoped>
+.nvlagfpb {
+ position: absolute;
+ z-index: 65535;
+}
+
+.fade-enter-active, .fade-leave-active {
+ transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
+ transform-origin: left top;
+}
+
+.fade-enter-from, .fade-leave-to {
+ opacity: 0;
+ transform: scale(0.9);
+}
+</style>