mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-30 21:21:09 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			101 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			101 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div v-click-outside="clickOutsideMenu" class="search-select" >
 | |
|     <div
 | |
|       class="activator"
 | |
|       @click="toggleSearchMenu">
 | |
|       <slot name="activator" />
 | |
|     </div>
 | |
|     <transition name="fade">
 | |
|       <div
 | |
|         v-if="showMenu"
 | |
|         :class="{'selector-menu-above': isAbove}"
 | |
|         class="selector-menu"
 | |
|       >
 | |
| 
 | |
|         <slot />
 | |
| 
 | |
|       </div>
 | |
|     </transition>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| export default {
 | |
|   props: {
 | |
|     toggle: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     openDirection: {
 | |
|       type: String,
 | |
|       default: ''
 | |
|     },
 | |
|     maxHeight: {
 | |
|       type: Number,
 | |
|       default: 180
 | |
|     }
 | |
|   },
 | |
|   data () {
 | |
|     return {
 | |
|       showMenu: false,
 | |
|       preferredOpenDirection: 'below',
 | |
|       optimizedHeight: null
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     isAbove () {
 | |
|       if (this.openDirection === 'above' || this.openDirection === 'top') {
 | |
|         return true
 | |
|       } else if (this.openDirection === 'below' || this.openDirection === 'bottom') {
 | |
|         return false
 | |
|       } else {
 | |
|         return this.preferredOpenDirection === 'above'
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     toggleSearchMenu () {
 | |
|       this.adjustPosition()
 | |
|       if (this.toggle) {
 | |
|         this.showMenu = !this.showMenu
 | |
|       } else {
 | |
|         this.showMenu = true
 | |
|       }
 | |
|     },
 | |
|     clickOutsideMenu () {
 | |
|       this.showMenu = false
 | |
|     },
 | |
|     open () {
 | |
|       this.showMenu = true
 | |
|     },
 | |
|     close () {
 | |
|       this.showMenu = false
 | |
|     },
 | |
|     adjustPosition () {
 | |
|       if (typeof window === 'undefined') return
 | |
| 
 | |
|       const spaceAbove = this.$el.getBoundingClientRect().top
 | |
|       const spaceBelow = window.innerHeight - this.$el.getBoundingClientRect().bottom
 | |
|       const hasEnoughSpaceBelow = spaceBelow > this.maxHeight
 | |
| 
 | |
|       if (hasEnoughSpaceBelow || spaceBelow > spaceAbove || this.openDirection === 'below' || this.openDirection === 'bottom') {
 | |
|         this.preferredOpenDirection = 'below'
 | |
|         this.optimizedHeight = Math.min(spaceBelow - 20, this.maxHeight)
 | |
|       } else {
 | |
|         this.preferredOpenDirection = 'above'
 | |
|         this.optimizedHeight = Math.min(spaceAbove - 20, this.maxHeight)
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style>
 | |
| .fade-enter-active, .fade-leave-active {
 | |
|   transition: opacity .5s;
 | |
| }
 | |
| .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
 | |
|   opacity: 0;
 | |
| }
 | |
| </style>
 |