Vendaweb-portal/components/SearchInput.tsx

109 lines
3.7 KiB
TypeScript
Raw Normal View History

2026-01-08 12:09:16 +00:00
import React from "react";
interface SearchInputProps {
value: string;
onChange: (value: string) => void;
onSearch: () => void;
placeholder?: string;
loading?: boolean;
disabled?: boolean;
minLength?: number;
}
/**
* SearchInput Component
* Componente reutilizável para campo de busca com botão de pesquisa
*
* @param value - Valor atual do input
* @param onChange - Callback quando o valor muda
* @param onSearch - Callback quando o botão de busca é clicado ou Enter é pressionado
* @param placeholder - Texto placeholder do input
* @param loading - Indica se está carregando
* @param disabled - Indica se está desabilitado
* @param minLength - Tamanho mínimo para habilitar a busca
*/
const SearchInput: React.FC<SearchInputProps> = ({
value,
onChange,
onSearch,
placeholder = "Ex: Cimento, Tijolo, Furadeira...",
loading = false,
disabled = false,
minLength = 3,
}) => {
const isValid = value.trim().length >= minLength;
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter" && !loading && isValid) {
onSearch();
}
};
return (
<div className="relative group mb-0 lg:mb-10 max-w-full lg:max-w-4xl mx-auto">
<input
type="text"
placeholder={placeholder}
className="w-full p-3 lg:p-5 pl-10 lg:pl-14 rounded-xl lg:rounded-2xl bg-white shadow-sm lg:shadow-lg shadow-slate-200 outline-none border-2 border-transparent focus:border-orange-500 transition-all text-sm lg:text-base font-medium disabled:opacity-50 disabled:cursor-not-allowed"
value={value}
onChange={(e) => onChange(e.target.value)}
onKeyDown={handleKeyDown}
disabled={disabled || loading}
/>
<button
onClick={onSearch}
disabled={loading || !isValid}
className="absolute right-1.5 lg:right-2 top-1.5 lg:top-2 bottom-1.5 lg:bottom-2 bg-[#002147] text-white px-3 lg:px-6 rounded-lg lg:rounded-xl font-black uppercase text-[10px] lg:text-xs tracking-widest hover:bg-[#003366] transition-all shadow-lg disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center touch-manipulation"
>
{loading ? (
<>
<svg
className="animate-spin -ml-1 mr-2 h-4 w-4 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
>
<circle
className="opacity-25"
cx="12"
cy="12"
r="10"
stroke="currentColor"
strokeWidth="4"
></circle>
<path
className="opacity-75"
fill="currentColor"
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
></path>
</svg>
Buscando...
</>
) : (
"Buscar"
)}
</button>
{value.trim().length > 0 && value.trim().length < minLength && (
<p className="absolute -bottom-6 left-0 text-xs text-slate-400 font-medium mt-1">
Digite pelo menos {minLength} caracteres
</p>
)}
<svg
className="absolute left-3 lg:left-8 top-1/2 -translate-y-1/2 w-4 h-4 lg:w-5 lg:h-5 text-slate-300 group-focus-within:text-orange-500 transition-colors"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2.5"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
/>
</svg>
</div>
);
};
export default SearchInput;