mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-27 07:43:41 +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 React from 'react';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import KeyboardIcon from '@mui/icons-material/Keyboard';
|
import KeyboardIcon from '@mui/icons-material/Keyboard';
|
||||||
import { useKeyboardShortcuts } from '../../contexts/KeyboardShortcutContext';
|
import { useKeyboardShortcuts } from '../../hooks/useKeyboardShortcuts';
|
||||||
import type { ShortcutCategory } from '../../hooks/useKeyboardShortcutManager';
|
import type { ShortcutCategory, KeyboardShortcut } from '../../hooks/useKeyboardShortcutManager';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* KeyboardShortcutsHelp Component
|
* KeyboardShortcutsHelp Component
|
||||||
|
|
@ -55,7 +55,7 @@ const KeyboardShortcutsHelp: React.FC<KeyboardShortcutsHelpProps> = ({
|
||||||
{categories.map(category => {
|
{categories.map(category => {
|
||||||
const categoryShortcuts = shortcuts
|
const categoryShortcuts = shortcuts
|
||||||
.getShortcutsByCategory(category)
|
.getShortcutsByCategory(category)
|
||||||
.filter(s => s.enabled !== false);
|
.filter((s: KeyboardShortcut) => s.enabled !== false);
|
||||||
|
|
||||||
if (categoryShortcuts.length === 0) return null;
|
if (categoryShortcuts.length === 0) return null;
|
||||||
|
|
||||||
|
|
@ -65,7 +65,7 @@ const KeyboardShortcutsHelp: React.FC<KeyboardShortcutsHelpProps> = ({
|
||||||
{category}
|
{category}
|
||||||
</h3>
|
</h3>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{categoryShortcuts.map(shortcut => (
|
{categoryShortcuts.map((shortcut: KeyboardShortcut) => (
|
||||||
<div
|
<div
|
||||||
key={shortcut.id}
|
key={shortcut.id}
|
||||||
className="flex items-center justify-between py-2 hover:bg-gray-50 px-2 rounded"
|
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 React, { ReactNode } from "react";
|
||||||
import { useKeyboardShortcutManager } from '../hooks/useKeyboardShortcutManager';
|
import { useKeyboardShortcutManager } from "../hooks/useKeyboardShortcutManager";
|
||||||
|
import { KeyboardShortcutContext } from "./keyboardShortcut";
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
interface KeyboardShortcutProviderProps {
|
interface KeyboardShortcutProviderProps {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const KeyboardShortcutProvider: React.FC<KeyboardShortcutProviderProps> = ({
|
export const KeyboardShortcutProvider: React.FC<
|
||||||
children,
|
KeyboardShortcutProviderProps
|
||||||
}) => {
|
> = ({ children }) => {
|
||||||
const shortcuts = useKeyboardShortcutManager();
|
const shortcuts = useKeyboardShortcutManager();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -29,26 +17,3 @@ export const KeyboardShortcutProvider: React.FC<KeyboardShortcutProviderProps> =
|
||||||
</KeyboardShortcutContext.Provider>
|
</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 { useEffect } from "react";
|
||||||
import { useKeyboardShortcuts } from "../contexts/KeyboardShortcutContext";
|
import { useKeyboardShortcuts } from "../hooks/useKeyboardShortcuts";
|
||||||
import { useWorkspaceStore } from "../stores/workspaceStore";
|
import { useWorkspaceStore } from "../stores/workspaceStore";
|
||||||
import type { KeyboardShortcut } from "./useKeyboardShortcutManager";
|
import type { KeyboardShortcut } from "./useKeyboardShortcutManager";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,119 +1,25 @@
|
||||||
import { useEffect } from 'react';
|
import { useContext } from "react";
|
||||||
import { useWorkspaceStore } from '../stores/workspaceStore';
|
import { KeyboardShortcutContext } from "../contexts/keyboardShortcut";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* useKeyboardShortcuts Hook
|
* Hook to access keyboard shortcut manager
|
||||||
*
|
*
|
||||||
* Global keyboard shortcuts for the application:
|
* Usage:
|
||||||
* - Ctrl/Cmd + Tab: Next document
|
* ```tsx
|
||||||
* - Ctrl/Cmd + Shift + Tab: Previous document
|
* const { shortcuts } = useKeyboardShortcuts();
|
||||||
* - Ctrl/Cmd + W: Close current document
|
*
|
||||||
* - Ctrl/Cmd + N: New document
|
* useEffect(() => {
|
||||||
* - Ctrl/Cmd + S: Save current document (trigger save immediately)
|
* shortcuts.register({...});
|
||||||
* - Ctrl/Cmd + O: Open document manager
|
* return () => shortcuts.unregister('id');
|
||||||
* - Ctrl/Cmd + Z: Undo (per-document)
|
* }, []);
|
||||||
* - Ctrl/Cmd + Y / Ctrl/Cmd + Shift + Z: Redo (per-document)
|
* ```
|
||||||
*/
|
*/
|
||||||
|
export function useKeyboardShortcuts() {
|
||||||
interface UseKeyboardShortcutsOptions {
|
const context = useContext(KeyboardShortcutContext);
|
||||||
onOpenDocumentManager?: () => void;
|
if (!context) {
|
||||||
onUndo?: () => void;
|
throw new Error(
|
||||||
onRedo?: () => void;
|
"useKeyboardShortcuts must be used within KeyboardShortcutProvider",
|
||||||
}
|
);
|
||||||
|
}
|
||||||
export function useKeyboardShortcuts(options?: UseKeyboardShortcutsOptions) {
|
return context;
|
||||||
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,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue