useShortcuts Hook

Access WebShorts functionality and manage shortcuts programmatically using the useShortcuts hook.

Basic Usage

Import and use the useShortcuts hook in any component within the WebShortsProvider:

import { useShortcuts } from '@chrisnski/webshorts';

function MyComponent() {
  const { shortcuts, registerShortcut, unregisterShortcut } = useShortcuts();
  
  // Use the hook values
  return <div>My Component</div>;
}

Hook Return Values

The useShortcuts hook returns an object with the following properties:

State Values

shortcuts

Array of all registered shortcuts

currentPage

Current page/route

isDialogOpen

Whether help dialog is open

debug

Debug mode status

Functions

registerShortcut

Register a new shortcut programmatically

unregisterShortcut

Remove a registered shortcut

openDialog

Open the help dialog

closeDialog

Close the help dialog

Function Examples

registerShortcut

function MyComponent() {
  const { registerShortcut } = useShortcuts();
  
  useEffect(() => {
    // Register a shortcut programmatically
    registerShortcut({
      keys: 'CTRL + SHIFT + S',
      action: () => console.log('Custom save action'),
      description: 'Custom save shortcut',
      page: '/editor'
    });
  }, [registerShortcut]);
  
  return <div>Component with custom shortcut</div>;
}

unregisterShortcut

function MyComponent() {
  const { unregisterShortcut } = useShortcuts();
  
  const handleRemoveShortcut = () => {
    // Remove a specific shortcut
    unregisterShortcut('CTRL + SHIFT + S');
  };
  
  return (
    <button onClick={handleRemoveShortcut}>
      Remove Shortcut
    </button>
  );
}

openDialog / closeDialog

function HelpButton() {
  const { openDialog, closeDialog, isDialogOpen } = useShortcuts();
  
  return (
    <div>
      <button onClick={openDialog}>
        Show Help
      </button>
      
      {isDialogOpen && (
        <button onClick={closeDialog}>
          Close Help
        </button>
      )}
    </div>
  );
}

State Usage

Accessing Shortcuts

function ShortcutsList() {
  const { shortcuts } = useShortcuts();
  
  return (
    <div>
      <h3>Available Shortcuts:</h3>
      <ul>
        {shortcuts.map((shortcut, index) => (
          <li key={index}>
            {shortcut.keys} - {shortcut.description}
          </li>
        ))}
      </ul>
    </div>
  );
}

Current Page Awareness

function PageSpecificComponent() {
  const { currentPage } = useShortcuts();
  
  return (
    <div>
      <p>Current page: {currentPage}</p>
      
      {currentPage === '/dashboard' && (
        <div>Dashboard-specific content</div>
      )}
      
      {currentPage === '/editor' && (
        <div>Editor-specific content</div>
      )}
    </div>
  );
}

Dialog State

function DialogAwareComponent() {
  const { isDialogOpen, openDialog } = useShortcuts();
  
  return (
    <div>
      <button 
        onClick={openDialog}
        disabled={isDialogOpen}
      >
        {isDialogOpen ? 'Dialog Open' : 'Open Help'}
      </button>
      
      {isDialogOpen && (
        <div className='overlay'>
          Help dialog is currently open
        </div>
      )}
    </div>
  );
}

Advanced Patterns

Dynamic Shortcuts

function DynamicShortcuts() {
  const { registerShortcut, unregisterShortcut } = useShortcuts();
  const [isEditing, setIsEditing] = useState(false);
  
  useEffect(() => {
    if (isEditing) {
      // Register editing shortcuts
      registerShortcut({
        keys: 'CTRL + S',
        action: handleSave,
        description: 'Save document'
      });
      
      registerShortcut({
        keys: 'ESC',
        action: () => setIsEditing(false),
        description: 'Exit edit mode'
      });
    } else {
      // Remove editing shortcuts
      unregisterShortcut('CTRL + S');
      unregisterShortcut('ESC');
    }
  }, [isEditing, registerShortcut, unregisterShortcut]);
  
  return (
    <button onClick={() => setIsEditing(!isEditing)}>
      {isEditing ? 'Stop Editing' : 'Start Editing'}
    </button>
  );
}

Shortcut Analytics

function ShortcutAnalytics() {
  const { shortcuts } = useShortcuts();
  const [usageStats, setUsageStats] = useState({});
  
  useEffect(() => {
    // Track shortcut usage
    const stats = shortcuts.reduce((acc, shortcut) => {
      acc[shortcut.keys] = {
        description: shortcut.description,
        page: shortcut.page,
        usageCount: 0
      };
      return acc;
    }, {});
    
    setUsageStats(stats);
  }, [shortcuts]);
  
  return (
    <div>
      <h3>Shortcut Usage Statistics</h3>
      <pre>{JSON.stringify(usageStats, null, 2)}</pre>
    </div>
  );
}

Custom Hook

// Custom hook for specific functionality
function useEditorShortcuts() {
  const { registerShortcut, unregisterShortcut } = useShortcuts();
  
  const registerEditorShortcuts = useCallback(() => {
    registerShortcut({
      keys: 'CTRL + B',
      action: () => document.execCommand('bold'),
      description: 'Bold text'
    });
    
    registerShortcut({
      keys: 'CTRL + I',
      action: () => document.execCommand('italic'),
      description: 'Italic text'
    });
  }, [registerShortcut]);
  
  const unregisterEditorShortcuts = useCallback(() => {
    unregisterShortcut('CTRL + B');
    unregisterShortcut('CTRL + I');
  }, [unregisterShortcut]);
  
  return {
    registerEditorShortcuts,
    unregisterEditorShortcuts
  };
}

// Usage
function Editor() {
  const { registerEditorShortcuts, unregisterEditorShortcuts } = useEditorShortcuts();
  
  useEffect(() => {
    registerEditorShortcuts();
    return () => unregisterEditorShortcuts();
  }, [registerEditorShortcuts, unregisterEditorShortcuts]);
  
  return <div>Editor with custom shortcuts</div>;
}

Error Handling

Handle potential errors when using the useShortcuts hook:

function SafeShortcutsComponent() {
  const shortcutsContext = useShortcuts();
  
  // Check if hook is available
  if (!shortcutsContext) {
    return <div>WebShorts not available</div>;
  }
  
  const { shortcuts, registerShortcut } = shortcutsContext;
  
  const handleRegisterShortcut = useCallback((shortcut) => {
    try {
      registerShortcut(shortcut);
    } catch (error) {
      console.error('Failed to register shortcut:', error);
      // Handle error appropriately
    }
  }, [registerShortcut]);
  
  return (
    <div>
      <button onClick={() => handleRegisterShortcut({
        keys: 'CTRL + T',
        action: () => console.log('Test shortcut'),
        description: 'Test shortcut'
      })}>
        Register Test Shortcut
      </button>
    </div>
  );
}

Best Practices

✅ Do

  • • Use the hook only within WebShortsProvider
  • • Clean up shortcuts when components unmount
  • • Use useCallback for function dependencies
  • • Handle errors gracefully
  • • Check for hook availability
  • • Use descriptive shortcut descriptions

❌ Don't

  • • Use the hook outside of WebShortsProvider
  • • Forget to clean up registered shortcuts
  • • Create infinite re-render loops
  • • Ignore error handling
  • • Use the hook in server components (Next.js)
  • • Register duplicate shortcuts

Troubleshooting

"useShortcuts must be used within WebShortsProvider"

  • • Ensure WebShortsProvider wraps your component tree
  • • Check that the component is a client component (Next.js)
  • • Verify the import path is correct
  • • Make sure the hook is called in a React component

Shortcuts not registering?

  • • Check that the shortcut object has required properties
  • • Verify the keys format is correct
  • • Ensure the action function is properly defined
  • • Check for conflicts with existing shortcuts
  • • Enable debug mode to see registration feedback

Performance issues?

  • • Use useCallback for function dependencies
  • • Avoid registering shortcuts in render
  • • Clean up shortcuts in useEffect cleanup
  • • Use React.memo for components that use the hook
  • • Limit the number of shortcuts registered