1- import React , { useCallback , useMemo , useRef , useState } from "react" ;
1+ import React , { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
22import { Check , ChevronRight , Globe , Loader2 , Plus , Wand2 } from "lucide-react" ;
33import { cn } from "@/common/lib/utils" ;
44import { Popover , PopoverContent , PopoverAnchor } from "./ui/popover" ;
55import { Tooltip , TooltipContent , TooltipTrigger } from "./ui/tooltip" ;
66import type { ExistingBranchSelection } from "@/common/types/branchSelection" ;
7+ import { inferExactExistingBranchSelection } from "./branchNameInputSelection" ;
78import type { BranchListResult } from "@/common/orpc/types" ;
89
910interface RemoteGroup {
@@ -70,6 +71,12 @@ export function BranchNameInput(props: BranchNameInputProps) {
7071 } = props ;
7172
7273 const inputRef = useRef < HTMLInputElement > ( null ) ;
74+ const selectedExistingBranchRef = useRef < ExistingBranchSelection | null > ( selectedExistingBranch ) ;
75+
76+ useEffect ( ( ) => {
77+ selectedExistingBranchRef . current = selectedExistingBranch ;
78+ } , [ selectedExistingBranch ] ) ;
79+
7380 const [ isOpen , setIsOpen ] = useState ( false ) ;
7481 const [ expandedRemotes , setExpandedRemotes ] = useState < Set < string > > ( new Set ( ) ) ;
7582
@@ -106,15 +113,17 @@ export function BranchNameInput(props: BranchNameInputProps) {
106113 const hasAnyBranches =
107114 localBranches . length > 0 || remoteGroups . some ( ( g ) => g . branches . length > 0 ) ;
108115
109- // Check if input exactly matches an existing branch
110- const exactLocalMatch = localBranches . find ( ( b ) => b . toLowerCase ( ) === searchLower ) ;
111- const exactRemoteMatch = remoteGroups . find ( ( g ) =>
112- g . branches . some ( ( b ) => b . toLowerCase ( ) === searchLower )
116+ const exactExistingBranchSelection = useMemo (
117+ ( ) =>
118+ inferExactExistingBranchSelection ( {
119+ value,
120+ localBranches,
121+ remoteGroups,
122+ } ) ,
123+ [ value , localBranches , remoteGroups ]
113124 ) ;
114- const hasExactMatch = exactLocalMatch ?? exactRemoteMatch ;
115125
116- // Show "Create new branch" option when there's input that doesn't exactly match
117- const showCreateOption = value . length > 0 && ! hasExactMatch ;
126+ const showCreateOption = value . length > 0 && exactExistingBranchSelection === null ;
118127
119128 // Handle input focus - show dropdown and disable auto-generate
120129 const handleFocus = useCallback ( ( ) => {
@@ -170,13 +179,33 @@ export function BranchNameInput(props: BranchNameInputProps) {
170179 inputRef . current ?. blur ( ) ;
171180 } , [ onSelectExistingBranch ] ) ;
172181
173- // Handle input blur - close dropdown
182+ // Handle input blur - close dropdown and opportunistically auto-select exact matches.
183+ //
184+ // Important: We only auto-select when the user *typed* an exact match but didn't click
185+ // a dropdown item. If a dropdown item click already selected a branch, don't override it.
174186 const handleBlur = useCallback ( ( ) => {
175187 // Small delay to allow click events on dropdown items to fire first
176188 setTimeout ( ( ) => {
177189 setIsOpen ( false ) ;
190+
191+ if ( disabled || ! branchesLoaded ) return ;
192+
193+ // If the user clicked a dropdown item, selection was already set.
194+ if ( selectedExistingBranchRef . current ) return ;
195+
196+ if ( value . length === 0 ) return ;
197+
198+ if ( exactExistingBranchSelection ) {
199+ onSelectExistingBranch ( exactExistingBranchSelection ) ;
200+ }
178201 } , 150 ) ;
179- } , [ ] ) ;
202+ } , [
203+ branchesLoaded ,
204+ disabled ,
205+ exactExistingBranchSelection ,
206+ onSelectExistingBranch ,
207+ value . length ,
208+ ] ) ;
180209
181210 // Handle keyboard navigation
182211 const handleKeyDown = useCallback (
@@ -186,23 +215,21 @@ export function BranchNameInput(props: BranchNameInputProps) {
186215 inputRef . current ?. blur ( ) ;
187216 } else if ( e . key === "Enter" ) {
188217 // If exact match exists, select it
189- if ( exactLocalMatch ) {
190- handleSelectLocalBranch ( exactLocalMatch ) ;
191- } else if ( exactRemoteMatch ) {
192- const branch = exactRemoteMatch . branches . find ( ( b ) => b . toLowerCase ( ) === searchLower ) ;
193- if ( branch ) {
194- handleSelectRemoteBranch ( exactRemoteMatch . remote , branch ) ;
195- }
218+ if ( exactExistingBranchSelection ?. kind === "local" ) {
219+ handleSelectLocalBranch ( exactExistingBranchSelection . branch ) ;
220+ } else if ( exactExistingBranchSelection ?. kind === "remote" ) {
221+ handleSelectRemoteBranch (
222+ exactExistingBranchSelection . remote ,
223+ exactExistingBranchSelection . branch
224+ ) ;
196225 } else if ( value . length > 0 ) {
197226 // No match - use as new branch name
198227 handleSelectCreateNew ( ) ;
199228 }
200229 }
201230 } ,
202231 [
203- exactLocalMatch ,
204- exactRemoteMatch ,
205- searchLower ,
232+ exactExistingBranchSelection ,
206233 value . length ,
207234 handleSelectLocalBranch ,
208235 handleSelectRemoteBranch ,
0 commit comments