upend/ui/src/components/utils/Selector.svelte

92 lines
1.9 KiB
Svelte
Raw Normal View History

<script lang="ts">
import { tick } from "svelte";
import Input from "./Input.svelte";
export let value = "";
export let type: "entity" | "attribute" | "value";
let options = [];
async function updateOptions(query: string) {
switch (type) {
case "entity":
throw new Error("unimplemented");
case "attribute":
const req = await fetch("/api/all/attributes");
const allAttributes: string[] = await req.json();
options = allAttributes.filter((attr) =>
attr.toLowerCase().includes(query.toLowerCase())
);
break;
case "value":
throw new Error("unimplemented");
}
}
$: updateOptions(value);
let inputFocused = false;
let hover = false;
$: visible = (inputFocused || hover) && Boolean(options.length);
</script>
<div class="selector">
<Input bind:value on:focusChange={(ev) => (inputFocused = ev.detail)} />
<ul
class="options"
class:visible
on:mouseenter={() => (hover = true)}
on:mouseleave={() => (hover = false)}
>
{#each options as option}
<li
on:click={() => {
value = option;
visible = false;
}}
>
{option}
</li>
{/each}
</ul>
</div>
<style lang="scss">
.selector {
position: relative;
}
.options {
position: absolute;
list-style: none;
margin: 0;
padding: 0;
border: 1px solid var(--foreground-lighter);
width: 100%;
border-radius: 4px;
margin-top: 2px;
background: var(--background);
font-size: smaller;
visibility: hidden;
opacity: 0;
transition: opacity 0.2s;
z-index: 99;
&.visible {
visibility: visible;
opacity: 1;
}
li {
cursor: pointer;
padding: 0.5em;
transition: background-color 0.2s;
&:hover {
background-color: var(--background-lighter);
}
}
}
</style>