Automatic scrolling with keyboard nav controls

This commit is contained in:
starrieste
2025-12-30 11:22:32 -05:00
parent 51c243a27e
commit 8ae806b64e
4 changed files with 26 additions and 1 deletions

View File

@@ -75,6 +75,10 @@ body::before {
border-radius: 3px;
}
[data-nav-id] {
scroll-margin: 200px;
}
html {
scroll-behavior: smooth;
}
@@ -746,4 +750,4 @@ body.theme-flash::after {
backface-visibility: hidden;
-webkit-perspective: 1000px;
perspective: 1000px;
}
}

View File

@@ -74,6 +74,7 @@ export const AppItem = memo(function AppItem({
return (
<div
data-nav-id={`app:${app.id}`}
role="checkbox"
aria-checked={isSelected}
aria-label={`${app.name}${!isAvailable ? ' (unavailable)' : ''}`}

View File

@@ -43,6 +43,7 @@ export function CategoryHeader({
}) {
return (
<button
data-nav-id={`category:${category}`}
onClick={(e) => { e.stopPropagation(); onFocus?.(); onToggle(); }}
tabIndex={-1}
aria-expanded={isExpanded}

View File

@@ -138,6 +138,25 @@ export function useKeyboardNavigation(
return () => window.removeEventListener('keydown', handleKeyDown);
}, [navItems, focusPos, onToggleCategory, onToggleApp]);
/* Scroll focused item into view automatically */
useEffect(() => {
if (!focusPos) return;
const item = navItems[focusPos.col]?.[focusPos.row];
if (!item) return;
const el = document.querySelector<HTMLElement>(
`[data-nav-id="${item.type}:${item.id}"]`
);
if (!el) return;
el.scrollIntoView({
block: 'nearest',
inline: 'nearest',
});
}, [focusPos, navItems]);
return {
focusPos,
focusedItem,