import { onMounted, onUnmounted } from "vue";
interface KeyboardShortcutOptions {
isOnSubmitStep: () => boolean;
showCancelReason: () => boolean;
isTextLikeElement: (target: EventTarget | null) => boolean;
navigateOptions: (direction: "up" | "down") => void;
navigateQuestions: (direction: "prev" | "next") => void;
toggleCurrentOptionBySpace: () => void;
selectCurrentOption: () => void;
openCancelDialog: () => void;
closeCancelDialog: () => void;
}
/**
* 统一键盘快捷键的注册与处理,保持组件模板简洁。
*/
export function useKeyboardShortcuts(options: KeyboardShortcutOptions) {
function handleKeyDown(event: KeyboardEvent) {
// 取消原因输入弹层打开时:仅允许 Esc 关闭弹层,其他交给默认行为
if (options.showCancelReason()) {
if (event.key === "Escape") {
options.closeCancelDialog();
event.preventDefault();
}
return;
}
// 全局禁用 Tab 焦点跳转,避免破坏自定义键盘导航
if (event.key === "Tab") {
event.preventDefault();
return;
}
if (options.isTextLikeElement(event.target)) {
return;
}
switch (event.key) {
case "ArrowUp":
options.navigateOptions("up");
event.preventDefault();
break;
case "ArrowDown":
options.navigateOptions("down");
event.preventDefault();
break;
case "ArrowLeft":
options.navigateQuestions("prev");
event.preventDefault();
break;
case "ArrowRight":
options.navigateQuestions("next");
event.preventDefault();
break;
case " ":
case "Space":
if (!options.isOnSubmitStep()) {
options.toggleCurrentOptionBySpace();
}
event.preventDefault();
break;
case "Enter":
options.selectCurrentOption();
event.preventDefault();
break;
case "Escape":
options.openCancelDialog();
event.preventDefault();
break;
default:
break;
}
}
onMounted(() => {
window.addEventListener("keydown", handleKeyDown);
});
onUnmounted(() => {
window.removeEventListener("keydown", handleKeyDown);
});
return {
handleKeyDown,
};
}