From ae2ba0add5aebc9b0415e7cb9f51ef949c47878a Mon Sep 17 00:00:00 2001 From: ysCha Date: Thu, 7 May 2026 11:14:09 +0900 Subject: [PATCH] =?UTF-8?q?[755]=20=EA=B0=9D=EC=B2=B4=20=EC=84=A0=ED=83=9D?= =?UTF-8?q?=20=EC=8B=9C=20Del/Backspace=20=EC=A6=89=EC=8B=9C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/context-menu/QContextMenu.jsx | 35 +++++++++++++++--- src/hooks/useContextMenu.js | 37 +++++++++++++------ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/components/common/context-menu/QContextMenu.jsx b/src/components/common/context-menu/QContextMenu.jsx index eec45f41..610a2a29 100644 --- a/src/components/common/context-menu/QContextMenu.jsx +++ b/src/components/common/context-menu/QContextMenu.jsx @@ -1,5 +1,5 @@ 'use client' -import { useEffect } from 'react' +import { useEffect, useRef } from 'react' import '@/styles/contents.scss' import { useRecoilState, useRecoilValue } from 'recoil' import { contextMenuListState, contextMenuState } from '@/store/contextMenu' @@ -15,8 +15,13 @@ export default function QContextMenu(props) { const contextMenuList = useRecoilValue(contextMenuListState) const currentObject = useRecoilValue(currentObjectState) const { tempGridMode, setTempGridMode } = useTempGrid() - const { handleKeyup } = useContextMenu() + const { handleKeyup, triggerDelete } = useContextMenu() const { addDocumentEventListener, removeDocumentEvent } = useEvent() + // [TMP-DEL 2026-05-07] 객체 선택 시 Del 키 활성화: 항상 최신 함수 참조용 ref + const handleKeyupRef = useRef(handleKeyup) + handleKeyupRef.current = handleKeyup + const triggerDeleteRef = useRef(triggerDelete) + triggerDeleteRef.current = triggerDelete // const { addDocumentEventListener, removeDocumentEvent } = useContext(EventContext) const getYPosition = (e) => { @@ -39,7 +44,7 @@ export default function QContextMenu(props) { y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY, } setContextMenu({ visible: true, ...position, currentMousePos: canvasProps.getPointer(e) }) - addDocumentEventListener('keyup', document, handleKeyup) + // [TMP-DEL 2026-05-07] keyup 등록은 객체 선택 useEffect 가 담당. 메뉴 오픈 시 별도 등록 불필요. } } @@ -52,7 +57,7 @@ export default function QContextMenu(props) { // e.preventDefault() if (contextMenu.visible) { setContextMenu({ ...contextMenu, visible: false }) - removeDocumentEvent('keyup') + // [TMP-DEL 2026-05-07] 메뉴 닫혀도 객체 선택 상태면 Del 살려야 하므로 keyup 제거하지 않음 } } @@ -64,13 +69,33 @@ export default function QContextMenu(props) { document.addEventListener('click', handleOutsideClick) return () => { - removeDocumentEvent('keyup') + // [TMP-DEL 2026-05-07] keyup 은 객체선택 useEffect 가 lifecycle 관리. 여기서 지우면 wrappedKeyup 이 같이 날아감 document.removeEventListener('click', handleClick) document.removeEventListener('click', handleOutsideClick) canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //한번 노출 후 이벤트 삭제 } }, [contextRef, contextMenuList, currentObject]) + // [TMP-DEL 2026-05-07] 객체 선택 시 Del 키로 즉시 삭제. 메뉴 단축키(M/C 등)는 기존 handleKeyup 으로 위임. + // input/textarea/contentEditable 포커스 중에는 무시. + useEffect(() => { + if (!currentObject) { + removeDocumentEvent('keyup') + return + } + const wrappedKeyup = (e) => { + const el = document.activeElement + if (el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable)) return + if (e.key === 'Delete' || e.key === 'Backspace') { + triggerDeleteRef.current() + return + } + handleKeyupRef.current(e) + } + addDocumentEventListener('keyup', document, wrappedKeyup) + return () => removeDocumentEvent('keyup') + }, [currentObject]) + return ( <> {contextMenu.visible && ( diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 25dd2a1a..97adc452 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -114,6 +114,24 @@ export function useContextMenu() { if (menu) handleClick(null, menu) } + // [TMP-DEL 2026-05-07] Del 키용: 현재 contextMenu 에서 삭제 메뉴를 찾아 실행 + // 매칭 규칙: id === 'remove' 또는 id 가 'Remove' 로 끝남 (단, 'wallLineRemove' 제외, 'RemoveAll' 제외) + const triggerDelete = () => { + let target = null + for (const group of contextMenu) { + for (const item of group) { + const id = item?.id || '' + if (id === 'wallLineRemove') continue + if (id === 'remove' || id.endsWith('Remove')) { + target = item + break + } + } + if (target) break + } + if (target?.fn) handleClick(null, target) + } + useEffect(() => { currentMenuSetting() }, [gridColor, currentMenu]) @@ -132,8 +150,7 @@ export function useContextMenu() { [ { id: 'dormerRemove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.remove')}(D)`, + name: getMessage('contextmenu.remove'), fn: () => deleteObject(), }, { @@ -206,8 +223,7 @@ export function useContextMenu() { }, { id: 'roofMaterialRemove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.remove')}(D)`, + name: getMessage('contextmenu.remove'), fn: () => deleteObject(), }, { @@ -300,8 +316,7 @@ export function useContextMenu() { }, { id: 'roofMaterialRemove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.remove')}(D)`, + name: getMessage('contextmenu.remove'), fn: () => deleteObject(), }, { @@ -364,8 +379,7 @@ export function useContextMenu() { }, { id: 'auxiliaryRemove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.auxiliary.remove')}(D)`, + name: getMessage('contextmenu.auxiliary.remove'), fn: () => { if (!currentObject) return const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0] @@ -474,8 +488,7 @@ export function useContextMenu() { }, { id: 'openingRemove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.remove')}(D)`, + name: getMessage('contextmenu.remove'), fn: () => deleteObject(), }, { @@ -677,8 +690,7 @@ export function useContextMenu() { }, { id: 'remove', - shortcut: ['d', 'D'], - name: `${getMessage('contextmenu.remove')}(D)`, + name: getMessage('contextmenu.remove'), fn: () => deleteObject(), }, { @@ -973,5 +985,6 @@ export function useContextMenu() { setCurrentContextMenu, handleClick, handleKeyup, + triggerDelete, // [TMP-DEL 2026-05-07] } } -- 2.47.2