Merge pull request '[755] 객체 선택 시 Del/Backspace 즉시 삭제' (#823) from dev into dev-deploy

Reviewed-on: #823
This commit is contained in:
ysCha 2026-05-07 12:17:54 +09:00
commit 0b2be2b4b1
2 changed files with 55 additions and 17 deletions

View File

@ -1,5 +1,5 @@
'use client' 'use client'
import { useEffect } from 'react' import { useEffect, useRef } from 'react'
import '@/styles/contents.scss' import '@/styles/contents.scss'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { contextMenuListState, contextMenuState } from '@/store/contextMenu' import { contextMenuListState, contextMenuState } from '@/store/contextMenu'
@ -15,8 +15,13 @@ export default function QContextMenu(props) {
const contextMenuList = useRecoilValue(contextMenuListState) const contextMenuList = useRecoilValue(contextMenuListState)
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const { tempGridMode, setTempGridMode } = useTempGrid() const { tempGridMode, setTempGridMode } = useTempGrid()
const { handleKeyup } = useContextMenu() const { handleKeyup, triggerDelete } = useContextMenu()
const { addDocumentEventListener, removeDocumentEvent } = useEvent() 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 { addDocumentEventListener, removeDocumentEvent } = useContext(EventContext)
const getYPosition = (e) => { const getYPosition = (e) => {
@ -39,7 +44,7 @@ export default function QContextMenu(props) {
y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY, y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY,
} }
setContextMenu({ visible: true, ...position, currentMousePos: canvasProps.getPointer(e) }) 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() // e.preventDefault()
if (contextMenu.visible) { if (contextMenu.visible) {
setContextMenu({ ...contextMenu, visible: false }) 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) document.addEventListener('click', handleOutsideClick)
return () => { return () => {
removeDocumentEvent('keyup') // [TMP-DEL 2026-05-07] keyup useEffect lifecycle . wrappedKeyup
document.removeEventListener('click', handleClick) document.removeEventListener('click', handleClick)
document.removeEventListener('click', handleOutsideClick) document.removeEventListener('click', handleOutsideClick)
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) // canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
} }
}, [contextRef, contextMenuList, currentObject]) }, [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 ( return (
<> <>
{contextMenu.visible && ( {contextMenu.visible && (

View File

@ -114,6 +114,24 @@ export function useContextMenu() {
if (menu) handleClick(null, menu) 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(() => { useEffect(() => {
currentMenuSetting() currentMenuSetting()
}, [gridColor, currentMenu]) }, [gridColor, currentMenu])
@ -132,8 +150,7 @@ export function useContextMenu() {
[ [
{ {
id: 'dormerRemove', id: 'dormerRemove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.remove'),
name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(), fn: () => deleteObject(),
}, },
{ {
@ -206,8 +223,7 @@ export function useContextMenu() {
}, },
{ {
id: 'roofMaterialRemove', id: 'roofMaterialRemove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.remove'),
name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(), fn: () => deleteObject(),
}, },
{ {
@ -300,8 +316,7 @@ export function useContextMenu() {
}, },
{ {
id: 'roofMaterialRemove', id: 'roofMaterialRemove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.remove'),
name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(), fn: () => deleteObject(),
}, },
{ {
@ -364,8 +379,7 @@ export function useContextMenu() {
}, },
{ {
id: 'auxiliaryRemove', id: 'auxiliaryRemove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.auxiliary.remove'),
name: `${getMessage('contextmenu.auxiliary.remove')}(D)`,
fn: () => { fn: () => {
if (!currentObject) return if (!currentObject) return
const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0] const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]
@ -474,8 +488,7 @@ export function useContextMenu() {
}, },
{ {
id: 'openingRemove', id: 'openingRemove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.remove'),
name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(), fn: () => deleteObject(),
}, },
{ {
@ -677,8 +690,7 @@ export function useContextMenu() {
}, },
{ {
id: 'remove', id: 'remove',
shortcut: ['d', 'D'], name: getMessage('contextmenu.remove'),
name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(), fn: () => deleteObject(),
}, },
{ {
@ -973,5 +985,6 @@ export function useContextMenu() {
setCurrentContextMenu, setCurrentContextMenu,
handleClick, handleClick,
handleKeyup, handleKeyup,
triggerDelete, // [TMP-DEL 2026-05-07]
} }
} }