onSelect(project)}>
+ {/* Project content */}
+
(null);
+ const scrollContainerRef = useRef(null);
// Filtered projects based on search query
const filteredProjects = useMemo(() => {
@@ -29,38 +30,67 @@ export function useProjectPicker({
return projects.filter((project) => project.name.toLowerCase().includes(query));
}, [projects, projectSearchQuery]);
- // Reset selection when filtered results change and project picker is open
- useEffect(() => {
- if (!isProjectPickerOpen) {
- return;
+ // Helper function to scroll to a specific project
+ const scrollToProject = useCallback((projectId: string) => {
+ if (!scrollContainerRef.current) return;
+
+ const element = scrollContainerRef.current.querySelector(
+ `[data-testid="project-option-${projectId}"]`
+ ) as HTMLElement;
+
+ if (element) {
+ element.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ });
}
+ }, []);
- if (!projectSearchQuery.trim()) {
- const currentIndex = currentProject
- ? filteredProjects.findIndex((p) => p.id === currentProject.id)
- : -1;
- if (currentIndex !== -1) {
- setSelectedProjectIndex(currentIndex);
- return;
- }
- }
-
- setSelectedProjectIndex(0);
- }, [isProjectPickerOpen, filteredProjects.length, projectSearchQuery, currentProject]);
-
- // Reset search query when dropdown closes, set to current project index when it opens
+ // Initialize state when dropdown opens, reset when it closes
useEffect(() => {
if (!isProjectPickerOpen) {
setProjectSearchQuery('');
setSelectedProjectIndex(0);
- } else {
- // Focus the search input when dropdown opens
- // Small delay to ensure the dropdown is rendered
- setTimeout(() => {
- projectSearchInputRef.current?.focus();
- }, 0);
+ return;
}
- }, [isProjectPickerOpen]);
+
+ // When opening, find and select the current project
+ const currentIndex = currentProject
+ ? filteredProjects.findIndex((p) => p.id === currentProject.id)
+ : -1;
+
+ const initialIndex = currentIndex !== -1 ? currentIndex : 0;
+ setSelectedProjectIndex(initialIndex);
+
+ // Focus search input and scroll to current project after DOM renders
+ requestAnimationFrame(() => {
+ projectSearchInputRef.current?.focus();
+
+ // Scroll to the current project
+ const targetProject = filteredProjects[initialIndex];
+ if (targetProject) {
+ scrollToProject(targetProject.id);
+ }
+ });
+ }, [isProjectPickerOpen, currentProject?.id]);
+
+ // Update selection when search query changes (while picker is open)
+ useEffect(() => {
+ if (!isProjectPickerOpen || !projectSearchQuery.trim()) return;
+
+ // When searching, reset to first result
+ setSelectedProjectIndex(0);
+ }, [isProjectPickerOpen, projectSearchQuery]);
+
+ // Scroll to highlighted item when selection changes via keyboard
+ useEffect(() => {
+ if (!isProjectPickerOpen) return;
+
+ const targetProject = filteredProjects[selectedProjectIndex];
+ if (targetProject) {
+ scrollToProject(targetProject.id);
+ }
+ }, [selectedProjectIndex, isProjectPickerOpen, filteredProjects, scrollToProject]);
// Handle selecting the currently highlighted project
const selectHighlightedProject = useCallback(() => {
@@ -111,6 +141,7 @@ export function useProjectPicker({
selectedProjectIndex,
setSelectedProjectIndex,
projectSearchInputRef,
+ scrollContainerRef,
filteredProjects,
selectHighlightedProject,
};
diff --git a/apps/ui/src/styles/global.css b/apps/ui/src/styles/global.css
index cd7f8145..802b1da0 100644
--- a/apps/ui/src/styles/global.css
+++ b/apps/ui/src/styles/global.css
@@ -870,6 +870,32 @@
animation: accordion-up 0.2s ease-out forwards;
}
+/* Project picker scrollbar styling */
+.project-picker-scroll {
+ scrollbar-width: thin;
+ scrollbar-color: var(--muted-foreground) transparent;
+}
+
+.project-picker-scroll::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+.project-picker-scroll::-webkit-scrollbar-track {
+ background: transparent;
+ border-radius: 3px;
+}
+
+.project-picker-scroll::-webkit-scrollbar-thumb {
+ background: var(--muted-foreground);
+ border-radius: 3px;
+ min-height: 30px;
+}
+
+.project-picker-scroll::-webkit-scrollbar-thumb:hover {
+ background: var(--foreground-secondary);
+}
+
/* Terminal scrollbar theming */
.xterm-viewport::-webkit-scrollbar {
width: 8px;