The selection of locations, events, roles, shifts and users using the native <select> element makes for awkward and difficult interactions. Add an alternative select control that fixes the issues with the poor handling and navigation of the control when having many options. The custom select component can handle the selection of either one or many entity from a ClientMap of entiteis with a name. Typing into the text box searches the entities by name, arrow keys can navigate and enter confirms the chosen entity by toggling it's presence in the selection.
64 lines
1.3 KiB
Vue
64 lines
1.3 KiB
Vue
<template>
|
|
<div
|
|
class="select"
|
|
@focusin="dropdownComponent?.focusin()"
|
|
@focusout="dropdownComponent?.focusout()"
|
|
@keyup.esc="dropdownComponent?.esc()"
|
|
>
|
|
<div class="selected">
|
|
<div
|
|
v-for="id of selectedIds"
|
|
:key="id"
|
|
class="item"
|
|
>
|
|
{{ entities.get(id)?.name ?? id }}
|
|
<button
|
|
@click="selectedIds.delete(id)"
|
|
>x</button>
|
|
</div>
|
|
</div>
|
|
<SelectDropdown
|
|
ref="dropdown"
|
|
v-model="selectedIds"
|
|
:multi="true"
|
|
:entities
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import type { ApiEntity } from '~/shared/types/api';
|
|
import type { Id } from '~/shared/types/common';
|
|
import type { ClientEntity } from '~/utils/client-entity';
|
|
|
|
const selectedIds = defineModel<Set<Id>>({ required: true });
|
|
defineProps<{
|
|
entities: ClientMap<ClientEntity<ApiEntity> & { name?: string }>,
|
|
}>();
|
|
|
|
const dropdownComponent = useTemplateRef("dropdown");
|
|
</script>
|
|
|
|
<style scoped>
|
|
.select {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
position: relative;
|
|
}
|
|
.selected {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0.2rem;
|
|
}
|
|
.item {
|
|
background-color: color-mix(in srgb, Canvas, CanvasText 10%);
|
|
border-radius: 0.3rem;
|
|
padding-inline: 0.2rem;
|
|
padding-block: 0.1rem;
|
|
margin-inline-end: 0.2rem;
|
|
white-space: pre-wrap;
|
|
}
|
|
.item button {
|
|
line-height: 0.7;
|
|
}
|
|
</style>
|