diff --git a/frontend/src/components/tasks/BranchSelector.tsx b/frontend/src/components/tasks/BranchSelector.tsx index 3c98fbdd..d764d140 100644 --- a/frontend/src/components/tasks/BranchSelector.tsx +++ b/frontend/src/components/tasks/BranchSelector.tsx @@ -1,4 +1,4 @@ -import { useState, useMemo, useRef } from 'react'; +import { useState, useMemo, useRef, useEffect } from 'react'; import { Button } from '@/components/ui/button.tsx'; import { ArrowDown, GitBranch as GitBranchIcon, Search } from 'lucide-react'; import { @@ -35,7 +35,10 @@ function BranchSelector({ excludeCurrentBranch = false, }: Props) { const [branchSearchTerm, setBranchSearchTerm] = useState(''); + const [highlighted, setHighlighted] = useState(null); + const [open, setOpen] = useState(false); const searchInputRef = useRef(null); + const itemRefs = useRef>([]); // Filter branches based on search term and options const filteredBranches = useMemo(() => { @@ -65,10 +68,44 @@ function BranchSelector({ const handleBranchSelect = (branchName: string) => { onBranchSelect(branchName); setBranchSearchTerm(''); + setHighlighted(null); + setOpen(false); }; + const moveHighlight = (delta: 1 | -1) => { + if (filteredBranches.length === 0) return; + + setHighlighted((prev) => { + const next = + prev === null + ? delta === 1 + ? 0 + : filteredBranches.length - 1 + : (prev + delta + filteredBranches.length) % filteredBranches.length; + + // Focus the matching item for scroll behavior + setTimeout( + () => itemRefs.current[next]?.scrollIntoView({ block: 'nearest' }), + 0 + ); + return next; + }); + }; + + // Reset highlight when filtered branches change + useEffect(() => { + if (highlighted !== null && highlighted >= filteredBranches.length) { + setHighlighted(null); + } + }, [filteredBranches, highlighted]); + + // Reset highlight when search changes + useEffect(() => { + setHighlighted(null); + }, [branchSearchTerm]); + return ( - +