// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. ========= import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { TooltipSimple } from '@/components/ui/tooltip'; import { cn } from '@/lib/utils'; import { AnimatePresence, motion } from 'framer-motion'; import { Search, X } from 'lucide-react'; import { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; export type SearchInputVariant = 'default' | 'icon'; interface SearchInputProps { value: string; onChange: (e: React.ChangeEvent) => void; placeholder?: string; variant?: SearchInputVariant; /** Optional: called when user presses Enter in the field (e.g. to submit search) */ onSearch?: () => void; /** Tooltip for the search icon button (icon variant). Defaults to agents.search-tooltip */ searchTooltip?: string; /** Tooltip for the clear (X) button (icon variant). Defaults to agents.clear-search-tooltip */ clearTooltip?: string; } const COLLAPSED_WIDTH = 40; const EXPANDED_WIDTH = 240; export default function SearchInput({ value, onChange, placeholder, variant = 'default', onSearch, searchTooltip, clearTooltip, }: SearchInputProps) { const { t } = useTranslation(); const inputRef = useRef(null); const [userExpanded, setUserExpanded] = useState(false); const isExpanded = userExpanded || value.length > 0; const expand = useCallback(() => { setUserExpanded(true); }, []); const collapse = useCallback(() => { setUserExpanded(false); onChange({ target: { value: '' } } as React.ChangeEvent); }, [onChange]); useEffect(() => { if (userExpanded && inputRef.current) { const id = requestAnimationFrame(() => { inputRef.current?.focus(); }); return () => cancelAnimationFrame(id); } }, [userExpanded]); const searchLabel = searchTooltip ?? t('agents.search-tooltip'); const clearLabel = clearTooltip ?? t('agents.clear-search-tooltip'); const place = placeholder ?? t('setting.search-mcp'); if (variant === 'icon') { return ( {!isExpanded ? ( ) : ( { if (value.length === 0) setUserExpanded(false); }} onKeyDown={(e) => { if (e.key === 'Enter') { onSearch?.(); } }} className="h-6 min-w-0 flex-1 bg-transparent pl-2 text-label-sm text-text-heading outline-none placeholder:text-text-label" /> )} ); } return (
} />
); }