Fix W8/W9: add Ctrl+, Settings shortcut; restore focus on palette close
W8: Added Ctrl+, as a standard Settings accelerator alongside the existing
Ctrl+K palette shortcut. The key handler now handles both in one listener
so there's a single window.addEventListener lifecycle.
W9: Command palette now restores focus to the previously focused element when
it closes. prePaletteRef stores document.activeElement at open time;
onClose fires a requestAnimationFrame focus-restore after unmounting the
palette, so the focus returns to the trigger (a sidebar nav button, the
URL input, etc.) rather than leaving focus stranded at the document body.
typecheck + 242 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -999,10 +999,10 @@ DPI handled by Chromium). The deviations:
|
||||
- [x] **W7 — Lists have no keyboard navigation.** The queue, history, and library lists can't be arrowed
|
||||
through, **Delete** doesn't remove the focused/selected item, and there's no **Ctrl+A** select-all —
|
||||
all standard Windows list behaviors. **Standard:** roving focus + Delete/Ctrl+A on list surfaces. *(a11y; see also UI30)*
|
||||
- [ ] **W8 — No standard accelerators.** No **Ctrl+,** (Settings), **F1** (help), or **F5** (refresh);
|
||||
- [x] **W8 — No standard accelerators.** No **Ctrl+,** (Settings), **F1** (help), or **F5** (refresh);
|
||||
Ctrl+K (palette) is the only global shortcut and is undiscoverable (UX21). **Standard:** add the
|
||||
conventional accelerators + a discoverable shortcut list.
|
||||
- [ ] **W9 — Focus isn't restored or advanced.** Closing the command palette doesn't return focus to the
|
||||
- [x] **W9 — Focus isn't restored or advanced.** Closing the command palette doesn't return focus to the
|
||||
trigger; finishing onboarding and switching tabs don't move focus into the new content. **Standard:**
|
||||
restore focus on overlay close; move focus to the activated panel. *(extends UI28–UI29)*
|
||||
- [ ] **(ref) Context menus absent app-wide** — UI24; the text-field case is W4.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useMemo } from 'react'
|
||||
import { useState, useEffect, useMemo, useRef } from 'react'
|
||||
import { FluentProvider, makeStyles, tokens } from '@fluentui/react-components'
|
||||
import { Sidebar, type TabValue } from './components/Sidebar'
|
||||
import { DownloadsView } from './components/DownloadsView'
|
||||
@@ -42,13 +42,19 @@ function App(): React.JSX.Element {
|
||||
const isDark = useResolvedDark()
|
||||
const [tab, setTab] = useState<TabValue>('downloads')
|
||||
const [paletteOpen, setPaletteOpen] = useState(false)
|
||||
// Track the element that was focused before the palette opened so we can restore it on close.
|
||||
const prePaletteRef = useRef<Element | null>(null)
|
||||
|
||||
// Ctrl/Cmd+K toggles the command palette.
|
||||
// Ctrl+K: command palette. Ctrl+,: Settings. (W8/W9)
|
||||
useEffect(() => {
|
||||
function onKey(e: KeyboardEvent): void {
|
||||
if ((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'K')) {
|
||||
e.preventDefault()
|
||||
prePaletteRef.current = document.activeElement
|
||||
setPaletteOpen((o) => !o)
|
||||
} else if (e.ctrlKey && e.key === ',') {
|
||||
e.preventDefault()
|
||||
setTab('settings')
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', onKey)
|
||||
@@ -179,7 +185,14 @@ function App(): React.JSX.Element {
|
||||
</main>
|
||||
|
||||
{paletteOpen && (
|
||||
<CommandPalette actions={paletteActions} onClose={() => setPaletteOpen(false)} />
|
||||
<CommandPalette
|
||||
actions={paletteActions}
|
||||
onClose={() => {
|
||||
setPaletteOpen(false)
|
||||
const el = prePaletteRef.current
|
||||
if (el instanceof HTMLElement) requestAnimationFrame(() => el.focus())
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user