<template>
	<div class="dropdown" :class="{ 'form-floating': label }">
		<input type="text" class="form-control" placeholder=" " @focus="option_open" @input="option_filter" v-model="x_modelValue" @keydown.down="option_down" @keydown.up="option_up" @keydown.enter="option_enter" />
		<ul class="dropdown-menu shadow" :class="{ show: (open) && (results.length > 0) }">
			<li class="loading" v-if="!items">Loading results...</li>
			<li v-else v-for="(result, i) in results" :key="i" @click="option_click(result)" class="dropdown-item" :class="{ 'is-active': i === index }">{{ result }}</li>
		</ul>
		<label v-if="label">{{label}}</label>
	</div>
</template>

<style scoped>
	.dropdown-menu {
		width: 100%;
		max-height: 10rem;
		overflow: auto;
	}

	.dropdown-item {
		cursor: default;
	}

	.dropdown-item.is-active,
	.dropdown-item:hover {
		background-color: var(--bs-primary);
		color: var(--bs-body-bg);
	}
</style>

<script>
	export default {
		props: {
			modelValue: {
				type: String,
				default: ''
			},
			items: {
				type: Array,
				required: false,
				default: () => [],
			},
			label: String
		},
		emits: [
			'update:modelValue'
		],
		data() {
			return {
				x_modelValue: this.modelValue,
				results: [],
				open: false,
				index: -1,
			};
		},
		watch: {
			modelValue(val) {
				this.x_modelValue = val;
			},
			x_modelValue(val) {
				this.$emit('update:modelValue', val);
			}
		},
		mounted() {
			this.x_modelValue = this.modelValue;
			document.addEventListener('click', this.option_close)
		},
		destroyed() {
			document.removeEventListener('click', this.option_close)
		},
		methods: {
			option_open() {
				if(this.items) {
					this.results = this.items;
					this.open = true;
				}
			},
			option_filter() {
				if(this.items) {
					if(this.x_modelValue) {
						var selection = this.x_modelValue.toLowerCase();
						this.results = this.items.filter((item) => item.toLowerCase().indexOf(selection) >= 0);
					} else this.results = this.items;
					this.open = true;
				}
			},
			option_down() {
				if(this.index < this.results.length) this.index++;
			},
			option_up() {
				if(this.index > 0) this.index--;
			},
			option_enter() {
				this.x_modelValue = this.results[this.index];
				this.open = false;
				this.index = -1;
			},
			option_click(result) {
				this.x_modelValue = result;
				this.open = false;
			},
			option_close(evt) {
				if(!this.$el.contains(evt.target)) {
					this.open = false;
					this.index = -1;
				}
			}
		}
	};
</script>
