mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-26 23:43:40 +00:00
fix: refactor keyboard shortcut context
This commit is contained in:
parent
75cb26a991
commit
4e335a8fde
5 changed files with 41 additions and 161 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import CloseIcon from '@mui/icons-material/Close';
|
||||
import KeyboardIcon from '@mui/icons-material/Keyboard';
|
||||
import { useKeyboardShortcuts } from '../../contexts/KeyboardShortcutContext';
|
||||
import type { ShortcutCategory } from '../../hooks/useKeyboardShortcutManager';
|
||||
import { useKeyboardShortcuts } from '../../hooks/useKeyboardShortcuts';
|
||||
import type { ShortcutCategory, KeyboardShortcut } from '../../hooks/useKeyboardShortcutManager';
|
||||
|
||||
/**
|
||||
* KeyboardShortcutsHelp Component
|
||||
|
|
@ -55,7 +55,7 @@ const KeyboardShortcutsHelp: React.FC<KeyboardShortcutsHelpProps> = ({
|
|||
{categories.map(category => {
|
||||
const categoryShortcuts = shortcuts
|
||||
.getShortcutsByCategory(category)
|
||||
.filter(s => s.enabled !== false);
|
||||
.filter((s: KeyboardShortcut) => s.enabled !== false);
|
||||
|
||||
if (categoryShortcuts.length === 0) return null;
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ const KeyboardShortcutsHelp: React.FC<KeyboardShortcutsHelpProps> = ({
|
|||
{category}
|
||||
</h3>
|
||||
<div className="space-y-2">
|
||||
{categoryShortcuts.map(shortcut => (
|
||||
{categoryShortcuts.map((shortcut: KeyboardShortcut) => (
|
||||
<div
|
||||
key={shortcut.id}
|
||||
className="flex items-center justify-between py-2 hover:bg-gray-50 px-2 rounded"
|
||||
|
|
|
|||
|
|
@ -1,26 +1,14 @@
|
|||
import React, { createContext, useContext, ReactNode } from 'react';
|
||||
import { useKeyboardShortcutManager } from '../hooks/useKeyboardShortcutManager';
|
||||
|
||||
/**
|
||||
* Keyboard Shortcut Context
|
||||
*
|
||||
* Provides centralized keyboard shortcut management throughout the application.
|
||||
* Components can register shortcuts and the system handles conflicts and priorities.
|
||||
*/
|
||||
|
||||
interface KeyboardShortcutContextValue {
|
||||
shortcuts: ReturnType<typeof useKeyboardShortcutManager>;
|
||||
}
|
||||
|
||||
const KeyboardShortcutContext = createContext<KeyboardShortcutContextValue | null>(null);
|
||||
import React, { ReactNode } from "react";
|
||||
import { useKeyboardShortcutManager } from "../hooks/useKeyboardShortcutManager";
|
||||
import { KeyboardShortcutContext } from "./keyboardShortcut";
|
||||
|
||||
interface KeyboardShortcutProviderProps {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export const KeyboardShortcutProvider: React.FC<KeyboardShortcutProviderProps> = ({
|
||||
children,
|
||||
}) => {
|
||||
export const KeyboardShortcutProvider: React.FC<
|
||||
KeyboardShortcutProviderProps
|
||||
> = ({ children }) => {
|
||||
const shortcuts = useKeyboardShortcutManager();
|
||||
|
||||
return (
|
||||
|
|
@ -29,26 +17,3 @@ export const KeyboardShortcutProvider: React.FC<KeyboardShortcutProviderProps> =
|
|||
</KeyboardShortcutContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hook to access keyboard shortcut manager
|
||||
*
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* const { shortcuts } = useKeyboardShortcuts();
|
||||
*
|
||||
* useEffect(() => {
|
||||
* shortcuts.register({...});
|
||||
* return () => shortcuts.unregister('id');
|
||||
* }, []);
|
||||
* ```
|
||||
*/
|
||||
export function useKeyboardShortcuts() {
|
||||
const context = useContext(KeyboardShortcutContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useKeyboardShortcuts must be used within KeyboardShortcutProvider'
|
||||
);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
|
|
|||
9
src/contexts/keyboardShortcut.ts
Normal file
9
src/contexts/keyboardShortcut.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { createContext } from "react";
|
||||
import { useKeyboardShortcutManager } from "../hooks/useKeyboardShortcutManager";
|
||||
|
||||
export interface KeyboardShortcutContextValue {
|
||||
shortcuts: ReturnType<typeof useKeyboardShortcutManager>;
|
||||
}
|
||||
|
||||
export const KeyboardShortcutContext =
|
||||
createContext<KeyboardShortcutContextValue | null>(null);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect } from "react";
|
||||
import { useKeyboardShortcuts } from "../contexts/KeyboardShortcutContext";
|
||||
import { useKeyboardShortcuts } from "../hooks/useKeyboardShortcuts";
|
||||
import { useWorkspaceStore } from "../stores/workspaceStore";
|
||||
import type { KeyboardShortcut } from "./useKeyboardShortcutManager";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,119 +1,25 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useWorkspaceStore } from '../stores/workspaceStore';
|
||||
import { useContext } from "react";
|
||||
import { KeyboardShortcutContext } from "../contexts/keyboardShortcut";
|
||||
|
||||
/**
|
||||
* useKeyboardShortcuts Hook
|
||||
* Hook to access keyboard shortcut manager
|
||||
*
|
||||
* Global keyboard shortcuts for the application:
|
||||
* - Ctrl/Cmd + Tab: Next document
|
||||
* - Ctrl/Cmd + Shift + Tab: Previous document
|
||||
* - Ctrl/Cmd + W: Close current document
|
||||
* - Ctrl/Cmd + N: New document
|
||||
* - Ctrl/Cmd + S: Save current document (trigger save immediately)
|
||||
* - Ctrl/Cmd + O: Open document manager
|
||||
* - Ctrl/Cmd + Z: Undo (per-document)
|
||||
* - Ctrl/Cmd + Y / Ctrl/Cmd + Shift + Z: Redo (per-document)
|
||||
* Usage:
|
||||
* ```tsx
|
||||
* const { shortcuts } = useKeyboardShortcuts();
|
||||
*
|
||||
* useEffect(() => {
|
||||
* shortcuts.register({...});
|
||||
* return () => shortcuts.unregister('id');
|
||||
* }, []);
|
||||
* ```
|
||||
*/
|
||||
|
||||
interface UseKeyboardShortcutsOptions {
|
||||
onOpenDocumentManager?: () => void;
|
||||
onUndo?: () => void;
|
||||
onRedo?: () => void;
|
||||
export function useKeyboardShortcuts() {
|
||||
const context = useContext(KeyboardShortcutContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useKeyboardShortcuts must be used within KeyboardShortcutProvider",
|
||||
);
|
||||
}
|
||||
|
||||
export function useKeyboardShortcuts(options?: UseKeyboardShortcutsOptions) {
|
||||
const {
|
||||
documentOrder,
|
||||
activeDocumentId,
|
||||
switchToDocument,
|
||||
closeDocument,
|
||||
createDocument,
|
||||
saveDocument,
|
||||
} = useWorkspaceStore();
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||
const modifier = isMac ? e.metaKey : e.ctrlKey;
|
||||
|
||||
// Ctrl/Cmd + Tab - Next document
|
||||
if (modifier && e.key === 'Tab' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
const currentIndex = documentOrder.findIndex(id => id === activeDocumentId);
|
||||
if (currentIndex !== -1) {
|
||||
const nextIndex = (currentIndex + 1) % documentOrder.length;
|
||||
switchToDocument(documentOrder[nextIndex]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + Shift + Tab - Previous document
|
||||
if (modifier && e.key === 'Tab' && e.shiftKey) {
|
||||
e.preventDefault();
|
||||
const currentIndex = documentOrder.findIndex(id => id === activeDocumentId);
|
||||
if (currentIndex !== -1) {
|
||||
const prevIndex = (currentIndex - 1 + documentOrder.length) % documentOrder.length;
|
||||
switchToDocument(documentOrder[prevIndex]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + W - Close current document
|
||||
if (modifier && e.key === 'w') {
|
||||
e.preventDefault();
|
||||
if (activeDocumentId && documentOrder.length > 1) {
|
||||
closeDocument(activeDocumentId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + N - New document
|
||||
if (modifier && e.key === 'n') {
|
||||
e.preventDefault();
|
||||
createDocument();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + S - Save current document
|
||||
if (modifier && e.key === 's') {
|
||||
e.preventDefault();
|
||||
if (activeDocumentId) {
|
||||
saveDocument(activeDocumentId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + O - Open document manager
|
||||
if (modifier && e.key === 'o') {
|
||||
e.preventDefault();
|
||||
options?.onOpenDocumentManager?.();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + Z - Undo
|
||||
if (modifier && e.key === 'z' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
options?.onUndo?.();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ctrl/Cmd + Y or Ctrl/Cmd + Shift + Z - Redo
|
||||
if (modifier && (e.key === 'y' || (e.key === 'z' && e.shiftKey))) {
|
||||
e.preventDefault();
|
||||
options?.onRedo?.();
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [
|
||||
documentOrder,
|
||||
activeDocumentId,
|
||||
switchToDocument,
|
||||
closeDocument,
|
||||
createDocument,
|
||||
saveDocument,
|
||||
options,
|
||||
]);
|
||||
return context;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue