mirror of
https://github.com/jlengrand/Maestro.git
synced 2026-03-10 08:31:19 +00:00
fix(tabs): scroll file preview tabs into view when selected
The TabBar scroll-into-view effect only triggered for AI tabs. Added activeFileTabId to the useEffect dependencies so file preview tabs are also scrolled into view when opened.
This commit is contained in:
@@ -1527,6 +1527,70 @@ describe('TabBar', () => {
|
||||
|
||||
rafSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('scrolls to center file tab when activeFileTabId changes', async () => {
|
||||
// Mock requestAnimationFrame
|
||||
const rafSpy = vi.spyOn(window, 'requestAnimationFrame').mockImplementation((cb) => {
|
||||
cb(0);
|
||||
return 0;
|
||||
});
|
||||
const scrollToSpy = vi.fn();
|
||||
|
||||
const tabs = [createTab({ id: 'tab-1', name: 'Tab 1' })];
|
||||
const fileTab: FilePreviewTab = {
|
||||
id: 'file-1',
|
||||
path: '/path/to/file.ts',
|
||||
name: 'file',
|
||||
extension: '.ts',
|
||||
};
|
||||
const unifiedTabs = [
|
||||
{ id: 'tab-1', type: 'ai' as const, data: tabs[0] },
|
||||
{ id: 'file-1', type: 'file' as const, data: fileTab },
|
||||
];
|
||||
|
||||
const { rerender, container } = render(
|
||||
<TabBar
|
||||
tabs={tabs}
|
||||
activeTabId="tab-1"
|
||||
theme={mockTheme}
|
||||
onTabSelect={mockOnTabSelect}
|
||||
onTabClose={mockOnTabClose}
|
||||
onNewTab={mockOnNewTab}
|
||||
unifiedTabs={unifiedTabs}
|
||||
activeFileTabId={null}
|
||||
onFileTabSelect={vi.fn()}
|
||||
onFileTabClose={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
// Mock scrollTo on the container
|
||||
const tabBarContainer = container.firstChild as HTMLElement;
|
||||
tabBarContainer.scrollTo = scrollToSpy;
|
||||
|
||||
// Clear initial calls
|
||||
scrollToSpy.mockClear();
|
||||
|
||||
// Select the file tab - this should trigger scroll to file tab
|
||||
rerender(
|
||||
<TabBar
|
||||
tabs={tabs}
|
||||
activeTabId="tab-1"
|
||||
theme={mockTheme}
|
||||
onTabSelect={mockOnTabSelect}
|
||||
onTabClose={mockOnTabClose}
|
||||
onNewTab={mockOnNewTab}
|
||||
unifiedTabs={unifiedTabs}
|
||||
activeFileTabId="file-1"
|
||||
onFileTabSelect={vi.fn()}
|
||||
onFileTabClose={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
// scrollTo should have been called when file tab was selected
|
||||
expect(scrollToSpy).toHaveBeenCalled();
|
||||
|
||||
rafSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe('styling', () => {
|
||||
|
||||
@@ -1598,12 +1598,14 @@ function TabBarInner({
|
||||
const tabRefs = useRef<Map<string, HTMLDivElement>>(new Map());
|
||||
const [isOverflowing, setIsOverflowing] = useState(false);
|
||||
|
||||
// Center the active tab in the scrollable area when activeTabId changes or filter is toggled
|
||||
// Center the active tab in the scrollable area when activeTabId or activeFileTabId changes, or filter is toggled
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const container = tabBarRef.current;
|
||||
// When a file tab is active, scroll to it; otherwise scroll to the active AI tab
|
||||
const targetTabId = activeFileTabId || activeTabId;
|
||||
const tabElement = container?.querySelector(
|
||||
`[data-tab-id="${activeTabId}"]`
|
||||
`[data-tab-id="${targetTabId}"]`
|
||||
) as HTMLElement | null;
|
||||
if (container && tabElement) {
|
||||
// Calculate scroll position to center the tab
|
||||
@@ -1612,7 +1614,7 @@ function TabBarInner({
|
||||
container.scrollTo({ left: scrollLeft, behavior: 'smooth' });
|
||||
}
|
||||
});
|
||||
}, [activeTabId, showUnreadOnly]);
|
||||
}, [activeTabId, activeFileTabId, showUnreadOnly]);
|
||||
|
||||
// Can always close tabs - closing the last one creates a fresh new tab
|
||||
const canClose = true;
|
||||
|
||||
Reference in New Issue
Block a user