fix click outside
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { vOnClickOutside } from '@vueuse/components';
|
||||||
import { useEventListener, useVModel } from '@vueuse/core';
|
import { useEventListener, useVModel } from '@vueuse/core';
|
||||||
import { watch } from 'vue';
|
import { watch } from 'vue';
|
||||||
|
|
||||||
@@ -37,7 +38,7 @@ useEventListener('keyup', e => {
|
|||||||
<div class="fixed inset-0">
|
<div class="fixed inset-0">
|
||||||
<div class="absolute bg-black opacity-80 inset-0 z-0" />
|
<div class="absolute bg-black opacity-80 inset-0 z-0" />
|
||||||
<div class="absolute grid inset-0">
|
<div class="absolute grid inset-0">
|
||||||
<div class="justify-self-center m-auto">
|
<div class="justify-self-center m-auto" v-on-click-outside="() => isOpen = false">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useFocus, useVirtualList, useVModel } from '@vueuse/core';
|
import { vOnClickOutside } from '@vueuse/components';
|
||||||
|
import { useVirtualList, useVModel } from '@vueuse/core';
|
||||||
|
import log from 'loglevel';
|
||||||
import { nextTick, ref, watch, watchEffect } from 'vue';
|
import { nextTick, ref, watch, watchEffect } from 'vue';
|
||||||
import { MarketType, searchMarketTypes } from './MarketType';
|
import { MarketType, searchMarketTypes } from './MarketType';
|
||||||
import MarketTypeLabel from "./MarketTypeLabel.vue";
|
import MarketTypeLabel from "./MarketTypeLabel.vue";
|
||||||
@@ -18,9 +20,7 @@ const emit = defineEmits<Emits>();
|
|||||||
|
|
||||||
const value = useVModel(props, 'modelValue', emit);
|
const value = useVModel(props, 'modelValue', emit);
|
||||||
|
|
||||||
const input = ref<HTMLInputElement>();
|
const isOpen = ref(false);
|
||||||
const {focused} = useFocus(input);
|
|
||||||
|
|
||||||
const name = ref('');
|
const name = ref('');
|
||||||
const suggestions = ref<MarketType[]>([]);
|
const suggestions = ref<MarketType[]>([]);
|
||||||
const currentIndex = ref(-1);
|
const currentIndex = ref(-1);
|
||||||
@@ -46,6 +46,7 @@ const moveUp = () => {
|
|||||||
scrollTo(currentIndex.value);
|
scrollTo(currentIndex.value);
|
||||||
}
|
}
|
||||||
const select = (type: MarketType) => {
|
const select = (type: MarketType) => {
|
||||||
|
log.debug('Select:', type);
|
||||||
value.value = type;
|
value.value = type;
|
||||||
currentIndex.value = -1;
|
currentIndex.value = -1;
|
||||||
suggestions.value = [];
|
suggestions.value = [];
|
||||||
@@ -77,7 +78,7 @@ watch(() => props.modelValue, async v => {
|
|||||||
watchEffect(async () => {
|
watchEffect(async () => {
|
||||||
const search = name.value.split('\t')[0];
|
const search = name.value.split('\t')[0];
|
||||||
|
|
||||||
if (!focused.value || search.length < 3) {
|
if (!isOpen.value || search.length < 3) {
|
||||||
suggestions.value = [];
|
suggestions.value = [];
|
||||||
} else {
|
} else {
|
||||||
suggestions.value = await searchMarketTypes(search);
|
suggestions.value = await searchMarketTypes(search);
|
||||||
@@ -87,16 +88,38 @@ watchEffect(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div @click="() => isOpen = true" v-on-click-outside="() => isOpen = false">
|
||||||
<input ref="input" type="text" class="w-96" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
|
<div class="fake-input">
|
||||||
|
<img v-if="value?.id" :src="`https://images.evetech.net/types/${value.id}/icon`" />
|
||||||
|
<input type="text" v-model="name" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp" />
|
||||||
|
</div>
|
||||||
<div v-if="suggestions.length > 1" class="z-10 absolute w-96">
|
<div v-if="suggestions.length > 1" class="z-10 absolute w-96">
|
||||||
<div v-bind="containerProps" style="height: 300px">
|
<div v-bind="containerProps" style="height: 300px">
|
||||||
<div v-bind="wrapperProps">
|
<div v-bind="wrapperProps">
|
||||||
<div v-for="s in list" :key="s.index" class="hover:bg-slate-700" :class="{'bg-slate-500': s.index !== currentIndex, 'bg-emerald-500': s.index === currentIndex}" @click="$emit('update:modelValue', s.data)">
|
<div v-for="s in list" :key="s.index" class="hover:bg-slate-700" :class="{'bg-slate-500': s.index !== currentIndex, 'bg-emerald-500': s.index === currentIndex}" @click="select(s.data)">
|
||||||
<MarketTypeLabel :id="s.data.id" :name="s.data.name" class="whitespace-nowrap overflow-hidden cursor-pointer" hideCopy @click="select(s.data)" />
|
<MarketTypeLabel :id="s.data.id" :name="s.data.name" class="whitespace-nowrap overflow-hidden cursor-pointer" hideCopy />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="postcss">
|
||||||
|
.fake-input {
|
||||||
|
@apply w-96 flex border bg-slate-500 rounded px-1;
|
||||||
|
|
||||||
|
&:has(> input:focus-visible) {
|
||||||
|
outline: -webkit-focus-ring-color auto 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> input {
|
||||||
|
@apply w-full border-none bg-transparent block focus-visible:outline-none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
> img {
|
||||||
|
@apply inline-block w-5 h-5 me-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user