Merge pull request '계산기능 추가' (#332) from dev into dev-deploy

Reviewed-on: #332
This commit is contained in:
ysCha 2025-09-05 15:38:09 +09:00
commit 4cd548eeb8
2 changed files with 118 additions and 25 deletions

View File

@ -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
.
</button>
{/* = 버튼 */}
<button onClick={handleCompute} className="btn-equals">
<button onClick={() => handleCompute(false)} className="btn-equals">
=
</button>
</div>
@ -399,4 +429,6 @@ export const CalculatorInput = ({ value, onChange, label, options = {}, id, clas
)}
</div>
)
}
})
CalculatorInput.displayName = 'CalculatorInput'

View File

@ -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 (
<div className="outline-wrap">
<div className="outline-inner">
<div className="outline-form">
<span className="mr10">{getMessage('straight.line')}</span>
<div className="input-grid" style={{ width: '63px' }}>
<input
type="text"
className="input-origin block"
{/*<input*/}
{/* type="text"*/}
{/* className="input-origin block"*/}
{/* value={length1}*/}
{/* ref={length1Ref}*/}
{/* onFocus={(e) => {*/}
{/* if (length1Ref.current.value === '0') {*/}
{/* length1Ref.current.value = ''*/}
{/* }*/}
{/* }}*/}
{/* onChange={(e) => setLength1(normalizeDigits(e.target.value))}*/}
{/* placeholder="3000"*/}
{/*/>*/}
<CalculatorInput
id="length1-calc"
label=""
className="input-origin block calculator-input"
readOnly={false}
value={length1}
onChange={(value) => 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"
/>
</div>
<button className="reset-btn" onClick={() => setLength1(0)}></button>