Ka-Note/ka-note/client/src/lib/components/DarkSelect.svelte

70 lines
2.0 KiB
Svelte

<script lang="ts">
import { ChevronDown } from 'lucide-svelte';
interface Option {
value: string;
label: string;
}
interface Props {
value: string;
options: Option[];
class?: string;
onchange?: (value: string) => void;
}
let { value = $bindable(), options, class: cls = '', onchange }: Props = $props();
let open = $state(false);
let container: HTMLDivElement;
let button: HTMLButtonElement;
let openUp = $state(false);
function calcDirection() {
if (!button) return;
const rect = button.getBoundingClientRect();
const spaceBelow = window.innerHeight - rect.bottom;
openUp = spaceBelow < 260; // less than max-h-60 (240px) + margin
}
const selected = $derived(options.find(o => o.value === value) ?? options[0]);
function select(v: string) {
value = v;
open = false;
onchange?.(v);
}
function onKeydown(e: KeyboardEvent) {
if (e.key === 'Escape') open = false;
}
</script>
<svelte:window onclick={(e) => { if (container && !container.contains(e.target as Node)) open = false; }} onkeydown={onKeydown} />
<div bind:this={container} class="relative {cls}">
<button
bind:this={button}
type="button"
class="flex w-full items-center justify-between gap-2 rounded border border-border bg-white/10 px-3 py-2 text-sm text-white hover:bg-white/15 focus:border-accent focus:outline-none"
onclick={() => { calcDirection(); open = !open; }}
>
<span class="truncate">{selected?.label ?? ''}</span>
<ChevronDown size={14} class="flex-shrink-0 text-muted transition-transform {open ? 'rotate-180' : ''}" />
</button>
{#if open}
<div class="absolute left-0 z-50 min-w-full rounded-lg border border-border bg-surface shadow-xl py-1 max-h-60 overflow-y-auto {openUp ? 'bottom-full mb-1' : 'top-full mt-1'}">
{#each options as opt}
<button
type="button"
class="w-full px-3 py-2 text-left text-sm transition-colors {opt.value === value ? 'bg-accent/20 text-accent' : 'text-white hover:bg-white/10'}"
onclick={() => select(opt.value)}
>
{opt.label}
</button>
{/each}
</div>
{/if}
</div>