import { CSSProperties, ChangeEvent, InputHTMLAttributes } from 'react'; export type SearchBarSize = "small" | "medium" | "large"; export interface SearchBarProps extends Omit, "size" | "onChange" | "type"> { value?: string; defaultValue?: string; onChange?: (event: ChangeEvent) => void; /** * Callback agnóstico que ejecuta la lógica de búsqueda. * El consumidor decide si hace fetch a API, filtra datos locales, etc. * Si devuelve una Promise y no se pasa `isFetching`, el Spinner interno * dura exactamente lo que tarda esa Promise (resolve/reject). */ onSearch?: (query: string) => void | Promise; /** Delay en ms antes de ejecutar la búsqueda (solo aplica si fireOn es 'change'). Default 500 */ debounceDelay?: number; /** Mínimo de caracteres para activar la búsqueda (solo aplica si fireOn es 'change'). Default 3 */ minCharacters?: number; /** * 'search': busca al presionar Enter o click en la lupa (expandida) * 'change': busca al cambiar el valor, respetando debounceDelay y minCharacters * Default 'change' */ fireOn?: "search" | "change"; /** Default true. Al vaciarse el input se dispara onClear + onSearch("") */ triggerOnClearWhenEmpty?: boolean; /** * Estado colapsado controlado. * Sin autoCollapse, el colapso post-blur es responsabilidad del consumidor * (collapsed + onCollapsedChange). */ collapsed?: boolean; /** Estado colapsado inicial (no controlado). Default false */ defaultCollapsed?: boolean; onCollapsedChange?: (collapsed: boolean) => void; /** * Solo para collapse NO controlado. Si el valor está vacío y el foco * sale del componente, se contrae automáticamente. Con valor, queda expandido. * Ignorado (con warning en dev) si se pasa `collapsed` controlado. * Default false. */ autoCollapse?: boolean; onClear?: () => void; /** Default false */ hideClearButton?: boolean; /** * Estado de fetching controlado. * Si se omite, el SearchBar lo deduce internamente cuando `onSearch` **devuelve** una Promise: * el Spinner dura exactamente lo que tarda esa Promise en resolverse o rechazarse. * No hay timeout propio; `debounceDelay` solo atrasa el disparo de `onSearch`, no la duración del Spinner. * Si se pasa `isFetching`, el consumidor controla el indicador por completo. */ isFetching?: boolean; /** Escala 1:1 con Figma: small=32px, medium=40px, large=48px. Default 'medium' */ size?: SearchBarSize; disabled?: boolean; placeholder?: string; className?: string; style?: CSSProperties; }