refactor(ProjectSelector): enhance project picker scrollbar styling and improve selection logic

This commit is contained in:
Illia Filippov
2025-12-23 18:17:12 +01:00
parent 190f18ecae
commit 4898a1307e
3 changed files with 32 additions and 59 deletions

View File

@@ -174,7 +174,7 @@ export function ProjectSelectorWithOptions({
> >
<div <div
ref={scrollContainerRef} ref={scrollContainerRef}
className="space-y-0.5 max-h-64 overflow-y-auto overflow-x-hidden scroll-smooth project-picker-scroll" className="space-y-0.5 max-h-64 overflow-y-auto overflow-x-hidden scroll-smooth scrollbar-styled"
> >
{filteredProjects.map((project, index) => ( {filteredProjects.map((project, index) => (
<SortableProjectItem <SortableProjectItem

View File

@@ -36,7 +36,7 @@ export function useProjectPicker({
const element = scrollContainerRef.current.querySelector( const element = scrollContainerRef.current.querySelector(
`[data-testid="project-option-${projectId}"]` `[data-testid="project-option-${projectId}"]`
) as HTMLElement; );
if (element) { if (element) {
element.scrollIntoView({ element.scrollIntoView({
@@ -46,49 +46,48 @@ export function useProjectPicker({
} }
}, []); }, []);
// Initialize state when dropdown opens, reset when it closes // On open/close, handle search query reset and focus
useEffect(() => {
if (isProjectPickerOpen) {
// Focus search input after DOM renders
requestAnimationFrame(() => {
projectSearchInputRef.current?.focus();
});
} else {
// Reset search when closing
setProjectSearchQuery('');
}
}, [isProjectPickerOpen]);
// Update selection when search query changes (while picker is open)
useEffect(() => { useEffect(() => {
if (!isProjectPickerOpen) { if (!isProjectPickerOpen) {
setProjectSearchQuery('');
setSelectedProjectIndex(0); setSelectedProjectIndex(0);
return; return;
} }
// When opening, find and select the current project if (projectSearchQuery.trim()) {
const currentIndex = currentProject // When searching, reset to first result
? filteredProjects.findIndex((p) => p.id === currentProject.id) setSelectedProjectIndex(0);
: -1; } else {
// When not searching (e.g., on open or search cleared), find and select the current project
const currentIndex = currentProject
? filteredProjects.findIndex((p) => p.id === currentProject.id)
: -1;
setSelectedProjectIndex(currentIndex !== -1 ? currentIndex : 0);
}
}, [isProjectPickerOpen, projectSearchQuery, filteredProjects, currentProject]);
const initialIndex = currentIndex !== -1 ? currentIndex : 0; // Scroll to highlighted item when selection changes
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(() => { useEffect(() => {
if (!isProjectPickerOpen) return; if (!isProjectPickerOpen) return;
const targetProject = filteredProjects[selectedProjectIndex]; const targetProject = filteredProjects[selectedProjectIndex];
if (targetProject) { if (targetProject) {
scrollToProject(targetProject.id); // Use requestAnimationFrame to ensure DOM is rendered before scrolling
requestAnimationFrame(() => {
scrollToProject(targetProject.id);
});
} }
}, [selectedProjectIndex, isProjectPickerOpen, filteredProjects, scrollToProject]); }, [selectedProjectIndex, isProjectPickerOpen, filteredProjects, scrollToProject]);

View File

@@ -870,32 +870,6 @@
animation: accordion-up 0.2s ease-out forwards; 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 */ /* Terminal scrollbar theming */
.xterm-viewport::-webkit-scrollbar { .xterm-viewport::-webkit-scrollbar {
width: 8px; width: 8px;