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:

  1. Import the necessary components from @/components/key-navigation
  2. Replace your existing key content overlay with KeyContentViewer
  3. Pass your list of keys and the initial key to view
  4. Provide an onClose handler to close the viewer

Advanced Integration

For more control over the UI, you can use the KeyNavigator component directly:

  1. Import KeyNavigator from @/components/key-navigation
  2. Convert your keys to navigation items
  3. Use the render props pattern to access navigation state and functions
  4. Build your custom UI using the provided props

API Reference

KeyNavigator Props

PropTypeDescription
itemsKeyNavigationItem[]Array of items to navigate through
initialIndexnumberInitial index to start navigation from
onNavigate(item, index) => voidCallback when navigation occurs
onExit() => voidCallback when navigation is exited
keyboardEnabledbooleanWhether keyboard navigation is enabled
navigationKeysobjectCustom keyboard keys for navigation
children(props) => ReactNodeRender props function for UI

KeyNavigatorChildProps

PropTypeDescription
currentItemKeyNavigationItem | nullThe currently selected item
currentIndexnumberIndex of the current item
totalItemsnumberTotal number of items
hasPreviousbooleanWhether there's a previous item
hasNextbooleanWhether there's a next item
navigatePrevious() => voidFunction to navigate to previous item
navigateNext() => voidFunction to navigate to next item
exit() => voidFunction to exit navigation
isNavigatingbooleanWhether 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 keyboardEnabled is set to true (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 onNavigate callback is properly updating your state
  • Check that the currentItem is 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