fchat-rising/components/Dropdown.vue

53 lines
1.9 KiB
Vue
Raw Normal View History

<template>
<div class="dropdown">
2018-07-20 01:12:26 +00:00
<a class="form-control custom-select" aria-haspopup="true" :aria-expanded="isOpen" @click="isOpen = true"
2018-03-28 13:51:05 +00:00
@blur="isOpen = false" style="width:100%;text-align:left;display:flex;align-items:center" role="button" tabindex="-1">
<div style="flex:1">
<slot name="title" style="flex:1"></slot>
</div>
2018-07-20 01:12:26 +00:00
</a>
2018-03-28 13:51:05 +00:00
<div class="dropdown-menu" :style="open ? 'display:block' : ''" @mousedown.stop.prevent @click="isOpen = false"
ref="menu">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
2018-03-28 13:51:05 +00:00
import {Prop, Watch} from 'vue-property-decorator';
@Component
export default class Dropdown extends Vue {
isOpen = false;
2018-03-28 13:51:05 +00:00
@Prop()
readonly keepOpen?: boolean;
get open(): boolean {
return this.keepOpen || this.isOpen;
}
@Watch('open')
onToggle(): void {
const menu = this.$refs['menu'] as HTMLElement;
if(!this.isOpen) {
menu.style.cssText = '';
return;
}
let element: HTMLElement | null = this.$el;
while(element !== null) {
if(getComputedStyle(element).position === 'fixed') {
menu.style.display = 'block';
const offset = menu.getBoundingClientRect();
menu.style.position = 'fixed';
menu.style.left = `${offset.left}px`;
menu.style.top = (offset.bottom < window.innerHeight) ? menu.style.top = `${offset.top}px` :
`${this.$el.getBoundingClientRect().top - offset.bottom + offset.top}px`;
break;
}
element = element.parentElement;
}
}
}
</script>