83 lines
1.9 KiB
Svelte
83 lines
1.9 KiB
Svelte
|
|
<script lang="ts">
|
||
|
|
import { Input } from '$shared/shadcn/ui/input';
|
||
|
|
import { Label } from '$shared/shadcn/ui/label';
|
||
|
|
import {
|
||
|
|
Content as PopoverContent,
|
||
|
|
Root as PopoverRoot,
|
||
|
|
Trigger as PopoverTrigger,
|
||
|
|
} from '$shared/shadcn/ui/popover';
|
||
|
|
import { useId } from 'bits-ui';
|
||
|
|
import {
|
||
|
|
type Snippet,
|
||
|
|
tick,
|
||
|
|
} from 'svelte';
|
||
|
|
|
||
|
|
interface Props {
|
||
|
|
id: string;
|
||
|
|
value: string;
|
||
|
|
class?: string;
|
||
|
|
placeholder?: string;
|
||
|
|
label?: string;
|
||
|
|
children: Snippet<[{ id: string }]> | undefined;
|
||
|
|
}
|
||
|
|
|
||
|
|
let {
|
||
|
|
id = 'search-bar',
|
||
|
|
value = $bindable(),
|
||
|
|
class: className,
|
||
|
|
placeholder,
|
||
|
|
label,
|
||
|
|
children,
|
||
|
|
}: Props = $props();
|
||
|
|
|
||
|
|
let open = $state(false);
|
||
|
|
let triggerRef = $state<HTMLInputElement>();
|
||
|
|
const contentId = useId(id);
|
||
|
|
|
||
|
|
function closeAndFocusTrigger() {
|
||
|
|
open = false;
|
||
|
|
tick().then(() => {
|
||
|
|
triggerRef?.focus();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleKeyDown(event: KeyboardEvent) {
|
||
|
|
if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter') {
|
||
|
|
event.preventDefault();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleInputClick() {
|
||
|
|
open = true;
|
||
|
|
tick().then(() => {
|
||
|
|
triggerRef?.focus();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<PopoverRoot>
|
||
|
|
<PopoverTrigger bind:ref={triggerRef}>
|
||
|
|
{#snippet child({ props })}
|
||
|
|
<div {...props} class="flex flex-row flex-1 w-full">
|
||
|
|
{#if label}
|
||
|
|
<Label for={id}>{label}</Label>
|
||
|
|
{/if}
|
||
|
|
<Input
|
||
|
|
id={id}
|
||
|
|
placeholder={placeholder}
|
||
|
|
bind:value={value}
|
||
|
|
onkeydown={handleKeyDown}
|
||
|
|
class="flex flex-row flex-1"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
{/snippet}
|
||
|
|
</PopoverTrigger>
|
||
|
|
|
||
|
|
<PopoverContent
|
||
|
|
onOpenAutoFocus={e => e.preventDefault()}
|
||
|
|
class="w-max"
|
||
|
|
>
|
||
|
|
{@render children?.({ id: contentId })}
|
||
|
|
</PopoverContent>
|
||
|
|
</PopoverRoot>
|