authorgravatar for maria@kuuro.netmaria <maria@kuuro.net> 2026-09-20 20:32:35-03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-20 20:32:35-03:00
log67285e4b8719000eecb9de2a424609ca5c6f0274
tree90d7d1ccdae7b04b0fc3a54ad1f6ce8f12c3d068
parent584450a1f198c8592d28947a0a7a060d28013298
signature Signed by PGP key B5690EEEBB952194

fix(web): route keyboard submit through the primary worktree action (#12526)


2 files changed, 45 insertions(+), 13 deletions(-)

apps/web/src/components/BranchToolbarBranchSelector.tsx+41-12
...@@ -545,6 +545,7 @@ export function BranchToolbarBranchSelector({...@@ -545,6 +545,7 @@ export function BranchToolbarBranchSelector({
545 setIsBranchMenuOpen(open);545 setIsBranchMenuOpen(open);
546 if (!open) {546 if (!open) {
547 setBranchQuery("");547 setBranchQuery("");
548 highlightedBranchValueRef.current = null;
548 }549 }
549 }, []);550 }, []);
550551
...@@ -594,6 +595,9 @@ export function BranchToolbarBranchSelector({...@@ -594,6 +595,9 @@ export function BranchToolbarBranchSelector({
594 }, [fetchNextBranchPage, hasNextPage, isBranchMenuOpen, isFetchingNextPage]);595 }, [fetchNextBranchPage, hasNextPage, isBranchMenuOpen, isFetchingNextPage]);
595596
596 const branchListRef = useRef<LegendListRef | null>(null);597 const branchListRef = useRef<LegendListRef | null>(null);
598 // Tracks the highlighted picker value so Enter can activate it even when the
599 // virtualized row is not mounted (Base UI Enter clicks the mounted element).
600 const highlightedBranchValueRef = useRef<string | null>(null);
597 const updateBranchListScrollFades = useCallback(() => {601 const updateBranchListScrollFades = useCallback(() => {
598 const scrollElement = branchListRef.current?.getScrollableNode?.();602 const scrollElement = branchListRef.current?.getScrollableNode?.();
599 if (!(scrollElement instanceof HTMLElement)) {603 if (!(scrollElement instanceof HTMLElement)) {
...@@ -676,6 +680,20 @@ export function BranchToolbarBranchSelector({...@@ -676,6 +680,20 @@ export function BranchToolbarBranchSelector({
676 const prUrl = currentLinkedPr?.url ?? displayedPr?.url;680 const prUrl = currentLinkedPr?.url ?? displayedPr?.url;
677 const openPrLink = useOpenPrLink(threadRef);681 const openPrLink = useOpenPrLink(threadRef);
678682
683 function selectPickerItem(itemValue: string) {
684 highlightedBranchValueRef.current = null;
685 if (itemValue === checkoutPullRequestItemValue && prReference && onCheckoutPullRequestRequest) {
686 handleOpenChange(false);
687 onComposerFocusRequest?.();
688 onCheckoutPullRequestRequest(prReference);
689 } else if (itemValue === createBranchItemValue) {
690 createRef(trimmedBranchQuery);
691 } else {
692 const refName = branchByName.get(itemValue);
693 if (refName) selectBranch(refName);
694 }
695 }
696
679 function renderPickerItem(itemValue: string, index: number) {697 function renderPickerItem(itemValue: string, index: number) {
680 if (checkoutPullRequestItemValue && itemValue === checkoutPullRequestItemValue) {698 if (checkoutPullRequestItemValue && itemValue === checkoutPullRequestItemValue) {
681 return (699 return (
...@@ -685,15 +703,7 @@ export function BranchToolbarBranchSelector({...@@ -685,15 +703,7 @@ export function BranchToolbarBranchSelector({
685 index={index}703 index={index}
686 value={itemValue}704 value={itemValue}
687 className="pe-2"705 className="pe-2"
688 onClick={() => {706 onClick={() => selectPickerItem(itemValue)}
689 if (!prReference || !onCheckoutPullRequestRequest) {
690 return;
691 }
692 setIsBranchMenuOpen(false);
693 setBranchQuery("");
694 onComposerFocusRequest?.();
695 onCheckoutPullRequestRequest(prReference);
696 }}
697 >707 >
698 <div className="flex min-w-0 items-center gap-2 py-1">708 <div className="flex min-w-0 items-center gap-2 py-1">
699 <SourceControlIcon className="size-3.5 shrink-0 text-muted-foreground" />709 <SourceControlIcon className="size-3.5 shrink-0 text-muted-foreground" />
...@@ -715,7 +725,7 @@ export function BranchToolbarBranchSelector({...@@ -715,7 +725,7 @@ export function BranchToolbarBranchSelector({
715 index={index}725 index={index}
716 value={itemValue}726 value={itemValue}
717 className="pe-1.5"727 className="pe-1.5"
718 onClick={() => createRef(trimmedBranchQuery)}728 onClick={() => selectPickerItem(itemValue)}
719 >729 >
720 <span className="truncate">Create new ref &quot;{newRefName}&quot;</span>730 <span className="truncate">Create new ref &quot;{newRefName}&quot;</span>
721 </ComboboxItem>731 </ComboboxItem>
...@@ -743,7 +753,7 @@ export function BranchToolbarBranchSelector({...@@ -743,7 +753,7 @@ export function BranchToolbarBranchSelector({
743 index={index}753 index={index}
744 value={itemValue}754 value={itemValue}
745 className="pe-1.5"755 className="pe-1.5"
746 onClick={() => selectBranch(refName)}756 onClick={() => selectPickerItem(itemValue)}
747 onContextMenu={(event) => handleBranchContextMenu(event, itemValue)}757 onContextMenu={(event) => handleBranchContextMenu(event, itemValue)}
748 >758 >
749 <div className="flex w-full min-w-0 items-center justify-between gap-2">759 <div className="flex w-full min-w-0 items-center justify-between gap-2">
...@@ -760,7 +770,8 @@ export function BranchToolbarBranchSelector({...@@ -760,7 +770,8 @@ export function BranchToolbarBranchSelector({
760 filteredItems={filteredBranchPickerItems}770 filteredItems={filteredBranchPickerItems}
761 autoHighlight771 autoHighlight
762 virtualized772 virtualized
763 onItemHighlighted={(_value, eventDetails) => {773 onItemHighlighted={(value, eventDetails) => {
774 highlightedBranchValueRef.current = typeof value === "string" ? value : null;
764 if (!isBranchMenuOpen || eventDetails.index < 0 || eventDetails.reason !== "keyboard") {775 if (!isBranchMenuOpen || eventDetails.index < 0 || eventDetails.reason !== "keyboard") {
765 return;776 return;
766 }777 }
...@@ -828,6 +839,24 @@ export function BranchToolbarBranchSelector({...@@ -828,6 +839,24 @@ export function BranchToolbarBranchSelector({
828 placeholder="Search refs..."839 placeholder="Search refs..."
829 value={branchQuery}840 value={branchQuery}
830 onChange={(event) => setBranchQuery(event.target.value)}841 onChange={(event) => setBranchQuery(event.target.value)}
842 onKeyDown={(event) => {
843 if (event.key !== "Enter" || event.nativeEvent.isComposing || event.keyCode === 229) {
844 return;
845 }
846 const highlightedValue = highlightedBranchValueRef.current;
847 if (
848 highlightedValue === null ||
849 !filteredBranchPickerItems.includes(highlightedValue)
850 ) {
851 return;
852 }
853 (
854 event as typeof event & { preventBaseUIHandler?: () => void }
855 ).preventBaseUIHandler?.();
856 event.preventDefault();
857 event.stopPropagation();
858 selectPickerItem(highlightedValue);
859 }}
831 />860 />
832 <div className="flex min-h-0 flex-1 flex-col overflow-hidden">861 <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
833 <ComboboxEmpty>No refs found.</ComboboxEmpty>862 <ComboboxEmpty>No refs found.</ComboboxEmpty>
apps/web/src/components/PullRequestThreadDialog.tsx+4-1
...@@ -222,9 +222,12 @@ export function PullRequestThreadDialog({...@@ -222,9 +222,12 @@ export function PullRequestThreadDialog({
222 if (event.key !== "Enter") {222 if (event.key !== "Enter") {
223 return;223 return;
224 }224 }
225 if (event.nativeEvent.isComposing || event.keyCode === 229) {
226 return;
227 }
225 event.preventDefault();228 event.preventDefault();
226 if (!isResolving && !preparePullRequestThreadAction.isPending) {229 if (!isResolving && !preparePullRequestThreadAction.isPending) {
227 void handleConfirm("local");230 void handleConfirm("worktree");
228 }231 }
229 }}232 }}
230 />233 />