fchat-rising/components/Dropdown.vue

55 lines
1.9 KiB
Vue
Raw Normal View History

<template>
2019-09-17 17:14:14 +00:00
<div class="dropdown" @focusout="blur">
<a :class="linkClass" aria-haspopup="true" :aria-expanded="isOpen" @click.prevent="isOpen = !isOpen" href="#"
style="width:100%;text-align:left;align-items:center" role="button" tabindex="-1" ref="button">
<slot name="title">{{title}}</slot>
2018-07-20 01:12:26 +00:00
</a>
2019-09-17 17:14:14 +00:00
<div class="dropdown-menu" ref="menu" @mousedown.prevent.stop @click.prevent.stop="menuClick()">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
2019-01-03 17:38:17 +00:00
import {Component, Prop, Watch} from '@f-list/vue-ts';
import Vue from 'vue';
@Component
export default class Dropdown extends Vue {
isOpen = false;
2019-09-17 17:14:14 +00:00
@Prop({default: 'btn btn-secondary dropdown-toggle'})
readonly linkClass!: string;
@Prop
2018-03-28 13:51:05 +00:00
readonly keepOpen?: boolean;
2019-09-17 17:14:14 +00:00
@Prop
readonly title?: string;
2018-03-28 13:51:05 +00:00
2019-09-17 17:14:14 +00:00
@Watch('isOpen')
2018-03-28 13:51:05 +00:00
onToggle(): void {
const menu = this.$refs['menu'] as HTMLElement;
if(!this.isOpen) {
menu.style.cssText = '';
return;
}
2019-09-17 17:14:14 +00:00
menu.style.display = 'block';
const offset = menu.getBoundingClientRect();
menu.style.position = 'fixed';
menu.style.left = offset.right < window.innerWidth ? `${offset.left}px` : `${window.innerWidth - offset.width}px`;
menu.style.top = (offset.bottom < window.innerHeight) ? `${offset.top}px` :
`${offset.top - offset.height - (<HTMLElement>this.$el).offsetHeight}px`;
}
blur(event: FocusEvent): void {
let elm = <HTMLElement | null>event.relatedTarget;
while(elm) {
if(elm === this.$refs['menu']) return;
elm = elm.parentElement;
2018-03-28 13:51:05 +00:00
}
2019-09-17 17:14:14 +00:00
this.isOpen = false;
}
menuClick(): void {
if(!this.keepOpen) this.isOpen = false;
2018-03-28 13:51:05 +00:00
}
}
</script>