127 lines
3.0 KiB
Svelte
127 lines
3.0 KiB
Svelte
<style>
|
|
img {
|
|
width: 'auto';
|
|
height: 90%;
|
|
flex-shrink: 0;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
import { clickOutside } from '$lib/helpers/clickOutside.js';
|
|
import Check from '$lib/icons/Check.svelte';
|
|
import Selector from '$lib/icons/Selector.svelte';
|
|
import Button from './Button.svelte';
|
|
|
|
export let title = 'Bitte wählen';
|
|
export let options = [];
|
|
|
|
export let onChange = null;
|
|
export let selected = -1;
|
|
export let disabled = false;
|
|
|
|
let classNames = '';
|
|
export { classNames as class };
|
|
|
|
let showOptions = false;
|
|
|
|
const selectOnChange = (index) => {
|
|
setTimeout(() => {
|
|
hideShowOptions();
|
|
}, 0);
|
|
if (typeof onChange == 'function') onChange(index);
|
|
};
|
|
|
|
const toggleShowOptions = () => {
|
|
showOptions = !showOptions;
|
|
};
|
|
|
|
const hideShowOptions = () => {
|
|
showOptions = false;
|
|
};
|
|
|
|
$: selected = selected ?? -1;
|
|
$: selectedItem =
|
|
selected >= 0
|
|
? options[selected]
|
|
: {
|
|
title,
|
|
img: null
|
|
};
|
|
</script>
|
|
|
|
<div class={classNames}>
|
|
<div use:clickOutside on:click_outside={hideShowOptions} class="relative mt-1">
|
|
<Button
|
|
on:click={toggleShowOptions}
|
|
{disabled}
|
|
type="button"
|
|
variant="white"
|
|
fullWidth
|
|
align="left"
|
|
class="relative cursor-default justify-start py-2 pl-3 pr-10 text-left"
|
|
>
|
|
<span class="flex h-6 items-center">
|
|
{#if selectedItem.img}
|
|
<img src={selectedItem.img} alt={selectedItem.alt} />
|
|
{/if}
|
|
<span class="ml-3 block truncate">
|
|
{selectedItem.title}
|
|
</span>
|
|
</span>
|
|
<span class="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
|
|
<Selector />
|
|
</span>
|
|
</Button>
|
|
|
|
<div
|
|
class:hidden={!showOptions}
|
|
class="absolute z-10 mt-1 w-full rounded-md bg-white shadow-lg"
|
|
>
|
|
<ul
|
|
tabindex="-1"
|
|
role="listbox"
|
|
aria-labelledby="listbox-label"
|
|
class="max-h-48 overflow-auto rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
|
|
>
|
|
<!--
|
|
Select option, manage highlight styles based on mouseenter/mouseleave and keyboard navigation.
|
|
|
|
Highlighted: "text-white bg-indigo-600", Not Highlighted: "text-gray-900"
|
|
-->
|
|
{#each options as option, index}
|
|
<li
|
|
on:click={() => {
|
|
selectOnChange(index);
|
|
}}
|
|
id="listbox-item-0"
|
|
role="option"
|
|
class="group relative cursor-default select-none py-2 pl-3 pr-9 text-gray-900 hover:bg-blue-500 hover:text-white"
|
|
>
|
|
<div class="flex h-6 items-center">
|
|
{#if option.img}
|
|
<img src={option.img} alt={option.alt} />
|
|
{/if}
|
|
<!-- Selected: "font-bold", Not Selected: "font-normal" -->
|
|
<span
|
|
class:font-bold={selected === index}
|
|
class:font-normal={!selected === index}
|
|
class:ml-3={option.img}
|
|
class="block truncate"
|
|
>
|
|
{option.title}
|
|
</span>
|
|
</div>
|
|
{#if selected === index}
|
|
<span
|
|
class="absolute inset-y-0 right-0 flex items-center pr-4 text-blue-500 group-hover:text-white"
|
|
>
|
|
<Check />
|
|
</span>
|
|
{/if}
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|