diff --git a/src/renderer/src/components/tab-bar/EditorFileTab.test.tsx b/src/renderer/src/components/tab-bar/EditorFileTab.test.tsx index 6eb614550c9..284d816023d 100644 --- a/src/renderer/src/components/tab-bar/EditorFileTab.test.tsx +++ b/src/renderer/src/components/tab-bar/EditorFileTab.test.tsx @@ -402,6 +402,10 @@ describe('EditorFileTab rename menu', () => { // "untitled-N.md" files directly. expect(renameItem.props.disabled).toBe(false) ;(renameItem.props.onSelect as () => void)() + const content = findElementsByType(firstRender, 'DropdownMenuContent')[0]! + ;(content.props.onCloseAutoFocus as (event: { preventDefault: () => void }) => void)({ + preventDefault: vi.fn() + }) const secondRender = expandNode((await renderEditorFileTab(file, onActivate)).element) const inputs = findElementsByType(secondRender, 'input') @@ -428,6 +432,10 @@ describe('EditorFileTab rename menu', () => { const renameItem = findMenuItemByText(firstRender, 'Rename') ;(renameItem.props.onSelect as () => void)() + const content = findElementsByType(firstRender, 'DropdownMenuContent')[0]! + ;(content.props.onCloseAutoFocus as (event: { preventDefault: () => void }) => void)({ + preventDefault: vi.fn() + }) const secondRender = expandNode((await renderEditorFileTab(file)).element) const input = findElementsByType(secondRender, 'input')[0] @@ -460,6 +468,10 @@ describe('EditorFileTab rename menu', () => { const renameItem = findMenuItemByText(firstRender, 'Rename') ;(renameItem.props.onSelect as () => void)() + const content = findElementsByType(firstRender, 'DropdownMenuContent')[0]! + ;(content.props.onCloseAutoFocus as (event: { preventDefault: () => void }) => void)({ + preventDefault: vi.fn() + }) const secondRender = expandNode((await renderEditorFileTab(file)).element) const input = findElementsByType(secondRender, 'input')[0] diff --git a/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.test.tsx b/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.test.tsx index 00b2d2a210c..812079563af 100644 --- a/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.test.tsx +++ b/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.test.tsx @@ -202,7 +202,9 @@ function extractText(node: unknown): string { return el.props && 'children' in el.props ? extractText(el.props.children) : '' } -async function renderMenu(): Promise { +async function renderMenu( + overrides: { onActivate?: () => void; onOpenRenameInput?: () => void } = {} +): Promise { const module = await import('./EditorFileTabContextMenu') return module.EditorFileTabContextMenu({ open: true, @@ -238,7 +240,8 @@ async function renderMenu(): Promise { onCloseAll: vi.fn(), onCloseToRight: vi.fn(), onCloseToLeft: vi.fn(), - onOpenMarkdownPreview: vi.fn() + onOpenMarkdownPreview: vi.fn(), + ...overrides }) } @@ -266,6 +269,27 @@ describe('EditorFileTabContextMenu close-all shortcut', () => { vi.unstubAllGlobals() }) + it('opens rename only after menu close releases focus and consumes the request once', async () => { + const onActivate = vi.fn() + const onOpenRenameInput = vi.fn() + const tree = expandNode(await renderMenu({ onActivate, onOpenRenameInput })) + const rename = findElementsByType(tree, 'DropdownMenuItem').find((item) => + extractText(item.props.children).includes('Rename') + )! + const content = findElementsByType(tree, 'DropdownMenuContent')[0]! + ;(rename.props.onSelect as () => void)() + expect(onActivate).not.toHaveBeenCalled() + expect(onOpenRenameInput).not.toHaveBeenCalled() + const preventDefault = vi.fn() + const close = content.props.onCloseAutoFocus as (event: { preventDefault: () => void }) => void + close({ preventDefault }) + expect(preventDefault).toHaveBeenCalledTimes(1) + expect(onActivate).toHaveBeenCalledTimes(1) + expect(onOpenRenameInput).toHaveBeenCalledTimes(1) + close({ preventDefault }) + expect(onOpenRenameInput).toHaveBeenCalledTimes(1) + }) + it('renders assigned shortcuts next to Rename, Close, and Close All Editor Tabs', async () => { const tree = expandNode(await renderMenu()) const menuItems = findElementsByType(tree, 'DropdownMenuItem') diff --git a/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.tsx b/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.tsx index 32e29595738..9753565c00e 100644 --- a/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.tsx +++ b/src/renderer/src/components/tab-bar/EditorFileTabContextMenu.tsx @@ -126,6 +126,9 @@ export function EditorFileTabContextMenu({ } skipMenuFocusRestoreRef.current = false event.preventDefault() + // The closing menu can still reclaim focus before its teardown completes. + onActivate() + onOpenRenameInput() }} > { skipMenuFocusRestoreRef.current = true - onActivate() - onOpenRenameInput() }} >