From 0e6e56696923053b97efaa2ee58ccb0455f3d299 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2026 03:48:53 +0000 Subject: [PATCH] feat(ux): add clear button to filter input in shortcuts dialog Co-authored-by: d-oit <6849456+d-oit@users.noreply.github.com> --- next-env.d.ts | 2 +- .../studio/shortcuts-dialog.test.tsx | 42 +++++++++++++++++-- src/components/studio/shortcuts-dialog.tsx | 19 ++++++++- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/next-env.d.ts b/next-env.d.ts index 9edff1c7..c4b7818f 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/types/routes.d.ts"; +import "./.next/dev/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/src/components/studio/shortcuts-dialog.test.tsx b/src/components/studio/shortcuts-dialog.test.tsx index 026195c4..eabd012b 100644 --- a/src/components/studio/shortcuts-dialog.test.tsx +++ b/src/components/studio/shortcuts-dialog.test.tsx @@ -27,7 +27,7 @@ vi.mock('@/lib/studio/use-reduced-motion', () => ({ })) vi.mock('@/components/studio/ui/shared-primitives', () => ({ - Overlay: ({ children, open, onClose, 'aria-label': ariaLabel }: { + Overlay: ({ children, open, 'aria-label': ariaLabel }: { children: ReactNode open: boolean onClose: () => void @@ -38,7 +38,7 @@ vi.mock('@/components/studio/ui/shared-primitives', () => ({ className?: string }) => open ? ( -
+
{children}
) : null, @@ -62,7 +62,43 @@ vi.mock('@/lib/studio/store', () => ({ ), })) -import { ShortcutsTrigger } from './shortcuts-dialog' +import { ShortcutsDialog, ShortcutsTrigger } from './shortcuts-dialog' + +describe('ShortcutsDialog', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('renders filter search clear button when text is entered and clears input on click', () => { + render( + <> + + + , + ) + + // Open the dialog + fireEvent.click(screen.getByLabelText('Show keyboard shortcuts')) + + const filterInput = screen.getByLabelText('Filter shortcuts') as HTMLInputElement + expect(filterInput.value).toBe('') + expect(screen.queryByLabelText('Clear filter search')).toBeNull() + + // Type filter text + fireEvent.change(filterInput, { target: { value: 'Bold' } }) + expect(filterInput.value).toBe('Bold') + + // Clear button should now be visible + const clearBtn = screen.getByLabelText('Clear filter search') + expect(clearBtn).toBeDefined() + expect(clearBtn.getAttribute('title')).toBe('Clear filter search') + + // Click clear button (prevent default / click handlers on buttons contained inside mocked Overlay) + fireEvent.click(clearBtn) + expect(filterInput.value).toBe('') + expect(screen.queryByLabelText('Clear filter search')).toBeNull() + }) +}) describe('ShortcutsTrigger', () => { beforeEach(() => { diff --git a/src/components/studio/shortcuts-dialog.tsx b/src/components/studio/shortcuts-dialog.tsx index 9aaaf499..f7f00838 100644 --- a/src/components/studio/shortcuts-dialog.tsx +++ b/src/components/studio/shortcuts-dialog.tsx @@ -274,9 +274,26 @@ export function ShortcutsDialog() { value={filter} onChange={(e) => { setFilter(e.target.value); }} placeholder="Filter shortcuts..." - className="w-full rounded-md border border-border bg-background py-1.5 pl-8 pr-3 text-body-sm text-ink placeholder:text-ink-faint focus:border-saffron focus:outline-none focus:ring-1 focus:ring-saffron/30" + className={cn( + 'w-full rounded-md border border-border bg-background py-1.5 pl-8 text-body-sm text-ink placeholder:text-ink-faint focus:border-saffron focus:outline-none focus:ring-1 focus:ring-saffron/30', + filter ? 'pr-8' : 'pr-3', + )} aria-label="Filter shortcuts" /> + {filter && ( + + )}