mirror of
https://github.com/supabase/supabase.git
synced 2026-05-06 08:56:46 -04:00
fix(studio): preserve ignoreInputs across re-renders in useShortcut (#45174)
## Summary Fixes [FE-3060](https://linear.app/supabase/issue/FE-3060/modshiftc-modshiftm-shortcuts-suppressed-when-a-table-editor-cell-is). `Mod+Shift+C` (Copy as CSV) and `Mod+Shift+M` (Copy as Markdown) — and any other Meta/Ctrl/Escape shortcut registered via `useShortcut` without an explicit `ignoreInputs` — stopped firing when focus landed on a `react-data-grid` cell in the table editor (or any other input/contenteditable). ## Fix In `apps/studio/state/shortcuts/useShortcut.tsx`, only include `ignoreInputs` in the options object when it's actually set, so TanStack's register-time default sticks across re-renders. Updated the `ignoreInputs resolution` test to assert that the key is omitted (rather than passed as `undefined`) when neither caller nor registry set it. ## Test plan - [x] SQL editor results: `Cmd+Shift+C`, `Cmd+Shift+M`, `Cmd+Shift+J`, `Cmd+Shift+D` still fire - [x] `Mod+ArrowUp` / `Mod+ArrowDown` / `Mod+ArrowLeft` / `Mod+ArrowRight` inside a focused cell editor still blocked (registry sets `ignoreInputs: true`) - [x] Unit tests: `pnpm vitest run state/shortcuts/useShortcut.test.tsx` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed keyboard shortcut handling to properly respect the hotkey library's default configuration values when custom options are not explicitly specified. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -118,9 +118,10 @@ describe('useShortcut', () => {
|
||||
})
|
||||
|
||||
describe('ignoreInputs resolution', () => {
|
||||
it('defaults to undefined when no registry default and no caller override', () => {
|
||||
it('omits the key when no registry default and no caller override (library applies its per-hotkey default)', () => {
|
||||
renderHook(() => useShortcut(SHORTCUT_IDS.COMMAND_MENU_OPEN, vi.fn()))
|
||||
expect(getLastHotkeyOptions().ignoreInputs).toBeUndefined()
|
||||
const options = getLastHotkeyOptions()
|
||||
expect('ignoreInputs' in options).toBe(false)
|
||||
})
|
||||
|
||||
it('uses the registry default when no caller override', () => {
|
||||
|
||||
@@ -60,7 +60,16 @@ export function useShortcut(id: ShortcutId, callback: () => void, options?: Shor
|
||||
const timeout = options?.timeout ?? def.options?.timeout ?? undefined
|
||||
const ignoreInputs = options?.ignoreInputs ?? def.options?.ignoreInputs
|
||||
|
||||
useHotkeySequence(def.sequence, callback, { enabled, timeout, ignoreInputs })
|
||||
// Only include `ignoreInputs` when set. The library resolves it to a concrete
|
||||
// boolean at register time (false for Meta/Ctrl/Escape, true otherwise), but
|
||||
// its setOptions does an object spread on every re-render — passing
|
||||
// `ignoreInputs: undefined` would overwrite the resolved value and re-enable
|
||||
// the input-focus guard for shortcuts that should always fire.
|
||||
useHotkeySequence(def.sequence, callback, {
|
||||
enabled,
|
||||
timeout,
|
||||
...(ignoreInputs !== undefined && { ignoreInputs }),
|
||||
})
|
||||
|
||||
// Handle overrides for command menu
|
||||
const enabledInCommandMenu = enabled && (options?.registerInCommandMenu ?? false)
|
||||
|
||||
Reference in New Issue
Block a user