fix(ui): ignore prompt rail in escape abort guard
This commit is contained in:
@@ -0,0 +1,30 @@
|
|||||||
|
import { expect, test } from 'bun:test';
|
||||||
|
|
||||||
|
import { hasOpenDropdown } from './keyboard-shortcut-dom';
|
||||||
|
|
||||||
|
test('does not treat an unrelated visible listbox as an open dropdown', () => {
|
||||||
|
const promptNavigator = {} as Element;
|
||||||
|
const root = {
|
||||||
|
querySelector: (selector: string) => selector.includes('[role="listbox"]') ? promptNavigator : null,
|
||||||
|
} as unknown as ParentNode;
|
||||||
|
|
||||||
|
expect(hasOpenDropdown(root)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('detects an open dropdown popup', () => {
|
||||||
|
const dropdown = {} as Element;
|
||||||
|
const root = {
|
||||||
|
querySelector: (selector: string) => selector.includes('[data-slot="dropdown-menu-content"][data-open]') ? dropdown : null,
|
||||||
|
} as unknown as ParentNode;
|
||||||
|
|
||||||
|
expect(hasOpenDropdown(root)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('detects an open select popup', () => {
|
||||||
|
const select = {} as Element;
|
||||||
|
const root = {
|
||||||
|
querySelector: (selector: string) => selector.includes('[data-slot="select-content"][data-open]') ? select : null,
|
||||||
|
} as unknown as ParentNode;
|
||||||
|
|
||||||
|
expect(hasOpenDropdown(root)).toBe(true);
|
||||||
|
});
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const OPEN_DROPDOWN_SELECTOR = [
|
||||||
|
'[data-slot="dropdown-menu-content"][data-open]',
|
||||||
|
'[data-slot="select-content"][data-open]',
|
||||||
|
].join(',');
|
||||||
|
|
||||||
|
export function hasOpenDropdown(root: ParentNode = document): boolean {
|
||||||
|
return Boolean(root.querySelector(OPEN_DROPDOWN_SELECTOR));
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import { useDirectoryStore } from '@/stores/useDirectoryStore';
|
|||||||
import { useProjectsStore } from '@/stores/useProjectsStore';
|
import { useProjectsStore } from '@/stores/useProjectsStore';
|
||||||
import { getCycledPrimaryAgentName } from '@/components/chat/mobileControlsUtils';
|
import { getCycledPrimaryAgentName } from '@/components/chat/mobileControlsUtils';
|
||||||
import { focusChatInput } from '@/components/chat/composer/editor/dom';
|
import { focusChatInput } from '@/components/chat/composer/editor/dom';
|
||||||
|
import { hasOpenDropdown } from './keyboard-shortcut-dom';
|
||||||
|
|
||||||
export const useKeyboardShortcuts = () => {
|
export const useKeyboardShortcuts = () => {
|
||||||
const openNewSessionDraft = useSessionUIStore((s) => s.openNewSessionDraft);
|
const openNewSessionDraft = useSessionUIStore((s) => s.openNewSessionDraft);
|
||||||
@@ -93,13 +94,6 @@ export const useKeyboardShortcuts = () => {
|
|||||||
return target instanceof Element && Boolean(target.closest(dropdownTargetSelector));
|
return target instanceof Element && Boolean(target.closest(dropdownTargetSelector));
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasOpenDropdown = () => {
|
|
||||||
const openDropdowns = document.querySelectorAll<HTMLElement>(
|
|
||||||
'[data-slot="dropdown-menu-content"], [data-slot="select-content"], [role="listbox"], [role="menu"], [data-radix-popper-content-wrapper]'
|
|
||||||
);
|
|
||||||
return Array.from(openDropdowns).some((element) => element.getClientRects().length > 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTerminalShortcutCapture = (e: KeyboardEvent) => {
|
const handleTerminalShortcutCapture = (e: KeyboardEvent) => {
|
||||||
if (!isTerminalEventTarget(e.target)) {
|
if (!isTerminalEventTarget(e.target)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user