ERP-node/frontend/components/admin/dashboard/hooks/useKeyboardShortcuts.ts

106 lines
2.5 KiB
TypeScript

import { useEffect, useCallback } from "react";
interface KeyboardShortcutsProps {
selectedElementId: string | null;
onDelete: () => void;
onCopy: () => void;
onPaste: () => void;
onUndo?: () => void;
onRedo?: () => void;
enabled?: boolean;
}
/**
* 대시보드 키보드 단축키 훅
*
* 지원 단축키:
* - Delete: 선택한 요소 삭제
* - Ctrl+C: 요소 복사
* - Ctrl+V: 요소 붙여넣기
* - Ctrl+Z: 실행 취소 (구현 예정)
* - Ctrl+Shift+Z: 재실행 (구현 예정)
*/
export function useKeyboardShortcuts({
selectedElementId,
onDelete,
onCopy,
onPaste,
onUndo,
onRedo,
enabled = true,
}: KeyboardShortcutsProps) {
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (!enabled) return;
// 입력 필드에서는 단축키 비활성화
const target = e.target as HTMLElement;
if (
target.tagName === "INPUT" ||
target.tagName === "TEXTAREA" ||
target.contentEditable === "true" ||
target.closest('[role="dialog"]') ||
target.closest('[role="alertdialog"]')
) {
return;
}
const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0;
const ctrlKey = isMac ? e.metaKey : e.ctrlKey;
// Delete: 선택한 요소 삭제
if (e.key === "Delete" || e.key === "Backspace") {
if (selectedElementId) {
e.preventDefault();
onDelete();
}
return;
}
// Ctrl+C: 복사
if (ctrlKey && e.key === "c") {
if (selectedElementId) {
e.preventDefault();
onCopy();
}
return;
}
// Ctrl+V: 붙여넣기
if (ctrlKey && e.key === "v") {
e.preventDefault();
onPaste();
return;
}
// Ctrl+Z: 실행 취소
if (ctrlKey && e.key === "z" && !e.shiftKey) {
if (onUndo) {
e.preventDefault();
onUndo();
}
return;
}
// Ctrl+Shift+Z 또는 Ctrl+Y: 재실행
if ((ctrlKey && e.shiftKey && e.key === "z") || (ctrlKey && e.key === "y")) {
if (onRedo) {
e.preventDefault();
onRedo();
}
return;
}
},
[enabled, selectedElementId, onDelete, onCopy, onPaste, onUndo, onRedo],
);
useEffect(() => {
if (!enabled) return;
document.addEventListener("keydown", handleKeyDown);
return () => {
document.removeEventListener("keydown", handleKeyDown);
};
}, [handleKeyDown, enabled]);
}