Skip to content

Commit 9f42f07

Browse files
committed
Fix #132: don't clear sidebar search on Escape while a dialog is open
1 parent ab4501c commit 9f42f07

4 files changed

Lines changed: 44 additions & 2 deletions

File tree

ui2/src/App.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {Breadcrumb, BreadcrumbItem, BreadcrumbList, BreadcrumbPage, BreadcrumbSe
1616
import {TestContainer} from './components/TestContainer';
1717
import {NotesCard} from './components/NotesCard';
1818
import {TooltipProvider} from "@/components/ui/tooltip";
19+
import {hasOpenDialog, shouldClearSearchOnEscape} from "@/util/escapeGuard";
1920

2021
const App = () => {
2122
const [config, setConfig] = useState<KensaConfig>(DEFAULT_CONFIG);
@@ -147,7 +148,13 @@ const App = () => {
147148

148149
useEffect(() => {
149150
const handleEscape = (e: KeyboardEvent) => {
150-
if (e.key === "Escape" && searchQueryRef.current && !commandOpenRef.current) {
151+
if (e.key !== "Escape") return;
152+
const clear = shouldClearSearchOnEscape({
153+
hasQuery: !!searchQueryRef.current,
154+
isCommandOpen: commandOpenRef.current,
155+
isDialogOpen: hasOpenDialog(),
156+
});
157+
if (clear) {
151158
e.preventDefault();
152159
onSearchChange('');
153160
}

ui2/src/components/AppSidebar.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {Popover, PopoverContent, PopoverTrigger,} from "@/components/ui/popover"
1313
import {Kbd, KbdGroup} from "@/components/ui/kbd"
1414
import {useConfig} from "@/contexts/ConfigContext"
1515
import {matchesAnyIssue} from "@/util/issueMatch"
16+
import {hasOpenDialog} from "@/util/escapeGuard"
1617

1718
interface StateCounts {
1819
passed: number;
@@ -91,7 +92,7 @@ export function AppSidebar({indices, searchQuery, onSearchChange, onSelect, sele
9192

9293
React.useEffect(() => {
9394
const handleEscape = (e: KeyboardEvent) => {
94-
if (e.key === 'Escape' && inputValueRef.current) {
95+
if (e.key === 'Escape' && inputValueRef.current && !hasOpenDialog()) {
9596
e.preventDefault();
9697
setInputValue('');
9798
setShowPicker(false);

ui2/src/util/escapeGuard.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { shouldClearSearchOnEscape } from './escapeGuard';
3+
4+
describe('shouldClearSearchOnEscape', () => {
5+
it('returns true when there is a query and nothing else is open', () => {
6+
expect(shouldClearSearchOnEscape({ hasQuery: true, isCommandOpen: false, isDialogOpen: false })).toBe(true);
7+
});
8+
9+
it('returns false when the query is empty', () => {
10+
expect(shouldClearSearchOnEscape({ hasQuery: false, isCommandOpen: false, isDialogOpen: false })).toBe(false);
11+
});
12+
13+
it('returns false when the command palette is open', () => {
14+
expect(shouldClearSearchOnEscape({ hasQuery: true, isCommandOpen: true, isDialogOpen: false })).toBe(false);
15+
});
16+
17+
it('returns false when any dialog is open', () => {
18+
expect(shouldClearSearchOnEscape({ hasQuery: true, isCommandOpen: false, isDialogOpen: true })).toBe(false);
19+
});
20+
});

ui2/src/util/escapeGuard.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface EscapeState {
2+
hasQuery: boolean;
3+
isCommandOpen: boolean;
4+
isDialogOpen: boolean;
5+
}
6+
7+
export function shouldClearSearchOnEscape(state: EscapeState): boolean {
8+
return state.hasQuery && !state.isCommandOpen && !state.isDialogOpen;
9+
}
10+
11+
export function hasOpenDialog(): boolean {
12+
if (typeof document === 'undefined') return false;
13+
return document.querySelector('[role="dialog"][data-state="open"]') !== null;
14+
}

0 commit comments

Comments
 (0)