Files
frontend-svelte/src/shared/ui/SearchBar/SearchBar.svelte

97 lines
2.5 KiB
Svelte
Raw Normal View History

<!--
Component: SearchBar
Search input with popover dropdown for results/suggestions
- Features keyboard navigation (ArrowDown/Up/Enter) and auto-focus prevention on popover open.
- The input field serves as the popover trigger.
-->
<script lang="ts">
import { Input } from '$shared/shadcn/ui/input';
import ScanSearchIcon from '@lucide/svelte/icons/scan-search';
import { useId } from 'bits-ui';
interface Props {
/**
* Unique identifier for the input element
*/
id?: string;
/**
* Current search value (bindable)
*/
value: string;
/**
* Whether popover is open (bindable)
*/
isOpen?: boolean;
/**
* Additional CSS classes for the container
*/
class?: string;
/**
* Placeholder text for the input
*/
placeholder?: string;
/**
* Optional label displayed above the input
*/
label?: string;
}
let {
id = 'search-bar',
value = $bindable(''),
isOpen = $bindable(false),
class: className,
placeholder,
}: Props = $props();
2026-01-13 20:09:30 +03:00
let triggerRef = $state<HTMLInputElement>(null!);
2026-01-14 15:27:41 +03:00
// svelte-ignore state_referenced_locally
const contentId = useId(id);
function handleKeyDown(event: KeyboardEvent) {
if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter') {
event.preventDefault();
}
}
function handleInputClick() {
isOpen = true;
}
</script>
<div class="relative w-full">
<div class="absolute left-5 top-1/2 -translate-y-1/2 pointer-events-none z-10">
<ScanSearchIcon class="size-4 stroke-gray-400 stroke-[1.5]" />
</div>
<Input
id={id}
placeholder={placeholder}
bind:value={value}
onkeydown={handleKeyDown}
onclick={handleInputClick}
class="
h-16 w-full text-base
backdrop-blur-md bg-white/80
border border-gray-300/50
shadow-[0_1px_3px_rgba(0,0,0,0.04)]
focus-visible:border-gray-400/60
focus-visible:outline-none
focus-visible:ring-1
focus-visible:ring-gray-400/30
focus-visible:bg-white/90
hover:bg-white/90
hover:border-gray-400/60
text-gray-900
placeholder:text-gray-400
placeholder:font-mono
placeholder:text-sm
placeholder:tracking-wide
pl-14 pr-6
rounded-xl
transition-all duration-200
font-medium
"
/>
</div>