import React, { useState, useRef, useEffect, useMemo } from "react"; import { Stack, Button, Text } from "@mantine/core"; import { useTranslation } from "react-i18next"; import { ToolRegistryEntry } from "../../../data/toolsTaxonomy"; import { TextInput } from "../../shared/TextInput"; import "./ToolPicker.css"; interface ToolSearchProps { value: string; onChange: (value: string) => void; toolRegistry: Readonly>; onToolSelect?: (toolId: string) => void; mode: "filter" | "dropdown" | "unstyled"; selectedToolKey?: string | null; placeholder?: string; hideIcon?: boolean; onFocus?: () => void; autoFocus?: boolean; } const ToolSearch = ({ value, onChange, toolRegistry, onToolSelect, mode = "filter", selectedToolKey, placeholder, hideIcon = false, onFocus, autoFocus = false, }: ToolSearchProps) => { const { t } = useTranslation(); const [dropdownOpen, setDropdownOpen] = useState(false); const searchRef = useRef(null); const dropdownRef = useRef(null); const filteredTools = useMemo(() => { if (!value.trim()) return []; return Object.entries(toolRegistry) .filter(([id, tool]) => { if (mode === "dropdown" && id === selectedToolKey) return false; return ( tool.name.toLowerCase().includes(value.toLowerCase()) || tool.description.toLowerCase().includes(value.toLowerCase()) ); }) .slice(0, 6) .map(([id, tool]) => ({ id, tool })); }, [value, toolRegistry, mode, selectedToolKey]); const handleSearchChange = (searchValue: string) => { onChange(searchValue); if (mode === "dropdown") { setDropdownOpen(searchValue.trim().length > 0 && filteredTools.length > 0); } }; useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( searchRef.current && dropdownRef.current && !searchRef.current.contains(event.target as Node) && !dropdownRef.current.contains(event.target as Node) ) { setDropdownOpen(false); } }; document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); }, []); // Auto-focus the input when requested useEffect(() => { if (autoFocus && searchRef.current) { setTimeout(() => { searchRef.current?.focus(); }, 10); } }, [autoFocus]); const searchInput = ( search} autoComplete="off" onFocus={onFocus} /> ); if (mode === "filter") { return
{searchInput}
; } if (mode === "unstyled") { return searchInput; } return (
{searchInput} {dropdownOpen && filteredTools.length > 0 && (
{filteredTools.map(({ id, tool }) => ( ))}
)}
); }; export default ToolSearch;