diff --git a/src/components/panel/saved-connections/index.tsx b/src/components/panel/saved-connections/index.tsx index 070d3174..b0d85cfc 100644 --- a/src/components/panel/saved-connections/index.tsx +++ b/src/components/panel/saved-connections/index.tsx @@ -133,7 +133,9 @@ export default function SavedConnections({ const [expandedGroups, setExpandedGroups] = useState>(new Set()); const [selectedConnectionIds, setSelectedConnectionIds] = useState>(new Set()); const [filterText, setFilterText] = useState(""); + const [isSearchExpanded, setIsSearchExpanded] = useState(false); const [keyboardActiveConnectionId, setKeyboardActiveConnectionId] = useState(null); + const searchInputRef = useRef(null); const searchExpandedBaseRef = useRef | null>(null); const searchAutoExpandedGroupIdsRef = useRef>(new Set()); const previousKeywordRef = useRef(""); @@ -175,6 +177,19 @@ export default function SavedConnections({ [savedConnections], ); + useEffect(() => { + if (!isSearchExpanded) return; + + const frame = window.requestAnimationFrame(() => { + const input = searchInputRef.current; + if (!input) return; + input.focus(); + input.select(); + }); + + return () => window.cancelAnimationFrame(frame); + }, [isSearchExpanded]); + // ── Derived tree ────────────────────────────────────────────────────────── const { rootNodes, ungrouped } = useMemo(() => { const filtered = keyword @@ -606,9 +621,21 @@ export default function SavedConnections({ }; const handleSearchKeyDown = (event: React.KeyboardEvent) => { - if (!keyword || visibleConnectionIds.length === 0) return; if (event.nativeEvent.isComposing || event.key === "Process") return; + if (event.key === "Escape") { + event.preventDefault(); + event.stopPropagation(); + if (filterText) { + setFilterText(""); + } else { + setIsSearchExpanded(false); + } + return; + } + + if (!keyword || visibleConnectionIds.length === 0) return; + if (event.key === "ArrowDown" || event.key === "ArrowUp") { event.preventDefault(); event.stopPropagation(); @@ -1388,7 +1415,7 @@ export default function SavedConnections({ />
setFilterText(e.target.value)} - onKeyDown={handleSearchKeyDown} + readOnly + onFocus={() => setIsSearchExpanded(true)} + onClick={() => setIsSearchExpanded(true)} placeholder={t("savedConnections.filter")} - autoCapitalize="none" - autoCorrect="off" - spellCheck={false} - autoComplete="off" - className="w-full pl-8 pr-7 py-1 h-7 text-xs rounded-md bg-[var(--df-bg-hover)] border border-transparent outline-none transition-all placeholder:text-[var(--df-text-dimmed)] focus:bg-transparent focus:border-[var(--df-primary)] focus:ring-1 focus:ring-[var(--df-primary)] text-[var(--df-text)]" + aria-label={t("savedConnections.search")} + className="w-full pl-8 pr-3 py-1 h-7 text-xs rounded-md bg-[var(--df-bg-hover)] border border-transparent outline-none transition-all cursor-text placeholder:text-[var(--df-text-dimmed)] focus:bg-transparent focus:border-[var(--df-primary)] focus:ring-1 focus:ring-[var(--df-primary)] text-[var(--df-text)]" /> - {filterText && ( - - )}
-
+
+ + {isSearchExpanded && ( +
+ + setFilterText(event.target.value)} + onKeyDown={handleSearchKeyDown} + placeholder={t("savedConnections.filter")} + autoCapitalize="none" + autoCorrect="off" + spellCheck={false} + autoComplete="off" + className="h-full min-w-0 flex-1 bg-transparent px-1 text-xs text-[var(--df-text)] outline-none placeholder:text-[var(--df-text-dimmed)]" + /> + +
+ )}
{/* List */}