From ff5c335c9b1b8415cc42a8262cd1e5cfe0b703a7 Mon Sep 17 00:00:00 2001 From: ysCha Date: Fri, 5 Sep 2025 15:34:55 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B3=84=EC=82=B0=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/input/CalcInput.jsx | 68 ++++++++++++----- .../modal/lineTypes/OuterLineWall.jsx | 75 +++++++++++++++++-- 2 files changed, 118 insertions(+), 25 deletions(-) diff --git a/src/components/common/input/CalcInput.jsx b/src/components/common/input/CalcInput.jsx index d0158da6..311e71c3 100644 --- a/src/components/common/input/CalcInput.jsx +++ b/src/components/common/input/CalcInput.jsx @@ -1,8 +1,8 @@ -import React, { useState, useRef, useEffect } from 'react' +import React, { useState, useRef, useEffect, forwardRef } from 'react' import { createCalculator } from '@/util/calc-utils' import '@/styles/calc.scss' -export const CalculatorInput = ({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false }) => { +export const CalculatorInput = forwardRef(({ value, onChange, label, options = {}, id, className = 'calculator-input', readOnly = false, placeholder}, ref) => { const [showKeypad, setShowKeypad] = useState(false) const [displayValue, setDisplayValue] = useState(value || '0') const [hasOperation, setHasOperation] = useState(false) @@ -10,6 +10,17 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas const containerRef = useRef(null) const inputRef = useRef(null) + // 외부 ref와 내부 ref를 동기화 + useEffect(() => { + if (ref) { + if (typeof ref === 'function') { + ref(inputRef.current) + } else { + ref.current = inputRef.current + } + } + }, [ref]) + // Sync displayValue with value prop useEffect(() => { setDisplayValue(value || '0') @@ -138,10 +149,10 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas } // 계산 실행 함수 수정 - const handleCompute = () => { + const handleCompute = (fromEnterKey = false) => { const calculator = calculatorRef.current if (!hasOperation || !calculator.currentOperand) return - + const result = calculator.compute() if (result !== undefined) { const resultStr = result.toString() @@ -149,15 +160,17 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas setHasOperation(false) // Only call onChange with the final result onChange(resultStr) - - // 포커스 유지 및 커서 위치 설정 (맨 뒤로) - requestAnimationFrame(() => { - if (inputRef.current) { - inputRef.current.focus() - const len = resultStr.length - inputRef.current.setSelectionRange(len, len) - } - }) + + // 엔터키로 호출된 경우 포커스 설정하지 않음 + if (!fromEnterKey) { + requestAnimationFrame(() => { + if (inputRef.current) { + inputRef.current.focus() + const len = resultStr.length + inputRef.current.setSelectionRange(len, len) + } + }) + } } } @@ -255,12 +268,22 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas return } - // 방향키는 기본 동작 허용 - if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') { + // 모든 방향키는 기본 동작 허용 + if (e.key === 'ArrowLeft' || e.key === 'ArrowRight' || e.key === 'ArrowUp' || e.key === 'ArrowDown') { setShowKeypad(true) return } + // 계산기 허용 키들이 입력되면 키패드 표시 (엔터키 제외) + if (/^[0-9+\-×÷.=]$/.test(e.key) || e.key === 'Backspace' || e.key === 'Delete' || e.key === '*' || e.key === '/') { + setShowKeypad(true) + } + + // 키패드가 숨겨진 상태에서 엔터키는 페이지로 전달 + if (!showKeypad && e.key === 'Enter') { + return + } + e.preventDefault() const calculator = calculatorRef.current const { allowDecimal } = options @@ -291,7 +314,12 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas break case 'Enter': case '=': - handleCompute() + if (showKeypad) { + // 키패드가 보이는 상태에서 엔터키: 계산 후 키패드만 숨김 + handleCompute(true) // 엔터키로 호출됨을 표시 + setShowKeypad(false) + } + // 키패드가 숨겨진 상태에서 엔터키: 페이지로 전달 (preventDefault 하지 않음) break case 'Backspace': case 'Delete': @@ -328,6 +356,8 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas onChange={handleInputChange} onKeyDown={handleKeyDown} tabIndex={readOnly ? -1 : 0} + placeholder={placeholder} + autoComplete={'off'} /> {showKeypad && !readOnly && ( @@ -391,7 +421,7 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas . {/* = 버튼 */} - @@ -399,4 +429,6 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas )} ) -} +}) + +CalculatorInput.displayName = 'CalculatorInput' diff --git a/src/components/floor-plan/modal/lineTypes/OuterLineWall.jsx b/src/components/floor-plan/modal/lineTypes/OuterLineWall.jsx index 2eb5bcd0..ffbfa9f4 100644 --- a/src/components/floor-plan/modal/lineTypes/OuterLineWall.jsx +++ b/src/components/floor-plan/modal/lineTypes/OuterLineWall.jsx @@ -2,29 +2,90 @@ import { useMessage } from '@/hooks/useMessage' import { normalizeDigits } from '@/util/input-utils' +import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' +import { CalculatorInput } from '@/components/common/input/CalcInput' +import { useEffect, useRef } from 'react' export default function OuterLineWall({ props }) { const { getMessage } = useMessage() const { length1, setLength1, length1Ref, arrow1, setArrow1 } = props + + // 키보드 입력 처리 + useEffect(() => { + const handleKeyDown = (e) => { + // 계산기 키패드가 보이는지 확인 + const keypadVisible = document.querySelector('.keypad-container') + + // 계산기 키패드가 보이면 계산기가 처리하도록 함 + if (keypadVisible) { + return + } + + // 이미 계산기 input에 포커스가 있으면 계산기가 처리하도록 함 + if (document.activeElement && document.activeElement.classList.contains('calculator-input')) { + return + } + + // 엔터키는 계산기가 숨겨진 상태에서만 페이지가 처리 + if (e.key === 'Enter') { + // 엔터키를 페이지 레벨로 전달 (useOuterLineWall.js에서 처리) + return + } + + // 숫자 키가 입력되면 계산기 input에 포커스만 주기 + if (/^[0-9+\-*\/=.]$/.test(e.key) || e.key === 'Backspace' || e.key === 'Delete') { + const calcInput = document.querySelector('.calculator-input') + if (calcInput) { + // 포커스만 주고 이벤트는 preventDefault 하지 않음 + calcInput.focus() + calcInput.click() + } + } + } + + // capture: true로 설정하여 다른 핸들러보다 먼저 실행 + document.addEventListener('keydown', handleKeyDown, { capture: true }) + return () => document.removeEventListener('keydown', handleKeyDown, { capture: true }) + }, []) return (
{getMessage('straight.line')}
- {*/} + {/* if (length1Ref.current.value === '0') {*/} + {/* length1Ref.current.value = ''*/} + {/* }*/} + {/* }}*/} + {/* onChange={(e) => setLength1(normalizeDigits(e.target.value))}*/} + {/* placeholder="3000"*/} + {/*/>*/} + + setLength1(value)} + options={{ + allowNegative: false, + allowDecimal: false //(index !== 0), + }} + placeholder={'3000'} ref={length1Ref} - onFocus={(e) => { - if (length1Ref.current.value === '0') { + onFocus={() => { + if (length1Ref.current && length1Ref.current.value === '0') { length1Ref.current.value = '' } }} - onChange={(e) => setLength1(normalizeDigits(e.target.value))} - placeholder="3000" />