Skip to content

Commit 94691e8

Browse files
committed
feat: show branch dropdown on focus with create option
- Show dropdown immediately when input is focused (not just when typing) - Add 'Create new branch' option at top when input doesn't match existing - Keep dropdown open while focused with existing branches visible - Remove 'Press Enter' hint since the create option makes it clear Change-Id: Id6c23e41008a9623762b0c6ec929038c775f140b Signed-off-by: Thomas Kosiewski <[email protected]>
1 parent 8136f64 commit 94691e8

File tree

1 file changed

+49
-24
lines changed

1 file changed

+49
-24
lines changed

src/browser/components/BranchNameInput.tsx

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
2-
import { Check, ChevronRight, Globe, Loader2, Wand2 } from "lucide-react";
1+
import React, { useCallback, useMemo, useRef, useState } from "react";
2+
import { Check, ChevronRight, Globe, Loader2, Plus, Wand2 } from "lucide-react";
33
import { cn } from "@/common/lib/utils";
44
import { Popover, PopoverContent, PopoverAnchor } from "./ui/popover";
55
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
@@ -103,27 +103,29 @@ export function BranchNameInput(props: BranchNameInputProps) {
103103
filteredLocalBranches.length > 0 ||
104104
remoteGroups.some((g) => getFilteredRemoteBranches(g.remote).length > 0);
105105

106+
const hasAnyBranches =
107+
localBranches.length > 0 || remoteGroups.some((g) => g.branches.length > 0);
108+
106109
// Check if input exactly matches an existing branch
107110
const exactLocalMatch = localBranches.find((b) => b.toLowerCase() === searchLower);
108111
const exactRemoteMatch = remoteGroups.find((g) =>
109112
g.branches.some((b) => b.toLowerCase() === searchLower)
110113
);
114+
const hasExactMatch = exactLocalMatch ?? exactRemoteMatch;
111115

112-
// Open popover when there's input and matching branches
113-
useEffect(() => {
114-
if (value.length > 0 && hasMatchingBranches && !disabled) {
115-
setIsOpen(true);
116-
} else if (value.length === 0 || !hasMatchingBranches) {
117-
setIsOpen(false);
118-
}
119-
}, [value, hasMatchingBranches, disabled]);
116+
// Show "Create new branch" option when there's input that doesn't exactly match
117+
const showCreateOption = value.length > 0 && !hasExactMatch;
120118

121-
// Handle input focus - disable auto-generate so user can edit
119+
// Handle input focus - show dropdown and disable auto-generate
122120
const handleFocus = useCallback(() => {
123121
if (autoGenerate) {
124122
onAutoGenerateChange(false);
125123
}
126-
}, [autoGenerate, onAutoGenerateChange]);
124+
// Show dropdown if branches are available (even when input is empty)
125+
if (branchesLoaded && hasAnyBranches && !disabled) {
126+
setIsOpen(true);
127+
}
128+
}, [autoGenerate, onAutoGenerateChange, branchesLoaded, hasAnyBranches, disabled]);
127129

128130
// Handle input change
129131
const handleChange = useCallback(
@@ -160,17 +162,21 @@ export function BranchNameInput(props: BranchNameInputProps) {
160162
[onChange, onSelectExistingBranch]
161163
);
162164

163-
// Handle input blur - check if we should auto-select an exact match
165+
// Handle selecting "Create new branch" option
166+
const handleSelectCreateNew = useCallback(() => {
167+
// Keep the current value, clear any existing branch selection
168+
onSelectExistingBranch(null);
169+
setIsOpen(false);
170+
inputRef.current?.blur();
171+
}, [onSelectExistingBranch]);
172+
173+
// Handle input blur - close dropdown
164174
const handleBlur = useCallback(() => {
165175
// Small delay to allow click events on dropdown items to fire first
166176
setTimeout(() => {
167-
// If input exactly matches a local branch, auto-select it
168-
if (exactLocalMatch && !selectedExistingBranch) {
169-
onSelectExistingBranch({ kind: "local", branch: exactLocalMatch });
170-
}
171177
setIsOpen(false);
172178
}, 150);
173-
}, [exactLocalMatch, selectedExistingBranch, onSelectExistingBranch]);
179+
}, []);
174180

175181
// Handle keyboard navigation
176182
const handleKeyDown = useCallback(
@@ -187,18 +193,20 @@ export function BranchNameInput(props: BranchNameInputProps) {
187193
if (branch) {
188194
handleSelectRemoteBranch(exactRemoteMatch.remote, branch);
189195
}
190-
} else {
191-
// No match - close popover and use as new branch name
192-
setIsOpen(false);
196+
} else if (value.length > 0) {
197+
// No match - use as new branch name
198+
handleSelectCreateNew();
193199
}
194200
}
195201
},
196202
[
197203
exactLocalMatch,
198204
exactRemoteMatch,
199205
searchLower,
206+
value.length,
200207
handleSelectLocalBranch,
201208
handleSelectRemoteBranch,
209+
handleSelectCreateNew,
202210
]
203211
);
204212

@@ -315,6 +323,23 @@ export function BranchNameInput(props: BranchNameInputProps) {
315323
</div>
316324
)}
317325

326+
{/* Create new branch option - shown when input doesn't match existing */}
327+
{branchesLoaded && showCreateOption && (
328+
<>
329+
<button
330+
type="button"
331+
onClick={handleSelectCreateNew}
332+
className="text-accent hover:bg-hover flex w-full items-center gap-1.5 rounded-sm px-2 py-1.5 font-mono text-[11px]"
333+
>
334+
<Plus className="h-3 w-3 shrink-0" />
335+
<span className="truncate">
336+
Create new branch <span className="font-semibold">{value}</span>
337+
</span>
338+
</button>
339+
{hasMatchingBranches && <div className="bg-border my-1 h-px" />}
340+
</>
341+
)}
342+
318343
{/* Remote branches as expandable groups */}
319344
{branchesLoaded && remoteGroups.length > 0 && (
320345
<>
@@ -399,10 +424,10 @@ export function BranchNameInput(props: BranchNameInputProps) {
399424
</>
400425
)}
401426

402-
{/* No matches - show hint */}
403-
{branchesLoaded && !hasMatchingBranches && value.length > 0 && (
427+
{/* Empty state when no input yet */}
428+
{branchesLoaded && value.length === 0 && !hasMatchingBranches && (
404429
<div className="text-muted px-2 py-2 text-center text-[11px]">
405-
Press Enter to create new branch
430+
Type to search or create a branch
406431
</div>
407432
)}
408433
</div>

0 commit comments

Comments
 (0)