diff --git a/apps/desktop/src/app/chat/sidebar/session-actions-menu.test.tsx b/apps/desktop/src/app/chat/sidebar/session-actions-menu.test.tsx index 559d648407..b43a860f2a 100644 --- a/apps/desktop/src/app/chat/sidebar/session-actions-menu.test.tsx +++ b/apps/desktop/src/app/chat/sidebar/session-actions-menu.test.tsx @@ -1,4 +1,4 @@ -import { cleanup, fireEvent, render, screen } from '@testing-library/react' +import { cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react' import { atom } from 'nanostores' import { afterEach, describe, expect, it, vi } from 'vitest' @@ -113,4 +113,28 @@ describe('SessionActionsMenu', () => { expect(screen.getByRole('menuitem', { name: /rename/i })).toBeTruthy() expect(screen.getByRole('menuitem', { name: /archive/i })).toBeTruthy() }) + + it('opens the rename dialog focused on its input, not the row trigger', async () => { + renderMenu() + + const trigger = screen.getByRole('button', { name: 'Session actions' }) + + fireEvent.pointerDown(trigger, { button: 0, pointerType: 'mouse' }) + fireEvent.pointerUp(trigger, { button: 0, pointerType: 'mouse' }) + fireEvent.click(trigger) + + const rename = await screen.findByRole('menuitem', { name: /rename/i }) + fireEvent.click(rename) + + // The dialog opens and its textbox takes focus. If the menu's close restored + // focus to the row trigger instead, Space would activate the row and the + // arrow keys would move the list rather than the caret (the reported bug). + const dialog = await screen.findByRole('dialog') + const input = within(dialog).getByRole('textbox') + + // eslint-disable-next-line no-restricted-globals -- asserting real focus requires the live document + await waitFor(() => expect(document.activeElement).toBe(input)) + // eslint-disable-next-line no-restricted-globals -- asserting real focus requires the live document + expect(document.activeElement).not.toBe(trigger) + }) }) diff --git a/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx b/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx index 0a32e1881f..2787b329f4 100644 --- a/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx +++ b/apps/desktop/src/app/chat/sidebar/session-actions-menu.tsx @@ -189,6 +189,14 @@ function useSessionActions({ const { t } = useI18n() const r = t.sidebar.row const [renameOpen, setRenameOpen] = useState(false) + // The rename item opens a Dialog. When a menu closes, Radix restores focus to + // its trigger — for a sidebar row that trigger is the row's own