This commit is contained in:
Timothy Jaeryang Baek
2026-06-29 11:35:08 -05:00
parent 815446d5bb
commit 61cee42ded
10 changed files with 275 additions and 141 deletions
@@ -1,16 +1,23 @@
<script lang="ts">
import { tick } from 'svelte';
import { createEventDispatcher, tick } from 'svelte';
type Voice = {
id: string;
name?: string;
description?: string;
meta?: {
description?: string;
};
};
export let id = 'tts-voice';
export let value = '';
export let voices: Voice[] = [];
export let placeholder = '';
export let className = 'w-full';
const listboxId = 'tts-voice-options';
const dispatch = createEventDispatcher<{ select: Voice }>();
const listboxId = `${id}-options`;
let inputElement: HTMLInputElement | null = null;
let popupElement: HTMLDivElement | null = null;
@@ -21,8 +28,11 @@
.filter((voice) => {
const id = voice.id.toLowerCase();
const name = (voice.name ?? '').toLowerCase();
const description = (voice.description ?? voice.meta?.description ?? '').toLowerCase();
return query === '' || id.includes(query) || name.includes(query);
return (
query === '' || id.includes(query) || name.includes(query) || description.includes(query)
);
})
.slice(0, 8);
$: if (suggestionsOpen && filteredVoices.length > 0) {
@@ -52,6 +62,7 @@
const selectVoice = (voice: Voice) => {
value = voice.id;
suggestionsOpen = false;
dispatch('select', voice);
};
const handlePointerDown = (event: PointerEvent) => {
@@ -75,7 +86,8 @@
<input
bind:this={inputElement}
bind:value
class="w-full text-sm bg-transparent outline-hidden"
id={`${id}-input`}
class="{className} text-sm bg-transparent outline-hidden"
type="text"
{placeholder}
role="combobox"
@@ -110,14 +122,14 @@
use:portal
bind:this={popupElement}
id={listboxId}
class="fixed max-h-48 overflow-y-auto rounded-lg border border-gray-200 bg-white p-0.5 shadow-lg dark:border-gray-800 dark:bg-gray-850"
class="fixed max-h-48 overflow-y-auto rounded-2xl border border-gray-200 bg-white p-0.5 shadow-lg dark:border-gray-800 dark:bg-gray-850"
role="listbox"
style="z-index: 9999; top: 0; left: 0;"
>
{#each filteredVoices as voice (voice.id)}
<button
type="button"
class="flex w-full items-center justify-between gap-3 rounded-md px-2 py-1.5 text-left text-xs text-gray-700 transition-colors hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-800"
class="flex w-full items-center justify-between gap-3 rounded-xl px-2 py-[5px] text-left text-xs text-gray-700 transition-colors hover:bg-gray-50 dark:text-gray-200 dark:hover:bg-gray-800"
role="option"
aria-selected={value === voice.id}
on:mousedown={(event) => {