ledger list clean + fix
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts" generic="T">
|
||||
import {vOnClickOutside} from '@vueuse/components';
|
||||
import {useVirtualList} from '@vueuse/core';
|
||||
import {computed, ref} from 'vue';
|
||||
|
||||
interface Props {
|
||||
items: T[];
|
||||
itemHeight?: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
itemHeight: 24,
|
||||
});
|
||||
|
||||
const modelValue = defineModel<T>();
|
||||
|
||||
const isOpen = ref(false);
|
||||
const currentIndex = ref(-1);
|
||||
const {list, scrollTo, containerProps, wrapperProps} = useVirtualList(computed(() => props.items), {
|
||||
itemHeight: () => props.itemHeight,
|
||||
overscan: 3,
|
||||
});
|
||||
|
||||
const moveDown = () => {
|
||||
currentIndex.value = currentIndex.value >= props.items.length - 1 ? 0 : currentIndex.value + 1;
|
||||
scrollTo(currentIndex.value);
|
||||
};
|
||||
const moveUp = () => {
|
||||
currentIndex.value = currentIndex.value <= 0 ? props.items.length - 1 : currentIndex.value - 1;
|
||||
scrollTo(currentIndex.value);
|
||||
};
|
||||
const select = (item?: T) => {
|
||||
modelValue.value = item;
|
||||
currentIndex.value = -1;
|
||||
isOpen.value = false;
|
||||
};
|
||||
const submit = () => {
|
||||
if (currentIndex.value >= 0 && currentIndex.value < props.items.length) {
|
||||
select(props.items[currentIndex.value]);
|
||||
} else if (modelValue.value === undefined && props.items.length > 0) {
|
||||
select(props.items[0]);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div @click="isOpen = true" v-on-click-outside="() => isOpen = false">
|
||||
<div class="fake-input" @keyup.enter="submit" @keyup.down="moveDown" @keyup.up="moveUp">
|
||||
<slot name="input" :value="modelValue" />
|
||||
</div>
|
||||
<div v-if="isOpen && items.length" class="z-20 absolute">
|
||||
<div v-bind="containerProps" class="rounded-b" style="height: 300px">
|
||||
<div v-bind="wrapperProps">
|
||||
<div v-for="s in list" :key="s.index"
|
||||
class="hover:bg-slate-700 cursor-pointer"
|
||||
:class="s.index === currentIndex ? 'bg-emerald-500' : 'bg-slate-500'"
|
||||
@click.stop="select(s.data)">
|
||||
<slot name="item" :item="s.data" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@reference "tailwindcss";
|
||||
.fake-input {
|
||||
@apply flex border bg-slate-500 rounded px-1 py-0.5;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user