aboutsummaryrefslogtreecommitdiff
path: root/viewer/src/components/LdDropdown.vue
blob: 2ab3252c19285af2e31c593f7d20e0d020145c0d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<template>
  <div style="position:relative;">
    <Transition name="fade">
      <div
        v-if="model"
        ref="dropdown"
        class="scrollbar"
        :class="$style.dropdown"
        v-bind="attrs"
      >
        <div
          v-for="(option,idx) in props.list"
          :key="listKey ? option[props.listKey] : idx"
          :tabindex="props.tabindexRoot + idx"
          @click="emit('select', option)"
          @keypress.enter.space="emit('select', option)"
        >
          <slot
            name="option"
            :option="option"
          />
        </div>
        <slot
          v-if="!props.list.length"
          name="empty"
        />
      </div>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import { onClickOutside, onKeyStroke, useVModel } from '@vueuse/core';
import { ref, useAttrs, watch } from 'vue';

const props = defineProps({
  modelValue: { type: Boolean, required: true },
  // Vue 3 currently won't allow generics in props
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  list: { type: Array<any>, required: true },
  listKey: { type: [String, Number], default: null },
  tabindexRoot: { type: Number, required: true },
});
const emit = defineEmits(['update:modelValue', 'select', 'opening', 'closing']);
const model = useVModel(props, 'modelValue', emit);

const attrs = useAttrs();

const dropdown = ref();

watch(() => model.value, value => {
  if (value) emit('opening');
  else emit('closing');
});

onClickOutside(dropdown, closeDropdown);
onKeyStroke('Escape', closeDropdown);

function closeDropdown() {
  setTimeout(() => (model.value = false));
}
</script>
<script lang="ts">
export default {
  inheritAttrs: false,
};
</script>

<style lang="scss" module>
@import "~@/assets/scss/theme";

.dropdown {
  position: absolute;
  left: 0;
  z-index: 99;
  width: $layout-left;
  color: $input-color;
  background-color: $dropdown-item-color;
  padding: 4px 0px;
  > div {
    padding: 4px 0;
    margin: 2px; // For the focus border
    cursor: pointer;
    &:hover {
      background-color: $dropdown-item-hover-color;
    }
    &:focus {
      outline: solid 1px $button-active-color;
    }
  }
}
  </style>