106 lines
2.5 KiB
TypeScript
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]);
|
|
}
|