Fix keyboard navigation in host pickers

This commit is contained in:
mam15mon committed 2026-07-21 09:24:33 +08:00
1 parent ef44faa7df
commit 7b9c634475
2 files changed
+20 -2

No files matched your search

+18
View File
@@ -97,15 +97,18 @@ const IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(naviga
const HostItem = memo(({
host,
isSelected,
selectedItemRef,
onSelect,
onMouseEnter,
}: {
host: Host;
isSelected: boolean;
selectedItemRef?: React.Ref<HTMLDivElement>;
onSelect: (host: Host) => void;
onMouseEnter: () => void;
}) => (
<div
ref={selectedItemRef}
className={`flex items-center justify-between px-4 py-2.5 cursor-pointer transition-colors ${isSelected ? "bg-primary/15" : "hover:bg-muted/50"
}`}
onClick={() => onSelect(host)}
@@ -192,6 +195,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
const [selectedIndex, setSelectedIndex] = useState(0);
const inputRef = useRef<HTMLInputElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const selectedItemRef = useRef<HTMLDivElement>(null);
// Reset state when opening
useEffect(() => {
@@ -322,6 +326,14 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
return itemIndexMap.get(`${type}:${id}`) ?? -1;
}, [itemIndexMap]);
const selectedItem = flatItems[selectedIndex];
const selectedItemKey = selectedItem ? `${selectedItem.type}:${selectedItem.id}` : '';
useEffect(() => {
if (!isOpen || !selectedItemKey) return;
selectedItemRef.current?.scrollIntoView({ block: "nearest" });
}, [isOpen, selectedIndex, selectedItemKey]);
if (!isOpen) return null;
const handleKeyDown = (e: React.KeyboardEvent) => {
@@ -449,6 +461,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
key={host.id}
host={host}
isSelected={getItemIndex("host", host.id) === selectedIndex}
selectedItemRef={getItemIndex("host", host.id) === selectedIndex ? selectedItemRef : undefined}
onSelect={onSelect}
onMouseEnter={() => setSelectedIndex(getItemIndex("host", host.id))}
/>
@@ -479,6 +492,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
return (
<div
key={tabId}
ref={isSelected ? selectedItemRef : undefined}
className={`flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors ${isSelected ? "bg-primary/15" : "hover:bg-muted/50"
}`}
onClick={() => {
@@ -503,6 +517,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
return (
<div
key={workspace.id}
ref={isSelected ? selectedItemRef : undefined}
className={`flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors ${isSelected ? "bg-primary/15" : "hover:bg-muted/50"
}`}
onClick={() => {
@@ -529,6 +544,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
return (
<div
key={session.id}
ref={isSelected ? selectedItemRef : undefined}
className={`flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors ${isSelected ? "bg-primary/15" : "hover:bg-muted/50"
}`}
onClick={() => {
@@ -563,6 +579,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
return (
<div
key={shell.id}
ref={isSelected ? selectedItemRef : undefined}
className={`flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors ${
isSelected ? "bg-primary/15" : "hover:bg-muted/50"
}`}
@@ -597,6 +614,7 @@ const QuickSwitcherInner: React.FC<QuickSwitcherProps> = ({
</span>
</div>
<div
ref={getItemIndex("action", "local-terminal") === selectedIndex ? selectedItemRef : undefined}
className={`flex items-center gap-3 px-4 py-2.5 cursor-pointer transition-colors ${
getItemIndex("action", "local-terminal") === selectedIndex
? "bg-primary/15"
@@ -128,7 +128,7 @@ export const AddToWorkspaceDialog: React.FC<AddToWorkspaceDialogProps> = ({
} else if (e.key === 'ArrowUp') {
e.preventDefault();
setSelectedIndex((i) => Math.max(i - 1, 0));
} else if (e.key === ' ' || (e.key === 'Enter' && !(e.metaKey || e.ctrlKey))) {
} else if (e.key === 'Enter' && !(e.metaKey || e.ctrlKey)) {
if (items.length === 0) return;
e.preventDefault();
toggle(items[selectedIndex].id);
@@ -180,7 +180,7 @@ export const AddToWorkspaceDialog: React.FC<AddToWorkspaceDialogProps> = ({
{/* Jump-to hint */}
<div className="px-4 py-2 flex items-center gap-2">
<span className="text-xs text-muted-foreground">Pick one or more</span>
<kbd className="text-[10px] text-muted-foreground bg-muted px-1 py-0.5 rounded">Space</kbd>
<kbd className="text-[10px] text-muted-foreground bg-muted px-1 py-0.5 rounded">Enter</kbd>
<span className="text-[10px] text-muted-foreground">toggle</span>
<kbd className="text-[10px] text-muted-foreground bg-muted px-1 py-0.5 rounded">
{typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform) ? '⌘' : 'Ctrl'}+Enter