Files
voiceon-character-admin/src/shared/ui/search-toolbar.tsx
2026-07-27 15:04:03 +09:00

38 lines
1.4 KiB
TypeScript

import { useEffect, useId, useRef } from "react";
import type { ReactNode } from "react";
export type SearchToolbarProps = {
readonly filters?: ReactNode;
readonly onQueryChange: (query: string) => void;
readonly onSearchChange: (search: string) => void;
readonly search: string;
};
export function SearchToolbar({ filters, onQueryChange, onSearchChange, search }: SearchToolbarProps) {
const searchId = useId();
const didMountRef = useRef(false);
useEffect(() => {
if (!didMountRef.current) {
didMountRef.current = true;
return undefined;
}
const timeoutId = window.setTimeout(() => onQueryChange(search), 300);
return () => window.clearTimeout(timeoutId);
}, [onQueryChange, search]);
return (
<section aria-label="검색 도구" className="flex flex-col gap-3 rounded-lg border border-border bg-card p-4 sm:flex-row sm:items-end sm:justify-between">
<div className="flex min-w-0 flex-1 flex-col gap-2">
<label className="text-sm font-semibold" htmlFor={searchId}>
</label>
<input className="rounded-md border border-input bg-card px-3 py-2 text-base text-foreground" id={searchId} onChange={(event) => onSearchChange(event.currentTarget.value)} type="search" value={search} />
</div>
{filters === undefined ? null : <div className="flex flex-col gap-2 sm:min-w-48">{filters}</div>}
</section>
);
}