<template> <div class="dropdown"> <a class="form-control custom-select" aria-haspopup="true" :aria-expanded="isOpen" @click="isOpen = true" @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> </a> <div class="dropdown-menu" :style="open ? {display: 'block'} : undefined" @mousedown.stop.prevent @click="isOpen = false" ref="menu"> <slot></slot> </div> </div> </template> <script lang="ts"> import {Component, Prop, Watch} from '@f-list/vue-ts'; import Vue from 'vue'; @Component export default class Dropdown extends Vue { isOpen = false; @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>