Key Navigation Components
A comprehensive system for navigating between keys in the Narrative Group Database with keyboard shortcuts and UI controls.
Overview
The Key Navigation system provides a standardized way to navigate between keys in the database using both UI controls and keyboard shortcuts. It's designed to be flexible, reusable, and easy to integrate into existing components.
Components
KeyNavigator
The core component that manages navigation state and keyboard shortcuts. It doesn't render any UI itself but provides props to its children.
import { KeyNavigator } from '@/components/key-navigation'
// Example usage
<KeyNavigator
items={keys.map(key => ({ key }))}
initialIndex={0}
onNavigate={(item, index) => console.log("Navigated to " + item.key)}
onExit={() => console.log("Navigation exited")}
navigationKeys={{
previous: 'e',
next: 'u',
exit: 'Escape'
}}
>
{(navProps) => (
<div>
<h2>{navProps.currentItem?.key}</h2>
<button onClick={navProps.navigatePrevious} disabled={!navProps.hasPrevious}>
Previous
</button>
<button onClick={navProps.navigateNext} disabled={!navProps.hasNext}>
Next
</button>
</div>
)}
</KeyNavigator>KeyNavigationControls
A UI component that renders navigation controls (previous/next buttons) and position indicators.
import { KeyNavigationControls } from '@/components/key-navigation'
// Example usage with KeyNavigator
<KeyNavigator items={items}>
{(navProps) => (
<div>
<KeyNavigationControls
{...navProps}
showPosition={true}
showKeyboardShortcuts={true}
/>
{/* Content */}
</div>
)}
</KeyNavigator>KeyNavigationShortcuts
A component that displays available keyboard shortcuts in a consistent format.
import { KeyNavigationShortcuts } from '@/components/key-navigation'
// Example usage
<KeyNavigationShortcuts
showNavigation={true}
showCopy={true}
navigationKeys={{
previous: 'e',
next: 'u',
exit: 'Escape'
}}
copyKeys={{
key: 'k',
content: 'c'
}}
/>KeyContentViewer
A complete component that combines all the above to create a full key content viewing experience with navigation.
import { KeyContentViewer } from '@/components/key-navigation'
// Example usage
<KeyContentViewer
keys={['key1', 'key2', 'key3']}
initialKey="key2"
onClose={() => setViewingKey(null)}
navigationKeys={{
previous: 'e',
next: 'u',
exit: 'Escape'
}}
/>Integration Guide
Basic Integration
To integrate the key navigation system into an existing component:
- Import the necessary components from
@/components/key-navigation - Replace your existing key content overlay with
KeyContentViewer - Pass your list of keys and the initial key to view
- Provide an
onClosehandler to close the viewer
Advanced Integration
For more control over the UI, you can use the KeyNavigator component directly:
- Import
KeyNavigatorfrom@/components/key-navigation - Convert your keys to navigation items
- Use the render props pattern to access navigation state and functions
- Build your custom UI using the provided props
API Reference
KeyNavigator Props
| Prop | Type | Description |
|---|---|---|
items | KeyNavigationItem[] | Array of items to navigate through |
initialIndex | number | Initial index to start navigation from |
onNavigate | (item, index) => void | Callback when navigation occurs |
onExit | () => void | Callback when navigation is exited |
keyboardEnabled | boolean | Whether keyboard navigation is enabled |
navigationKeys | object | Custom keyboard keys for navigation |
children | (props) => ReactNode | Render props function for UI |
KeyNavigatorChildProps
| Prop | Type | Description |
|---|---|---|
currentItem | KeyNavigationItem | null | The currently selected item |
currentIndex | number | Index of the current item |
totalItems | number | Total number of items |
hasPrevious | boolean | Whether there's a previous item |
hasNext | boolean | Whether there's a next item |
navigatePrevious | () => void | Function to navigate to previous item |
navigateNext | () => void | Function to navigate to next item |
exit | () => void | Function to exit navigation |
isNavigating | boolean | Whether navigation is in progress |
Examples
Basic Usage
import { useState } from 'react'
import { KeyContentViewer } from '@/components/key-navigation'
export function KeyClusterView({ keys }) {
const [viewingKey, setViewingKey] = useState(null)
return (
<div>
{/* Key list */}
<ul>
{keys.map(key => (
<li key={key}>
<button onClick={() => setViewingKey(key)}>
{key}
</button>
</li>
))}
</ul>
{/* Key content viewer with navigation */}
{viewingKey && (
<KeyContentViewer
keys={keys}
initialKey={viewingKey}
onClose={() => setViewingKey(null)}
navigationKeys={{
previous: 'e',
next: 'u',
exit: 'Escape'
}}
/>
)}
</div>
)
}Custom UI
import { useState } from 'react'
import { KeyNavigator, KeyNavigationControls } from '@/components/key-navigation'
export function CustomKeyViewer({ keys }) {
const [isOpen, setIsOpen] = useState(false)
const [selectedKey, setSelectedKey] = useState(null)
// Find initial index
const initialIndex = selectedKey ? keys.indexOf(selectedKey) : 0
return (
<div>
<button onClick={() => setIsOpen(true)}>
Open Viewer
</button>
{isOpen && (
<div className="modal">
<KeyNavigator
items={keys.map(key => ({ key }))}
initialIndex={initialIndex}
onExit={() => setIsOpen(false)}
navigationKeys={{
previous: 'e',
next: 'u',
exit: 'Escape'
}}
>
{(navProps) => (
<div className="custom-viewer">
<h2>{navProps.currentItem?.key}</h2>
<KeyNavigationControls {...navProps} />
<div className="content">
{/* Custom content rendering */}
</div>
<div className="footer">
<button onClick={navProps.exit}>Close</button>
</div>
</div>
)}
</KeyNavigator>
</div>
)}
</div>
)
}Troubleshooting
Keyboard Shortcuts Not Working
If keyboard shortcuts aren't working, check the following:
- Ensure
keyboardEnabledis set totrue(it's true by default) - Check if any input elements are focused, as shortcuts are disabled when inputs have focus
- Verify that the navigation keys are correctly configured
- Make sure there are no conflicting keyboard event listeners in parent components
Navigation Not Updating Content
If navigation works but content doesn't update:
- Ensure the
onNavigatecallback is properly updating your state - Check that the
currentItemis being used to render content - Verify that content fetching is triggered when the current item changes
Best Practices
- Always provide clear visual indicators for keyboard shortcuts
- Use consistent keyboard shortcuts throughout the application
- Implement proper focus management for accessibility
- Provide fallback UI controls for users who don't use keyboard shortcuts
- Consider adding haptic or visual feedback when navigation occurs