1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-04-09 07:07:49 +00:00
bramw_baserow/web-frontend/modules/core/components/Dropdown.vue
2020-03-31 14:15:27 +00:00

150 lines
3.6 KiB
Vue

<template>
<div class="dropdown">
<a class="dropdown-selected" @click="show()">
<template v-if="hasValue()">
<i
v-if="icon"
class="dropdown-selected-icon fas"
:class="'fa-' + icon"
></i>
{{ name }}
</template>
<template v-if="!hasValue()">
Make a choice
</template>
<i class="dropdown-toggle-icon fas fa-caret-down"></i>
</a>
<div class="dropdown-items" :class="{ hidden: !open }">
<div class="select-search">
<i class="select-search-icon fas fa-search"></i>
<input
ref="search"
v-model="query"
type="text"
class="select-search-input"
placeholder="Search field types"
@keyup="search(query)"
/>
</div>
<ul class="select-items">
<slot></slot>
</ul>
</div>
</div>
</template>
<script>
import { isElement } from '@baserow/modules/core/utils/dom'
// @TODO focus on tab
export default {
name: 'Dropdown',
props: {
value: {
type: [String, Number, Boolean, Object],
required: true,
},
},
data() {
return {
open: false,
name: null,
icon: null,
query: '',
}
},
watch: {
/**
* If the value changes we have to update the visible name and icon.
*/
value(newValue) {
this.setDisplayValue(newValue)
},
},
/**
* When the dropdown first loads we have to check if there already is a value, if
* there is, we have to update the displayed name and icon.
*/
mounted() {
if (this.hasValue()) {
this.setDisplayValue(this.value)
}
},
methods: {
/**
* Returns true if there is a value.
* @return {boolean}
*/
hasValue() {
return !!this.value
},
/**
* Shows the lists of choices, so a user can change the value.
*/
show() {
this.open = true
this.$emit('show')
// We have to wait for the input to be visible before we can focus.
this.$nextTick(() => {
this.$refs.search.focus()
})
// If the user clicks outside the dropdown while the list of choices of open we
// have to hide them.
this.$el.clickOutsideEvent = (event) => {
if (
// Check if the context menu is still open
this.open &&
// If the click was outside the context element because we want to ignore
// clicks inside it.
!isElement(this.$el, event.target)
) {
this.hide()
}
}
document.body.addEventListener('click', this.$el.clickOutsideEvent)
},
/**
* Hides the list of choices
*/
hide() {
this.open = false
this.$emit('hide')
// Make sure that all the items are visible the next time we open the dropdown.
this.query = ''
this.search(this.query)
document.body.removeEventListener('click', this.$el.clickOutsideEvent)
},
/**
* Selects a new value which will also be
*/
select(value) {
this.$emit('input', value)
this.$emit('change', value)
this.hide()
},
/**
* If not empty it will only show children that contain the given query.
*/
search(query) {
this.$children.forEach((item) => {
item.search(query)
})
},
/**
* Changes the selected name and icon of the dropdown based on the provided value.
*/
setDisplayValue(value) {
this.$children.forEach((item) => {
if (item.value === value) {
this.name = item.name
this.icon = item.icon
}
})
},
},
}
</script>